SEBWIN-531, #240: Replaced custom life span handler implementation with new API of the browser engine in order to enable parent-child relationship / JavaScript functionality for popup windows.
This commit is contained in:
parent
83c387cffd
commit
71423803e5
65 changed files with 1433 additions and 464 deletions
122
.editorconfig
122
.editorconfig
|
@ -5,10 +5,130 @@ root = true
|
|||
|
||||
[*]
|
||||
end_of_line = crlf
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
tab_width = 4
|
||||
indent_size = 4
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_object_initializer = false:none
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
dotnet_style_namespace_match_folder = true:suggestion
|
||||
|
||||
[*.cs]
|
||||
dotnet_style_object_initializer = false:none
|
||||
indent_style = tab
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_style_namespace_declarations = block_scoped:silent
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_prefer_null_check_over_type_check = true:suggestion
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_prefer_local_over_anonymous_function = true:suggestion
|
||||
csharp_style_prefer_index_operator = true:suggestion
|
||||
csharp_style_prefer_range_operator = true:suggestion
|
||||
csharp_style_prefer_tuple_swap = true:suggestion
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
|
||||
csharp_style_deconstructed_variable_declaration = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:silent
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
csharp_style_prefer_switch_expression = true:suggestion
|
||||
csharp_style_prefer_pattern_matching = true:silent
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_prefer_not_pattern = true:suggestion
|
||||
csharp_style_prefer_extended_property_pattern = true:suggestion
|
||||
csharp_style_var_for_built_in_types = false:silent
|
||||
csharp_style_var_when_type_is_apparent = false:silent
|
||||
csharp_style_var_elsewhere = false:silent
|
||||
csharp_space_after_cast = true
|
||||
|
||||
[*.xml]
|
||||
indent_style = space
|
||||
indent_style = space
|
||||
[*.{cs,vb}]
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||
dotnet_style_predefined_type_for_member_access = true:silent
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = true:silent
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
|
||||
dotnet_code_quality_unused_parameters = all:suggestion
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
||||
dotnet_style_qualification_for_field = false:silent
|
||||
dotnet_style_qualification_for_property = false:silent
|
||||
dotnet_style_qualification_for_method = false:silent
|
||||
dotnet_style_qualification_for_event = false:silent
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
[TestMethod]
|
||||
public void MustCorrectlyCancelDialog()
|
||||
{
|
||||
RequestDialog(default(CefFileDialogMode), false);
|
||||
RequestDialog(default, false);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -80,7 +80,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
threadId = Thread.CurrentThread.ManagedThreadId;
|
||||
};
|
||||
|
||||
var status = sut.OnFileDialog(default(IWebBrowser), default(IBrowser), mode, default(CefFileDialogFlags), title, initialPath, default(List<string>), default(int), callback.Object);
|
||||
var status = sut.OnFileDialog(default, default, mode, default, title, initialPath, default, default, callback.Object);
|
||||
|
||||
sync.WaitOne();
|
||||
|
||||
|
|
|
@ -6,11 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CefSharp;
|
||||
using CefSharp.Enums;
|
||||
using CefSharp.Structs;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SafeExamBrowser.Browser.Handlers;
|
||||
|
||||
|
@ -32,10 +28,10 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
{
|
||||
var text = default(string);
|
||||
|
||||
Assert.IsFalse(sut.OnAutoResize(default(IWebBrowser), default(IBrowser), default(Size)));
|
||||
Assert.IsFalse(sut.OnConsoleMessage(default(IWebBrowser), default(ConsoleMessageEventArgs)));
|
||||
Assert.IsFalse(sut.OnCursorChange(default(IWebBrowser), default(IBrowser), default(IntPtr), default(CursorType), default(CursorInfo)));
|
||||
Assert.IsFalse(sut.OnTooltipChanged(default(IWebBrowser), ref text));
|
||||
Assert.IsFalse(sut.OnAutoResize(default, default, default));
|
||||
Assert.IsFalse(sut.OnConsoleMessage(default, default));
|
||||
Assert.IsFalse(sut.OnCursorChange(default, default, default, default, default));
|
||||
Assert.IsFalse(sut.OnTooltipChanged(default, ref text));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -50,12 +46,12 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
called = true;
|
||||
url = u;
|
||||
};
|
||||
sut.OnFaviconUrlChange(default(IWebBrowser), default(IBrowser), new List<string>());
|
||||
sut.OnFaviconUrlChange(default, default, new List<string>());
|
||||
|
||||
Assert.AreEqual(default(string), url);
|
||||
Assert.AreEqual(default, url);
|
||||
Assert.IsFalse(called);
|
||||
|
||||
sut.OnFaviconUrlChange(default(IWebBrowser), default(IBrowser), new List<string> { newUrl });
|
||||
sut.OnFaviconUrlChange(default, default, new List<string> { newUrl });
|
||||
|
||||
Assert.AreEqual(newUrl, url);
|
||||
Assert.IsTrue(called);
|
||||
|
@ -68,7 +64,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
var actual = default(double);
|
||||
|
||||
sut.ProgressChanged += (p) => actual = p;
|
||||
sut.OnLoadingProgressChange(default(IWebBrowser), default(IBrowser), expected);
|
||||
sut.OnLoadingProgressChange(default, default, expected);
|
||||
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SafeExamBrowser.Browser.Events;
|
||||
using SafeExamBrowser.Browser.Handlers;
|
||||
|
||||
namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
||||
{
|
||||
[TestClass]
|
||||
public class LifeSpanHandlerTests
|
||||
{
|
||||
private LifeSpanHandler sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
sut = new LifeSpanHandler();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustUseDefaultBehavior()
|
||||
{
|
||||
Assert.IsFalse(sut.DoClose(default(IWebBrowser), default(IBrowser)));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustHandlePopup()
|
||||
{
|
||||
var args = default(PopupRequestedEventArgs);
|
||||
var jsAccess = false;
|
||||
var url = "https://www.host.org/some-url";
|
||||
|
||||
sut.PopupRequested += (a) => args = a;
|
||||
|
||||
var result = sut.OnBeforePopup(default(IWebBrowser), default(IBrowser), default(IFrame), url, default(string), default(WindowOpenDisposition), default(bool), default(IPopupFeatures), default(IWindowInfo), default(IBrowserSettings), ref jsAccess, out var newBrowser);
|
||||
|
||||
Assert.IsTrue(result);
|
||||
Assert.AreEqual(default(IWebBrowser), newBrowser);
|
||||
Assert.AreEqual(url, args.Url);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,16 +50,16 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
text = new Mock<IText>();
|
||||
resourceHandler = new ResourceHandler(appConfig, filter.Object, keyGenerator.Object, logger.Object, settings, windowSettings, text.Object);
|
||||
|
||||
sut = new TestableRequestHandler(appConfig, filter.Object, logger.Object, resourceHandler, settings, windowSettings, text.Object);
|
||||
sut = new TestableRequestHandler(appConfig, filter.Object, logger.Object, resourceHandler, settings, windowSettings);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustBlockSpecialWindowDispositions()
|
||||
{
|
||||
Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.NewBackgroundTab, default(bool)));
|
||||
Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.NewPopup, default(bool)));
|
||||
Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.NewWindow, default(bool)));
|
||||
Assert.IsTrue(sut.OnOpenUrlFromTab(default(IWebBrowser), default(IBrowser), default(IFrame), default(string), WindowOpenDisposition.SaveToDisk, default(bool)));
|
||||
Assert.IsTrue(sut.OnOpenUrlFromTab(default, default, default, default, WindowOpenDisposition.NewBackgroundTab, default));
|
||||
Assert.IsTrue(sut.OnOpenUrlFromTab(default, default, default, default, WindowOpenDisposition.NewPopup, default));
|
||||
Assert.IsTrue(sut.OnOpenUrlFromTab(default, default, default, default, WindowOpenDisposition.NewWindow, default));
|
||||
Assert.IsTrue(sut.OnOpenUrlFromTab(default, default, default, default, WindowOpenDisposition.SaveToDisk, default));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -214,7 +214,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
public void MustReturnResourceHandler()
|
||||
{
|
||||
var disableDefaultHandling = default(bool);
|
||||
var handler = sut.GetResourceRequestHandler(default(IWebBrowser), default(IBrowser), default(IFrame), default(IRequest), default(bool), default(bool), default(string), ref disableDefaultHandling);
|
||||
var handler = sut.GetResourceRequestHandler(default, default, default, default, default, default, default, ref disableDefaultHandling);
|
||||
|
||||
Assert.AreSame(resourceHandler, handler);
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
settings.Proxy.Proxies.Add(proxy1);
|
||||
settings.Proxy.Proxies.Add(proxy2);
|
||||
|
||||
var result = sut.GetAuthCredentials(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), default(string), true, "WWW.tEst.Com", 10, default(string), default(string), callback.Object);
|
||||
var result = sut.GetAuthCredentials(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), default, true, "WWW.tEst.Com", 10, default, default, callback.Object);
|
||||
|
||||
callback.Verify(c => c.Cancel(), Times.Never);
|
||||
callback.Verify(c => c.Continue(It.Is<string>(u => u.Equals(proxy1.Username)), It.Is<string>(p => p.Equals(proxy1.Password))), Times.Once);
|
||||
|
@ -243,7 +243,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
{
|
||||
var callback = new Mock<IAuthCallback>();
|
||||
|
||||
sut.GetAuthCredentials(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), default(string), false, default(string), default(int), default(string), default(string), callback.Object);
|
||||
sut.GetAuthCredentials(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), default, false, default, default, default, default, callback.Object);
|
||||
|
||||
callback.Verify(c => c.Cancel(), Times.Never);
|
||||
callback.Verify(c => c.Continue(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
|
||||
|
@ -251,14 +251,7 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers
|
|||
|
||||
private class TestableRequestHandler : RequestHandler
|
||||
{
|
||||
internal TestableRequestHandler(
|
||||
AppConfig appConfig,
|
||||
IRequestFilter filter,
|
||||
ILogger logger,
|
||||
ResourceHandler resourceHandler,
|
||||
BrowserSettings settings,
|
||||
WindowSettings windowSettings,
|
||||
IText text) : base(appConfig, filter, logger, resourceHandler, settings, windowSettings, text)
|
||||
internal TestableRequestHandler(AppConfig appConfig, IRequestFilter filter, ILogger logger, ResourceHandler resourceHandler, BrowserSettings settings, WindowSettings windowSettings) : base(appConfig, filter, logger, resourceHandler, settings, windowSettings)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props')" />
|
||||
<Import Project="..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props')" />
|
||||
<Import Project="..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props')" />
|
||||
<Import Project="..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props')" />
|
||||
<Import Project="..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props')" />
|
||||
<Import Project="..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props')" />
|
||||
<Import Project="..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
|
@ -64,11 +64,11 @@
|
|||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Core.4.4.1\lib\net45\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CefSharp, Version=97.1.11.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.97.1.11\lib\net452\CefSharp.dll</HintPath>
|
||||
<Reference Include="CefSharp, Version=98.1.210.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.98.1.210\lib\net452\CefSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CefSharp.Core, Version=97.1.11.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.97.1.11\lib\net452\CefSharp.Core.dll</HintPath>
|
||||
<Reference Include="CefSharp.Core, Version=98.1.210.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.98.1.210\lib\net452\CefSharp.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.2.8\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||
|
@ -101,7 +101,6 @@
|
|||
<Compile Include="Handlers\DisplayHandlerTests.cs" />
|
||||
<Compile Include="Handlers\DownloadHandlerTests.cs" />
|
||||
<Compile Include="Handlers\KeyboardHandlerTests.cs" />
|
||||
<Compile Include="Handlers\LifeSpanHandlerTests.cs" />
|
||||
<Compile Include="Handlers\RequestHandlerTests.cs" />
|
||||
<Compile Include="Handlers\ResourceHandlerTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
@ -152,11 +151,11 @@
|
|||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.8\build\net45\MSTest.TestAdapter.targets')" />
|
||||
<Import Project="..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets')" />
|
||||
<Import Project="..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets')" />
|
||||
</Project>
|
|
@ -16,11 +16,11 @@
|
|||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="CefSharp" publicKeyToken="40c4b6fc221f4138" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-97.1.11.0" newVersion="97.1.11.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-98.1.210.0" newVersion="98.1.210.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="CefSharp.Core" publicKeyToken="40c4b6fc221f4138" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-97.1.11.0" newVersion="97.1.11.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-98.1.210.0" newVersion="98.1.210.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Castle.Core" version="4.4.1" targetFramework="net472" />
|
||||
<package id="cef.redist.x64" version="97.1.1" targetFramework="net472" />
|
||||
<package id="cef.redist.x86" version="97.1.1" targetFramework="net472" />
|
||||
<package id="CefSharp.Common" version="97.1.11" targetFramework="net472" />
|
||||
<package id="cef.redist.x64" version="98.1.21" targetFramework="net472" />
|
||||
<package id="cef.redist.x86" version="98.1.21" targetFramework="net472" />
|
||||
<package id="CefSharp.Common" version="98.1.210" targetFramework="net472" />
|
||||
<package id="Moq" version="4.16.1" targetFramework="net472" />
|
||||
<package id="MSTest.TestAdapter" version="2.2.8" targetFramework="net472" />
|
||||
<package id="MSTest.TestFramework" version="2.2.8" targetFramework="net472" />
|
||||
|
|
|
@ -24,7 +24,6 @@ using SafeExamBrowser.Configuration.Contracts.Cryptography;
|
|||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.Settings.Browser.Proxy;
|
||||
using SafeExamBrowser.Settings.Logging;
|
||||
using SafeExamBrowser.UserInterface.Contracts;
|
||||
|
@ -170,36 +169,45 @@ namespace SafeExamBrowser.Browser
|
|||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
private void CreateNewWindow(string url = null)
|
||||
private void CreateNewWindow(PopupRequestedEventArgs args = default)
|
||||
{
|
||||
var id = ++windowIdCounter;
|
||||
var isMainWindow = windows.Count == 0;
|
||||
var startUrl = url ?? GenerateStartUrl();
|
||||
var startUrl = GenerateStartUrl();
|
||||
var windowLogger = logger.CloneFor($"Browser Window #{id}");
|
||||
var window = new BrowserWindow(
|
||||
appConfig,
|
||||
settings,
|
||||
id,
|
||||
isMainWindow,
|
||||
fileSystemDialog,
|
||||
hashAlgorithm,
|
||||
id,
|
||||
isMainWindow,
|
||||
keyGenerator,
|
||||
messageBox,
|
||||
windowLogger,
|
||||
messageBox,
|
||||
settings,
|
||||
startUrl,
|
||||
text,
|
||||
uiFactory,
|
||||
startUrl);
|
||||
uiFactory);
|
||||
|
||||
window.Closed += Window_Closed;
|
||||
window.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
|
||||
window.ConfigurationDownloadRequested += (f, a) => ConfigurationDownloadRequested?.Invoke(f, a);
|
||||
window.PopupRequested += Window_PopupRequested;
|
||||
window.ResetRequested += Window_ResetRequested;
|
||||
window.SessionIdentifierDetected += (i) => SessionIdentifierDetected?.Invoke(i);
|
||||
window.TerminationRequested += () => TerminationRequested?.Invoke();
|
||||
|
||||
window.Initialize();
|
||||
window.InitializeControl();
|
||||
windows.Add(window);
|
||||
|
||||
if (args != default(PopupRequestedEventArgs))
|
||||
{
|
||||
args.Window = window;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.InitializeWindow();
|
||||
}
|
||||
|
||||
logger.Info($"Created browser window #{window.Id}.");
|
||||
WindowsChanged?.Invoke();
|
||||
}
|
||||
|
@ -421,8 +429,8 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
private void Window_PopupRequested(PopupRequestedEventArgs args)
|
||||
{
|
||||
logger.Info($"Received request to create new window{(settings.AdditionalWindow.UrlPolicy.CanLog() ? $" for '{args.Url}'" : "")}...");
|
||||
CreateNewWindow(args.Url);
|
||||
logger.Info($"Received request to create new window...");
|
||||
CreateNewWindow(args);
|
||||
}
|
||||
|
||||
private void Window_ResetRequested()
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
using System;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using SafeExamBrowser.Browser.Content;
|
||||
using SafeExamBrowser.Browser.Wrapper;
|
||||
using SafeExamBrowser.Browser.Wrapper.Events;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.Configuration.Contracts.Cryptography;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
|
@ -18,105 +19,80 @@ using SafeExamBrowser.UserInterface.Contracts.Browser.Events;
|
|||
|
||||
namespace SafeExamBrowser.Browser
|
||||
{
|
||||
internal class BrowserControl : ChromiumWebBrowser, IBrowserControl
|
||||
internal class BrowserControl : IBrowserControl
|
||||
{
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly ContentLoader contentLoader;
|
||||
private readonly IContextMenuHandler contextMenuHandler;
|
||||
private readonly ICefSharpControl control;
|
||||
private readonly IDialogHandler dialogHandler;
|
||||
private readonly IDisplayHandler displayHandler;
|
||||
private readonly IDownloadHandler downloadHandler;
|
||||
private readonly IKeyGenerator generator;
|
||||
private readonly IKeyboardHandler keyboardHandler;
|
||||
private readonly ILifeSpanHandler lifeSpanHandler;
|
||||
private readonly IKeyGenerator generator;
|
||||
private readonly IRequestHandler requestHandler;
|
||||
private readonly IText text;
|
||||
|
||||
private AddressChangedEventHandler addressChanged;
|
||||
private LoadFailedEventHandler loadFailed;
|
||||
private LoadingStateChangedEventHandler loadingStateChanged;
|
||||
private TitleChangedEventHandler titleChanged;
|
||||
public string Address => control.Address;
|
||||
public bool CanNavigateBackwards => control.BrowserCore.CanGoBack;
|
||||
public bool CanNavigateForwards => control.BrowserCore.CanGoForward;
|
||||
public object EmbeddableControl => control;
|
||||
|
||||
public bool CanNavigateBackwards => GetBrowser().CanGoBack;
|
||||
public bool CanNavigateForwards => GetBrowser().CanGoForward;
|
||||
|
||||
event AddressChangedEventHandler IBrowserControl.AddressChanged
|
||||
{
|
||||
add { addressChanged += value; }
|
||||
remove { addressChanged -= value; }
|
||||
}
|
||||
|
||||
event LoadFailedEventHandler IBrowserControl.LoadFailed
|
||||
{
|
||||
add { loadFailed += value; }
|
||||
remove { loadFailed -= value; }
|
||||
}
|
||||
|
||||
event LoadingStateChangedEventHandler IBrowserControl.LoadingStateChanged
|
||||
{
|
||||
add { loadingStateChanged += value; }
|
||||
remove { loadingStateChanged -= value; }
|
||||
}
|
||||
|
||||
event TitleChangedEventHandler IBrowserControl.TitleChanged
|
||||
{
|
||||
add { titleChanged += value; }
|
||||
remove { titleChanged -= value; }
|
||||
}
|
||||
public event AddressChangedEventHandler AddressChanged;
|
||||
public event LoadFailedEventHandler LoadFailed;
|
||||
public event LoadingStateChangedEventHandler LoadingStateChanged;
|
||||
public event TitleChangedEventHandler TitleChanged;
|
||||
|
||||
public BrowserControl(
|
||||
AppConfig appConfig,
|
||||
IContextMenuHandler contextMenuHandler,
|
||||
ICefSharpControl control,
|
||||
IDialogHandler dialogHandler,
|
||||
IDisplayHandler displayHandler,
|
||||
IDownloadHandler downloadHandler,
|
||||
IKeyGenerator generator,
|
||||
IKeyboardHandler keyboardHandler,
|
||||
ILifeSpanHandler lifeSpanHandler,
|
||||
IKeyGenerator generator,
|
||||
IRequestHandler requestHandler,
|
||||
IText text,
|
||||
string url) : base(url)
|
||||
IText text)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.contentLoader = new ContentLoader(text);
|
||||
this.contextMenuHandler = contextMenuHandler;
|
||||
this.control = control;
|
||||
this.dialogHandler = dialogHandler;
|
||||
this.displayHandler = displayHandler;
|
||||
this.downloadHandler = downloadHandler;
|
||||
this.generator = generator;
|
||||
this.keyboardHandler = keyboardHandler;
|
||||
this.lifeSpanHandler = lifeSpanHandler;
|
||||
this.generator = generator;
|
||||
this.requestHandler = requestHandler;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
if (!IsDisposed)
|
||||
if (!control.IsDisposed)
|
||||
{
|
||||
Dispose(true);
|
||||
control.Dispose(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
|
||||
FrameLoadStart += BrowserControl_FrameLoadStart;
|
||||
IsBrowserInitializedChanged += BrowserControl_IsBrowserInitializedChanged;
|
||||
LoadError += BrowserControl_LoadError;
|
||||
LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading);
|
||||
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
|
||||
|
||||
DialogHandler = dialogHandler;
|
||||
DisplayHandler = displayHandler;
|
||||
DownloadHandler = downloadHandler;
|
||||
KeyboardHandler = keyboardHandler;
|
||||
LifeSpanHandler = lifeSpanHandler;
|
||||
MenuHandler = contextMenuHandler;
|
||||
RequestHandler = requestHandler;
|
||||
control.AddressChanged += (o, e) => AddressChanged?.Invoke(e.Address);
|
||||
control.AuthCredentialsRequired += (w, b, o, i, h, p, r, s, c, a) => a.Value = requestHandler.GetAuthCredentials(w, b, o, i, h, p, r, s, c);
|
||||
control.BeforeBrowse += (w, b, f, r, u, i, a) => a.Value = requestHandler.OnBeforeBrowse(w, b, f, r, u, i);
|
||||
control.BeforeDownload += (w, b, d, c) => downloadHandler.OnBeforeDownload(w, b, d, c);
|
||||
control.DownloadUpdated += (w, b, d, c) => downloadHandler.OnDownloadUpdated(w, b, d, c);
|
||||
control.FaviconUrlChanged += (w, b, u) => displayHandler.OnFaviconUrlChange(w, b, u);
|
||||
control.FileDialogRequested += (w, b, m, f, t, d, a, s, c) => dialogHandler.OnFileDialog(w, b, m, f, t, d, a, s, c);
|
||||
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.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);
|
||||
control.PreKeyEvent += (IWebBrowser w, IBrowser b, KeyType t, int k, int n, CefEventFlags m, bool i, ref bool s, GenericEventArgs a) => a.Value = keyboardHandler.OnPreKeyEvent(w, b, t, k, n, m, i, ref s);
|
||||
control.ResourceRequestHandlerRequired += (IWebBrowser w, IBrowser b, IFrame f, IRequest r, bool n, bool d, string i, ref bool h, ResourceRequestEventArgs a) => a.Handler = requestHandler.GetResourceRequestHandler(w, b, f, r, n, d, i, ref h);
|
||||
control.TitleChanged += (o, e) => TitleChanged?.Invoke(e.Title);
|
||||
}
|
||||
|
||||
private void BrowserControl_FrameLoadStart(object sender, FrameLoadStartEventArgs e)
|
||||
private void Control_FrameLoadStart(object sender, FrameLoadStartEventArgs e)
|
||||
{
|
||||
var browserExamKey = generator.CalculateBrowserExamKeyHash(e.Url);
|
||||
var configurationKey = generator.CalculateConfigurationKeyHash(e.Url);
|
||||
|
@ -125,52 +101,47 @@ namespace SafeExamBrowser.Browser
|
|||
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)
|
||||
{
|
||||
this.Find(0, term, forward, caseSensitive, !isInitial);
|
||||
control.Find(0, term, forward, caseSensitive, !isInitial);
|
||||
}
|
||||
|
||||
public void NavigateBackwards()
|
||||
{
|
||||
GetBrowser().GoBack();
|
||||
control.BrowserCore.GoBack();
|
||||
}
|
||||
|
||||
public void NavigateForwards()
|
||||
{
|
||||
GetBrowser().GoForward();
|
||||
control.BrowserCore.GoForward();
|
||||
}
|
||||
|
||||
public void NavigateTo(string address)
|
||||
{
|
||||
Load(address);
|
||||
control.Load(address);
|
||||
}
|
||||
|
||||
public void ShowDeveloperConsole()
|
||||
{
|
||||
GetBrowser().ShowDevTools();
|
||||
control.BrowserCore.ShowDevTools();
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
GetBrowser().Reload();
|
||||
control.BrowserCore.Reload();
|
||||
}
|
||||
|
||||
public void Zoom(double level)
|
||||
{
|
||||
GetBrowser().SetZoomLevel(level);
|
||||
}
|
||||
|
||||
private void BrowserControl_IsBrowserInitializedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (IsBrowserInitialized)
|
||||
{
|
||||
GetBrowser().GetHost().SetFocus(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void BrowserControl_LoadError(object sender, LoadErrorEventArgs e)
|
||||
{
|
||||
loadFailed?.Invoke((int) e.ErrorCode, e.ErrorText, e.FailedUrl);
|
||||
control.BrowserCore.SetZoomLevel(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms.Handler;
|
||||
using CefSharp.WinForms.Host;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Applications.Contracts.Events;
|
||||
using SafeExamBrowser.Browser.Contracts.Events;
|
||||
|
@ -17,6 +20,7 @@ using SafeExamBrowser.Browser.Contracts.Filters;
|
|||
using SafeExamBrowser.Browser.Events;
|
||||
using SafeExamBrowser.Browser.Filters;
|
||||
using SafeExamBrowser.Browser.Handlers;
|
||||
using SafeExamBrowser.Browser.Wrapper;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.Configuration.Contracts.Cryptography;
|
||||
using SafeExamBrowser.Core.Contracts.Resources.Icons;
|
||||
|
@ -31,6 +35,7 @@ using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
|||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||
using Syroot.Windows.IO;
|
||||
using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings;
|
||||
using DisplayHandler = SafeExamBrowser.Browser.Handlers.DisplayHandler;
|
||||
using Request = SafeExamBrowser.Browser.Contracts.Filters.Request;
|
||||
using ResourceHandler = SafeExamBrowser.Browser.Handlers.ResourceHandler;
|
||||
using TitleChangedEventHandler = SafeExamBrowser.Applications.Contracts.Events.TitleChangedEventHandler;
|
||||
|
@ -49,12 +54,12 @@ namespace SafeExamBrowser.Browser
|
|||
private readonly IKeyGenerator keyGenerator;
|
||||
private readonly IModuleLogger logger;
|
||||
private readonly IMessageBox messageBox;
|
||||
private readonly Dictionary<int, BrowserWindow> popups;
|
||||
private readonly BrowserSettings settings;
|
||||
private readonly string startUrl;
|
||||
private readonly IText text;
|
||||
private readonly IUserInterfaceFactory uiFactory;
|
||||
|
||||
private IBrowserControl control;
|
||||
private IBrowserWindow window;
|
||||
private double zoomLevel;
|
||||
|
||||
|
@ -63,6 +68,7 @@ namespace SafeExamBrowser.Browser
|
|||
get { return isMainWindow ? settings.MainWindow : settings.AdditionalWindow; }
|
||||
}
|
||||
|
||||
internal IBrowserControl Control { get; private set; }
|
||||
internal int Id { get; }
|
||||
|
||||
public IntPtr Handle { get; private set; }
|
||||
|
@ -81,31 +87,32 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
public BrowserWindow(
|
||||
AppConfig appConfig,
|
||||
BrowserSettings settings,
|
||||
int id,
|
||||
bool isMainWindow,
|
||||
IFileSystemDialog fileSystemDialog,
|
||||
IHashAlgorithm hashAlgorithm,
|
||||
int id,
|
||||
bool isMainWindow,
|
||||
IKeyGenerator keyGenerator,
|
||||
IMessageBox messageBox,
|
||||
IModuleLogger logger,
|
||||
IMessageBox messageBox,
|
||||
BrowserSettings settings,
|
||||
string startUrl,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory,
|
||||
string startUrl)
|
||||
IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.Id = id;
|
||||
this.httpClient = new HttpClient();
|
||||
this.isMainWindow = isMainWindow;
|
||||
this.fileSystemDialog = fileSystemDialog;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
this.httpClient = new HttpClient();
|
||||
this.Id = id;
|
||||
this.isMainWindow = isMainWindow;
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.messageBox = messageBox;
|
||||
this.logger = logger;
|
||||
this.messageBox = messageBox;
|
||||
this.popups = new Dictionary<int, BrowserWindow>();
|
||||
this.settings = settings;
|
||||
this.startUrl = startUrl;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
this.startUrl = startUrl;
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
|
@ -116,31 +123,34 @@ namespace SafeExamBrowser.Browser
|
|||
internal void Close()
|
||||
{
|
||||
window.Close();
|
||||
control.Destroy();
|
||||
Control.Destroy();
|
||||
}
|
||||
|
||||
internal void Initialize()
|
||||
{
|
||||
InitializeControl();
|
||||
InitializeWindow();
|
||||
}
|
||||
|
||||
private void InitializeControl()
|
||||
internal void InitializeControl()
|
||||
{
|
||||
var cefSharpControl = default(ICefSharpControl);
|
||||
var contextMenuHandler = new ContextMenuHandler();
|
||||
var dialogHandler = new DialogHandler();
|
||||
var displayHandler = new DisplayHandler();
|
||||
var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} #{Id}");
|
||||
var downloadHandler = new DownloadHandler(appConfig, downloadLogger, settings, WindowSettings);
|
||||
var keyboardHandler = new KeyboardHandler();
|
||||
var lifeSpanHandler = new LifeSpanHandler();
|
||||
var requestFilter = new RequestFilter();
|
||||
var requestLogger = logger.CloneFor($"{nameof(RequestHandler)} #{Id}");
|
||||
var resourceHandler = new ResourceHandler(appConfig, requestFilter, keyGenerator, logger, settings, WindowSettings, text);
|
||||
var requestHandler = new RequestHandler(appConfig, requestFilter, requestLogger, resourceHandler, settings, WindowSettings, text);
|
||||
var requestHandler = new RequestHandler(appConfig, requestFilter, requestLogger, resourceHandler, settings, WindowSettings);
|
||||
|
||||
Icon = new BrowserIconResource();
|
||||
|
||||
if (isMainWindow)
|
||||
{
|
||||
cefSharpControl = new CefSharpBrowserControl(CreateLifeSpanHandlerForMainWindow(), startUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
cefSharpControl = new CefSharpPopupControl();
|
||||
}
|
||||
|
||||
dialogHandler.DialogRequested += DialogHandler_DialogRequested;
|
||||
displayHandler.FaviconChanged += DisplayHandler_FaviconChanged;
|
||||
displayHandler.ProgressChanged += DisplayHandler_ProgressChanged;
|
||||
|
@ -152,34 +162,65 @@ namespace SafeExamBrowser.Browser
|
|||
keyboardHandler.ZoomInRequested += ZoomInRequested;
|
||||
keyboardHandler.ZoomOutRequested += ZoomOutRequested;
|
||||
keyboardHandler.ZoomResetRequested += ZoomResetRequested;
|
||||
lifeSpanHandler.PopupRequested += LifeSpanHandler_PopupRequested;
|
||||
resourceHandler.SessionIdentifierDetected += (id) => SessionIdentifierDetected?.Invoke(id);
|
||||
requestHandler.QuitUrlVisited += RequestHandler_QuitUrlVisited;
|
||||
requestHandler.RequestBlocked += RequestHandler_RequestBlocked;
|
||||
|
||||
InitializeRequestFilter(requestFilter);
|
||||
|
||||
control = new BrowserControl(
|
||||
Control = new BrowserControl(
|
||||
appConfig,
|
||||
contextMenuHandler,
|
||||
cefSharpControl,
|
||||
dialogHandler,
|
||||
displayHandler,
|
||||
downloadHandler,
|
||||
keyGenerator,
|
||||
keyboardHandler,
|
||||
lifeSpanHandler,
|
||||
keyGenerator,
|
||||
requestHandler,
|
||||
text,
|
||||
startUrl);
|
||||
control.AddressChanged += Control_AddressChanged;
|
||||
control.LoadFailed += Control_LoadFailed;
|
||||
control.LoadingStateChanged += Control_LoadingStateChanged;
|
||||
control.TitleChanged += Control_TitleChanged;
|
||||
text);
|
||||
Control.AddressChanged += Control_AddressChanged;
|
||||
Control.LoadFailed += Control_LoadFailed;
|
||||
Control.LoadingStateChanged += Control_LoadingStateChanged;
|
||||
Control.TitleChanged += Control_TitleChanged;
|
||||
|
||||
control.Initialize();
|
||||
Control.Initialize();
|
||||
logger.Debug("Initialized browser control.");
|
||||
}
|
||||
|
||||
internal void InitializeWindow()
|
||||
{
|
||||
window = uiFactory.CreateBrowserWindow(Control, settings, isMainWindow);
|
||||
window.AddressChanged += Window_AddressChanged;
|
||||
window.BackwardNavigationRequested += Window_BackwardNavigationRequested;
|
||||
window.Closed += Window_Closed;
|
||||
window.Closing += Window_Closing;
|
||||
window.DeveloperConsoleRequested += Window_DeveloperConsoleRequested;
|
||||
window.FindRequested += Window_FindRequested;
|
||||
window.ForwardNavigationRequested += Window_ForwardNavigationRequested;
|
||||
window.HomeNavigationRequested += HomeNavigationRequested;
|
||||
window.ReloadRequested += ReloadRequested;
|
||||
window.ZoomInRequested += ZoomInRequested;
|
||||
window.ZoomOutRequested += ZoomOutRequested;
|
||||
window.ZoomResetRequested += ZoomResetRequested;
|
||||
window.UpdateZoomLevel(CalculateZoomPercentage());
|
||||
window.Show();
|
||||
window.BringToForeground();
|
||||
|
||||
Handle = window.Handle;
|
||||
|
||||
logger.Debug("Initialized browser window.");
|
||||
}
|
||||
|
||||
private ILifeSpanHandler CreateLifeSpanHandlerForMainWindow()
|
||||
{
|
||||
return LifeSpanHandler
|
||||
.Create(() => LifeSpanHandler_CreatePopup())
|
||||
.OnBeforePopupCreated((wb, b, f, u, t, d, g, s) => LifeSpanHandler_PopupRequested(u))
|
||||
.OnPopupCreated((c, u) => LifeSpanHandler_PopupCreated(c))
|
||||
.OnPopupDestroyed((c, b) => LifeSpanHandler_PopupDestroyed(c))
|
||||
.Build();
|
||||
}
|
||||
|
||||
private void InitializeRequestFilter(IRequestFilter requestFilter)
|
||||
{
|
||||
if (settings.Filter.ProcessContentRequests || settings.Filter.ProcessMainRequests)
|
||||
|
@ -208,32 +249,9 @@ namespace SafeExamBrowser.Browser
|
|||
}
|
||||
}
|
||||
|
||||
private void InitializeWindow()
|
||||
{
|
||||
window = uiFactory.CreateBrowserWindow(control, settings, isMainWindow);
|
||||
window.AddressChanged += Window_AddressChanged;
|
||||
window.BackwardNavigationRequested += Window_BackwardNavigationRequested;
|
||||
window.Closing += Window_Closing;
|
||||
window.DeveloperConsoleRequested += Window_DeveloperConsoleRequested;
|
||||
window.FindRequested += Window_FindRequested;
|
||||
window.ForwardNavigationRequested += Window_ForwardNavigationRequested;
|
||||
window.HomeNavigationRequested += HomeNavigationRequested;
|
||||
window.ReloadRequested += ReloadRequested;
|
||||
window.ZoomInRequested += ZoomInRequested;
|
||||
window.ZoomOutRequested += ZoomOutRequested;
|
||||
window.ZoomResetRequested += ZoomResetRequested;
|
||||
window.UpdateZoomLevel(CalculateZoomPercentage());
|
||||
window.Show();
|
||||
window.BringToForeground();
|
||||
|
||||
Handle = window.Handle;
|
||||
|
||||
logger.Debug("Initialized browser window.");
|
||||
}
|
||||
|
||||
private void Control_AddressChanged(string address)
|
||||
{
|
||||
logger.Debug($"Navigated{(WindowSettings.UrlPolicy.CanLog() ? $" to '{address}'" : "")}.");
|
||||
logger.Info($"Navigated{(WindowSettings.UrlPolicy.CanLog() ? $" to '{address}'" : "")}.");
|
||||
window.UpdateAddress(address);
|
||||
|
||||
if (WindowSettings.UrlPolicy == UrlPolicy.Always || WindowSettings.UrlPolicy == UrlPolicy.BeforeTitle)
|
||||
|
@ -265,14 +283,14 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
private void Control_LoadingStateChanged(bool isLoading)
|
||||
{
|
||||
window.CanNavigateBackwards = WindowSettings.AllowBackwardNavigation && control.CanNavigateBackwards;
|
||||
window.CanNavigateForwards = WindowSettings.AllowForwardNavigation && control.CanNavigateForwards;
|
||||
window.CanNavigateBackwards = WindowSettings.AllowBackwardNavigation && Control.CanNavigateBackwards;
|
||||
window.CanNavigateForwards = WindowSettings.AllowForwardNavigation && Control.CanNavigateForwards;
|
||||
window.UpdateLoadingState(isLoading);
|
||||
}
|
||||
|
||||
|
@ -423,7 +441,7 @@ namespace SafeExamBrowser.Browser
|
|||
|
||||
if (navigate)
|
||||
{
|
||||
control.NavigateTo(url);
|
||||
Control.NavigateTo(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -436,32 +454,67 @@ namespace SafeExamBrowser.Browser
|
|||
}
|
||||
}
|
||||
|
||||
private void LifeSpanHandler_PopupRequested(PopupRequestedEventArgs args)
|
||||
private ChromiumHostControl LifeSpanHandler_CreatePopup()
|
||||
{
|
||||
var validCurrentUri = Uri.TryCreate(control.Address, UriKind.Absolute, out var currentUri);
|
||||
var validNewUri = Uri.TryCreate(args.Url, UriKind.Absolute, out var newUri);
|
||||
var args = new PopupRequestedEventArgs();
|
||||
|
||||
PopupRequested?.Invoke(args);
|
||||
|
||||
var control = args.Window.Control.EmbeddableControl as ChromiumHostControl;
|
||||
var id = control.GetHashCode();
|
||||
var window = args.Window;
|
||||
|
||||
popups[id] = window;
|
||||
window.Closed += (_) => popups.Remove(id);
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
private void LifeSpanHandler_PopupCreated(ChromiumHostControl control)
|
||||
{
|
||||
var id = control.GetHashCode();
|
||||
var window = popups[id];
|
||||
|
||||
window.InitializeWindow();
|
||||
}
|
||||
|
||||
private void LifeSpanHandler_PopupDestroyed(ChromiumHostControl control)
|
||||
{
|
||||
var id = control.GetHashCode();
|
||||
var window = popups[id];
|
||||
|
||||
window.Close();
|
||||
}
|
||||
|
||||
private PopupCreation LifeSpanHandler_PopupRequested(string targetUrl)
|
||||
{
|
||||
var creation = PopupCreation.Cancel;
|
||||
var validCurrentUri = Uri.TryCreate(Control.Address, UriKind.Absolute, out var currentUri);
|
||||
var validNewUri = Uri.TryCreate(targetUrl, UriKind.Absolute, out var newUri);
|
||||
var sameHost = validCurrentUri && validNewUri && string.Equals(currentUri.Host, newUri.Host, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
switch (settings.PopupPolicy)
|
||||
{
|
||||
case PopupPolicy.Allow:
|
||||
case PopupPolicy.AllowSameHost when sameHost:
|
||||
logger.Debug($"Forwarding request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{args.Url}'" : "")}...");
|
||||
PopupRequested?.Invoke(args);
|
||||
logger.Debug($"Forwarding request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{targetUrl}'" : "")}...");
|
||||
creation = PopupCreation.Continue;
|
||||
break;
|
||||
case PopupPolicy.AllowSameWindow:
|
||||
case PopupPolicy.AllowSameHostAndWindow when sameHost:
|
||||
logger.Info($"Discarding request to open new window and loading{(WindowSettings.UrlPolicy.CanLog() ? $" '{args.Url}'" : "")} directly...");
|
||||
control.NavigateTo(args.Url);
|
||||
logger.Info($"Discarding request to open new window and loading{(WindowSettings.UrlPolicy.CanLog() ? $" '{targetUrl}'" : "")} directly...");
|
||||
Control.NavigateTo(targetUrl);
|
||||
break;
|
||||
case PopupPolicy.AllowSameHost when !sameHost:
|
||||
case PopupPolicy.AllowSameHostAndWindow when !sameHost:
|
||||
logger.Info($"Blocked request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{args.Url}'" : "")} as it targets a different host.");
|
||||
logger.Info($"Blocked request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{targetUrl}'" : "")} as it targets a different host.");
|
||||
break;
|
||||
default:
|
||||
logger.Info($"Blocked request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{args.Url}'" : "")}.");
|
||||
logger.Info($"Blocked request to open new window{(WindowSettings.UrlPolicy.CanLog() ? $" for '{targetUrl}'" : "")}.");
|
||||
break;
|
||||
}
|
||||
|
||||
return creation;
|
||||
}
|
||||
|
||||
private void RequestHandler_QuitUrlVisited(string url)
|
||||
|
@ -508,7 +561,7 @@ namespace SafeExamBrowser.Browser
|
|||
var message = text.Get(TextKey.MessageBox_BrowserNavigationBlocked).Replace("%%URL%%", WindowSettings.UrlPolicy.CanLogError() ? url : "");
|
||||
var title = text.Get(TextKey.MessageBox_BrowserNavigationBlockedTitle);
|
||||
|
||||
control.TitleChanged -= Control_TitleChanged;
|
||||
Control.TitleChanged -= Control_TitleChanged;
|
||||
|
||||
if (url.Equals(startUrl, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
@ -517,7 +570,7 @@ namespace SafeExamBrowser.Browser
|
|||
}
|
||||
|
||||
messageBox.Show(message, title, parent: window);
|
||||
control.TitleChanged += Control_TitleChanged;
|
||||
Control.TitleChanged += Control_TitleChanged;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -530,7 +583,7 @@ namespace SafeExamBrowser.Browser
|
|||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
logger.Debug("The user confirmed reloading the current page...");
|
||||
control.Reload();
|
||||
Control.Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -540,7 +593,7 @@ namespace SafeExamBrowser.Browser
|
|||
else if (WindowSettings.AllowReloading)
|
||||
{
|
||||
logger.Debug("Reloading current page...");
|
||||
control.Reload();
|
||||
Control.Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -555,7 +608,7 @@ namespace SafeExamBrowser.Browser
|
|||
if (isValid)
|
||||
{
|
||||
logger.Debug($"The user requested to navigate to '{address}', the URI is valid.");
|
||||
control.NavigateTo(address);
|
||||
Control.NavigateTo(address);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -567,34 +620,39 @@ namespace SafeExamBrowser.Browser
|
|||
private void Window_BackwardNavigationRequested()
|
||||
{
|
||||
logger.Debug("Navigating backwards...");
|
||||
control.NavigateBackwards();
|
||||
Control.NavigateBackwards();
|
||||
}
|
||||
|
||||
private void Window_Closing()
|
||||
{
|
||||
logger.Info($"Window is closing...");
|
||||
control.Destroy();
|
||||
logger.Debug($"Window is closing...");
|
||||
}
|
||||
|
||||
private void Window_Closed()
|
||||
{
|
||||
logger.Debug($"Window has been closed.");
|
||||
Control.Destroy();
|
||||
Closed?.Invoke(Id);
|
||||
}
|
||||
|
||||
private void Window_DeveloperConsoleRequested()
|
||||
{
|
||||
logger.Debug("Showing developer console...");
|
||||
control.ShowDeveloperConsole();
|
||||
Control.ShowDeveloperConsole();
|
||||
}
|
||||
|
||||
private void Window_FindRequested(string term, bool isInitial, bool caseSensitive, bool forward = true)
|
||||
{
|
||||
if (settings.AllowFind)
|
||||
{
|
||||
control.Find(term, isInitial, caseSensitive, forward);
|
||||
Control.Find(term, isInitial, caseSensitive, forward);
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_ForwardNavigationRequested()
|
||||
{
|
||||
logger.Debug("Navigating forwards...");
|
||||
control.NavigateForwards();
|
||||
Control.NavigateForwards();
|
||||
}
|
||||
|
||||
private void ZoomInRequested()
|
||||
|
@ -602,7 +660,7 @@ namespace SafeExamBrowser.Browser
|
|||
if (settings.AllowPageZoom && CalculateZoomPercentage() < 300)
|
||||
{
|
||||
zoomLevel += ZOOM_FACTOR;
|
||||
control.Zoom(zoomLevel);
|
||||
Control.Zoom(zoomLevel);
|
||||
window.UpdateZoomLevel(CalculateZoomPercentage());
|
||||
logger.Debug($"Increased page zoom to {CalculateZoomPercentage()}%.");
|
||||
}
|
||||
|
@ -613,7 +671,7 @@ namespace SafeExamBrowser.Browser
|
|||
if (settings.AllowPageZoom && CalculateZoomPercentage() > 25)
|
||||
{
|
||||
zoomLevel -= ZOOM_FACTOR;
|
||||
control.Zoom(zoomLevel);
|
||||
Control.Zoom(zoomLevel);
|
||||
window.UpdateZoomLevel(CalculateZoomPercentage());
|
||||
logger.Debug($"Decreased page zoom to {CalculateZoomPercentage()}%.");
|
||||
}
|
||||
|
@ -624,7 +682,7 @@ namespace SafeExamBrowser.Browser
|
|||
if (settings.AllowPageZoom)
|
||||
{
|
||||
zoomLevel = 0;
|
||||
control.Zoom(0);
|
||||
Control.Zoom(0);
|
||||
window.UpdateZoomLevel(CalculateZoomPercentage());
|
||||
logger.Debug($"Reset page zoom to {CalculateZoomPercentage()}%.");
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@ namespace SafeExamBrowser.Browser.Events
|
|||
{
|
||||
internal class PopupRequestedEventArgs
|
||||
{
|
||||
public string Url { get; set; }
|
||||
public BrowserWindow Window { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ using System.Collections.Generic;
|
|||
using System.Threading.Tasks;
|
||||
using CefSharp;
|
||||
using SafeExamBrowser.Browser.Events;
|
||||
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
||||
using SafeExamBrowser.Browser.Wrapper;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Handlers
|
||||
{
|
||||
|
@ -22,9 +22,9 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
{
|
||||
var args = new DialogRequestedEventArgs
|
||||
{
|
||||
Element = ToElement(mode),
|
||||
Element = mode.ToElement(),
|
||||
InitialPath = defaultFilePath,
|
||||
Operation = ToOperation(mode),
|
||||
Operation = mode.ToOperation(),
|
||||
Title = title
|
||||
};
|
||||
|
||||
|
@ -47,27 +47,5 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
private FileSystemElement ToElement(CefFileDialogMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case CefFileDialogMode.OpenFolder:
|
||||
return FileSystemElement.Folder;
|
||||
default:
|
||||
return FileSystemElement.File;
|
||||
}
|
||||
}
|
||||
|
||||
private FileSystemOperation ToOperation(CefFileDialogMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case CefFileDialogMode.Save:
|
||||
return FileSystemOperation.Save;
|
||||
default:
|
||||
return FileSystemOperation.Open;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
{
|
||||
internal class DownloadHandler : IDownloadHandler
|
||||
{
|
||||
private AppConfig appConfig;
|
||||
private BrowserSettings settings;
|
||||
private WindowSettings windowSettings;
|
||||
private ConcurrentDictionary<int, DownloadFinishedCallback> callbacks;
|
||||
private ConcurrentDictionary<int, Guid> downloads;
|
||||
private ILogger logger;
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly ConcurrentDictionary<int, DownloadFinishedCallback> callbacks;
|
||||
private readonly ConcurrentDictionary<int, Guid> downloads;
|
||||
private readonly ILogger logger;
|
||||
private readonly BrowserSettings settings;
|
||||
private readonly WindowSettings windowSettings;
|
||||
|
||||
internal event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||
internal event DownloadUpdatedEventHandler DownloadUpdated;
|
||||
|
@ -85,7 +85,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
IsComplete = downloadItem.IsComplete,
|
||||
Url = downloadItem.Url
|
||||
};
|
||||
|
||||
|
||||
Task.Run(() => DownloadUpdated?.Invoke(state));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
using SafeExamBrowser.Browser.Events;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Handlers
|
||||
{
|
||||
internal class LifeSpanHandler : ILifeSpanHandler
|
||||
{
|
||||
public event PopupRequestedEventHandler PopupRequested;
|
||||
|
||||
public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
|
||||
{
|
||||
}
|
||||
|
||||
public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
|
||||
{
|
||||
var args = new PopupRequestedEventArgs { Url = targetUrl };
|
||||
|
||||
newBrowser = default(IWebBrowser);
|
||||
PopupRequested?.Invoke(args);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,6 @@ using CefSharp;
|
|||
using SafeExamBrowser.Browser.Contracts.Filters;
|
||||
using SafeExamBrowser.Browser.Events;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.Settings.Browser.Filter;
|
||||
|
@ -25,13 +24,14 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
{
|
||||
internal class RequestHandler : CefSharp.Handler.RequestHandler
|
||||
{
|
||||
private AppConfig appConfig;
|
||||
private IRequestFilter filter;
|
||||
private ILogger logger;
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly IRequestFilter filter;
|
||||
private readonly ILogger logger;
|
||||
private readonly ResourceHandler resourceHandler;
|
||||
private readonly WindowSettings windowSettings;
|
||||
private readonly BrowserSettings settings;
|
||||
|
||||
private string quitUrlPattern;
|
||||
private ResourceHandler resourceHandler;
|
||||
private WindowSettings windowSettings;
|
||||
private BrowserSettings settings;
|
||||
|
||||
internal event UrlEventHandler QuitUrlVisited;
|
||||
internal event UrlEventHandler RequestBlocked;
|
||||
|
@ -42,8 +42,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
ILogger logger,
|
||||
ResourceHandler resourceHandler,
|
||||
BrowserSettings settings,
|
||||
WindowSettings windowSettings,
|
||||
IText text)
|
||||
WindowSettings windowSettings)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.filter = filter;
|
||||
|
@ -53,16 +52,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
this.windowSettings = windowSettings;
|
||||
}
|
||||
|
||||
protected override bool GetAuthCredentials(
|
||||
IWebBrowser webBrowser,
|
||||
IBrowser browser,
|
||||
string originUrl,
|
||||
bool isProxy,
|
||||
string host,
|
||||
int port,
|
||||
string realm,
|
||||
string scheme,
|
||||
IAuthCallback callback)
|
||||
protected override bool GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
|
||||
{
|
||||
if (isProxy)
|
||||
{
|
||||
|
@ -80,15 +70,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
return base.GetAuthCredentials(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback);
|
||||
}
|
||||
|
||||
protected override IResourceRequestHandler GetResourceRequestHandler(
|
||||
IWebBrowser webBrowser,
|
||||
IBrowser browser,
|
||||
IFrame frame,
|
||||
IRequest request,
|
||||
bool isNavigation,
|
||||
bool isDownload,
|
||||
string requestInitiator,
|
||||
ref bool disableDefaultHandling)
|
||||
protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
|
||||
{
|
||||
return resourceHandler;
|
||||
}
|
||||
|
@ -122,13 +104,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
return base.OnBeforeBrowse(webBrowser, browser, frame, request, userGesture, isRedirect);
|
||||
}
|
||||
|
||||
protected override bool OnOpenUrlFromTab(
|
||||
IWebBrowser webBrowser,
|
||||
IBrowser browser,
|
||||
IFrame frame,
|
||||
string targetUrl,
|
||||
WindowOpenDisposition targetDisposition,
|
||||
bool userGesture)
|
||||
protected override bool OnOpenUrlFromTab(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
|
||||
{
|
||||
switch (targetDisposition)
|
||||
{
|
||||
|
@ -172,7 +148,7 @@ namespace SafeExamBrowser.Browser.Handlers
|
|||
|
||||
if (!string.IsNullOrWhiteSpace(settings.QuitUrl))
|
||||
{
|
||||
if (quitUrlPattern == default(string))
|
||||
if (quitUrlPattern == default)
|
||||
{
|
||||
quitUrlPattern = Regex.Escape(settings.QuitUrl.TrimEnd('/')) + @"\/?";
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props')" />
|
||||
<Import Project="..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props')" />
|
||||
<Import Project="..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props')" />
|
||||
<Import Project="..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props')" />
|
||||
<Import Project="..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props')" />
|
||||
<Import Project="..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
|
@ -53,14 +53,14 @@
|
|||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="CefSharp, Version=97.1.11.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.97.1.11\lib\net452\CefSharp.dll</HintPath>
|
||||
<Reference Include="CefSharp, Version=98.1.210.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.98.1.210\lib\net452\CefSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CefSharp.Core, Version=97.1.11.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.97.1.11\lib\net452\CefSharp.Core.dll</HintPath>
|
||||
<Reference Include="CefSharp.Core, Version=98.1.210.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.Common.98.1.210\lib\net452\CefSharp.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CefSharp.WinForms, Version=97.1.11.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.WinForms.97.1.11\lib\net462\CefSharp.WinForms.dll</HintPath>
|
||||
<Reference Include="CefSharp.WinForms, Version=98.1.210.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CefSharp.WinForms.98.1.210\lib\net462\CefSharp.WinForms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
|
@ -95,19 +95,42 @@
|
|||
<Compile Include="Filters\RuleFactory.cs" />
|
||||
<Compile Include="Filters\Rules\SimplifiedRule.cs" />
|
||||
<Compile Include="Handlers\ContextMenuHandler.cs" />
|
||||
<Compile Include="BrowserControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="BrowserControl.cs" />
|
||||
<Compile Include="BrowserIconResource.cs" />
|
||||
<Compile Include="Handlers\DialogHandler.cs" />
|
||||
<Compile Include="Handlers\DisplayHandler.cs" />
|
||||
<Compile Include="Handlers\DownloadHandler.cs" />
|
||||
<Compile Include="Handlers\KeyboardHandler.cs" />
|
||||
<Compile Include="Handlers\LifeSpanHandler.cs" />
|
||||
<Compile Include="Handlers\RequestHandler.cs" />
|
||||
<Compile Include="Handlers\ResourceHandler.cs" />
|
||||
<Compile Include="Content\ContentLoader.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Wrapper\CefSharpBrowserControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Wrapper\CefSharpPopupControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Wrapper\Events\AuthCredentialsEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Events\BeforeBrowseEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Events\BeforeDownloadEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Events\DownloadUpdatedEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Events\FaviconUrlChangedEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Events\FileDialogRequestedEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Events\KeyEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Events\LoadingProgressChangedEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Events\GenericEventArgs.cs" />
|
||||
<Compile Include="Wrapper\Events\OpenUrlFromTabEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Events\PreKeyEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Events\ResourceRequestEventArgs.cs" />
|
||||
<Compile Include="Wrapper\Events\ResourceRequestEventHandler.cs" />
|
||||
<Compile Include="Wrapper\Extensions.cs" />
|
||||
<Compile Include="Wrapper\Handlers\DialogHandlerSwitch.cs" />
|
||||
<Compile Include="Wrapper\Handlers\DisplayHandlerSwitch.cs" />
|
||||
<Compile Include="Wrapper\Handlers\DownloadHandlerSwitch.cs" />
|
||||
<Compile Include="Wrapper\Handlers\KeyboardHandlerSwitch.cs" />
|
||||
<Compile Include="Wrapper\Handlers\RequestHandlerSwitch.cs" />
|
||||
<Compile Include="Wrapper\ICefSharpControl.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Applications.Contracts\SafeExamBrowser.Applications.Contracts.csproj">
|
||||
|
@ -153,9 +176,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Content\Api.js" />
|
||||
|
@ -172,10 +193,10 @@
|
|||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.97.1.1\build\cef.redist.x64.props'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.97.1.1\build\cef.redist.x86.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.98.1.21\build\cef.redist.x64.props'))" />
|
||||
<Error Condition="!Exists('..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.98.1.21\build\cef.redist.x86.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.props'))" />
|
||||
<Error Condition="!Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.97.1.11\build\CefSharp.Common.targets')" />
|
||||
<Import Project="..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.98.1.210\build\CefSharp.Common.targets')" />
|
||||
</Project>
|
103
SafeExamBrowser.Browser/Wrapper/CefSharpBrowserControl.cs
Normal file
103
SafeExamBrowser.Browser/Wrapper/CefSharpBrowserControl.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using SafeExamBrowser.Browser.Handlers;
|
||||
using SafeExamBrowser.Browser.Wrapper.Events;
|
||||
using SafeExamBrowser.Browser.Wrapper.Handlers;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper
|
||||
{
|
||||
internal class CefSharpBrowserControl : ChromiumWebBrowser, ICefSharpControl
|
||||
{
|
||||
public event AuthCredentialsEventHandler AuthCredentialsRequired;
|
||||
public event BeforeBrowseEventHandler BeforeBrowse;
|
||||
public event BeforeDownloadEventHandler BeforeDownload;
|
||||
public event DownloadUpdatedEventHandler DownloadUpdated;
|
||||
public event FaviconUrlChangedEventHandler FaviconUrlChanged;
|
||||
public event FileDialogRequestedEventHandler FileDialogRequested;
|
||||
public event KeyEventHandler KeyEvent;
|
||||
public event LoadingProgressChangedEventHandler LoadingProgressChanged;
|
||||
public event OpenUrlFromTabEventHandler OpenUrlFromTab;
|
||||
public event PreKeyEventHandler PreKeyEvent;
|
||||
public event ResourceRequestEventHandler ResourceRequestHandlerRequired;
|
||||
|
||||
public CefSharpBrowserControl(ILifeSpanHandler lifeSpanHandler, string url) : base(url)
|
||||
{
|
||||
DialogHandler = new DialogHandlerSwitch();
|
||||
DisplayHandler = new DisplayHandlerSwitch();
|
||||
DownloadHandler = new DownloadHandlerSwitch();
|
||||
KeyboardHandler = new KeyboardHandlerSwitch();
|
||||
LifeSpanHandler = lifeSpanHandler;
|
||||
MenuHandler = new ContextMenuHandler();
|
||||
RequestHandler = new RequestHandlerSwitch();
|
||||
}
|
||||
|
||||
void ICefSharpControl.Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public void GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback, GenericEventArgs args)
|
||||
{
|
||||
AuthCredentialsRequired?.Invoke(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback, args);
|
||||
}
|
||||
|
||||
public void GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling, ResourceRequestEventArgs args)
|
||||
{
|
||||
ResourceRequestHandlerRequired?.Invoke(webBrowser, browser, frame, request, isNavigation, isDownload, requestInitiator, ref disableDefaultHandling, args);
|
||||
}
|
||||
|
||||
public void OnBeforeBrowse(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect, GenericEventArgs args)
|
||||
{
|
||||
BeforeBrowse?.Invoke(webBrowser, browser, frame, request, userGesture, isRedirect, args);
|
||||
}
|
||||
|
||||
public void OnBeforeDownload(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
|
||||
{
|
||||
BeforeDownload?.Invoke(webBrowser, browser, downloadItem, callback);
|
||||
}
|
||||
|
||||
public void OnDownloadUpdated(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
|
||||
{
|
||||
DownloadUpdated?.Invoke(webBrowser, browser, downloadItem, callback);
|
||||
}
|
||||
|
||||
public void OnFaviconUrlChange(IWebBrowser webBrowser, IBrowser browser, IList<string> urls)
|
||||
{
|
||||
FaviconUrlChanged?.Invoke(webBrowser, browser, urls);
|
||||
}
|
||||
|
||||
public void OnFileDialog(IWebBrowser webBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback)
|
||||
{
|
||||
FileDialogRequested?.Invoke(webBrowser, browser, mode, flags, title, defaultFilePath, acceptFilters, selectedAcceptFilter, callback);
|
||||
}
|
||||
|
||||
public void OnKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
|
||||
{
|
||||
KeyEvent?.Invoke(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey);
|
||||
}
|
||||
|
||||
public void OnLoadingProgressChange(IWebBrowser webBrowser, IBrowser browser, double progress)
|
||||
{
|
||||
LoadingProgressChanged?.Invoke(webBrowser, browser, progress);
|
||||
}
|
||||
|
||||
public void OnOpenUrlFromTab(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture, GenericEventArgs args)
|
||||
{
|
||||
OpenUrlFromTab?.Invoke(webBrowser, browser, frame, targetUrl, targetDisposition, userGesture, args);
|
||||
}
|
||||
|
||||
public void OnPreKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut, GenericEventArgs args)
|
||||
{
|
||||
PreKeyEvent?.Invoke(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey, ref isKeyboardShortcut, args);
|
||||
}
|
||||
}
|
||||
}
|
98
SafeExamBrowser.Browser/Wrapper/CefSharpPopupControl.cs
Normal file
98
SafeExamBrowser.Browser/Wrapper/CefSharpPopupControl.cs
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms.Host;
|
||||
using SafeExamBrowser.Browser.Wrapper.Events;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper
|
||||
{
|
||||
internal class CefSharpPopupControl : ChromiumHostControl, ICefSharpControl
|
||||
{
|
||||
public event AuthCredentialsEventHandler AuthCredentialsRequired;
|
||||
public event BeforeBrowseEventHandler BeforeBrowse;
|
||||
public event BeforeDownloadEventHandler BeforeDownload;
|
||||
public event DownloadUpdatedEventHandler DownloadUpdated;
|
||||
public event FaviconUrlChangedEventHandler FaviconUrlChanged;
|
||||
public event FileDialogRequestedEventHandler FileDialogRequested;
|
||||
public event KeyEventHandler KeyEvent;
|
||||
public event LoadingProgressChangedEventHandler LoadingProgressChanged;
|
||||
public event OpenUrlFromTabEventHandler OpenUrlFromTab;
|
||||
public event PreKeyEventHandler PreKeyEvent;
|
||||
public event ResourceRequestEventHandler ResourceRequestHandlerRequired;
|
||||
|
||||
void ICefSharpControl.Dispose(bool disposing)
|
||||
{
|
||||
if (!IsDisposed && IsHandleCreated)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
public void GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback, GenericEventArgs args)
|
||||
{
|
||||
AuthCredentialsRequired?.Invoke(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback, args);
|
||||
}
|
||||
|
||||
public void GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling, ResourceRequestEventArgs args)
|
||||
{
|
||||
ResourceRequestHandlerRequired?.Invoke(webBrowser, browser, frame, request, isNavigation, isDownload, requestInitiator, ref disableDefaultHandling, args);
|
||||
}
|
||||
|
||||
public void Load(string address)
|
||||
{
|
||||
LoadUrl(address);
|
||||
}
|
||||
|
||||
public void OnBeforeBrowse(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect, GenericEventArgs args)
|
||||
{
|
||||
BeforeBrowse?.Invoke(webBrowser, browser, frame, request, userGesture, isRedirect, args);
|
||||
}
|
||||
|
||||
public void OnBeforeDownload(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
|
||||
{
|
||||
BeforeDownload?.Invoke(webBrowser, browser, downloadItem, callback);
|
||||
}
|
||||
|
||||
public void OnDownloadUpdated(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
|
||||
{
|
||||
DownloadUpdated?.Invoke(webBrowser, browser, downloadItem, callback);
|
||||
}
|
||||
|
||||
public void OnFaviconUrlChange(IWebBrowser webBrowser, IBrowser browser, IList<string> urls)
|
||||
{
|
||||
FaviconUrlChanged?.Invoke(webBrowser, browser, urls);
|
||||
}
|
||||
|
||||
public void OnFileDialog(IWebBrowser webBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback)
|
||||
{
|
||||
FileDialogRequested?.Invoke(webBrowser, browser, mode, flags, title, defaultFilePath, acceptFilters, selectedAcceptFilter, callback);
|
||||
}
|
||||
|
||||
public void OnKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
|
||||
{
|
||||
KeyEvent?.Invoke(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey);
|
||||
}
|
||||
|
||||
public void OnLoadingProgressChange(IWebBrowser webBrowser, IBrowser browser, double progress)
|
||||
{
|
||||
LoadingProgressChanged?.Invoke(webBrowser, browser, progress);
|
||||
}
|
||||
|
||||
public void OnOpenUrlFromTab(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture, GenericEventArgs args)
|
||||
{
|
||||
OpenUrlFromTab?.Invoke(webBrowser, browser, frame, targetUrl, targetDisposition, userGesture, args);
|
||||
}
|
||||
|
||||
public void OnPreKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut, GenericEventArgs args)
|
||||
{
|
||||
PreKeyEvent?.Invoke(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey, ref isKeyboardShortcut, args);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void AuthCredentialsEventHandler(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback, GenericEventArgs args);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void BeforeBrowseEventHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect, GenericEventArgs args);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void BeforeDownloadEventHandler(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void DownloadUpdatedEventHandler(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void FaviconUrlChangedEventHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IList<string> urls);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void FileDialogRequestedEventHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback);
|
||||
}
|
15
SafeExamBrowser.Browser/Wrapper/Events/GenericEventArgs.cs
Normal file
15
SafeExamBrowser.Browser/Wrapper/Events/GenericEventArgs.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal class GenericEventArgs
|
||||
{
|
||||
public bool Value { get; set; }
|
||||
}
|
||||
}
|
14
SafeExamBrowser.Browser/Wrapper/Events/KeyEventHandler.cs
Normal file
14
SafeExamBrowser.Browser/Wrapper/Events/KeyEventHandler.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void KeyEventHandler(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void LoadingProgressChangedEventHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, double progress);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void OpenUrlFromTabEventHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture, GenericEventArgs args);
|
||||
}
|
14
SafeExamBrowser.Browser/Wrapper/Events/PreKeyEventHandler.cs
Normal file
14
SafeExamBrowser.Browser/Wrapper/Events/PreKeyEventHandler.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void PreKeyEventHandler(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut, GenericEventArgs args);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal class ResourceRequestEventArgs
|
||||
{
|
||||
public IResourceRequestHandler Handler { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Events
|
||||
{
|
||||
internal delegate void ResourceRequestEventHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling, ResourceRequestEventArgs args);
|
||||
}
|
38
SafeExamBrowser.Browser/Wrapper/Extensions.cs
Normal file
38
SafeExamBrowser.Browser/Wrapper/Extensions.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper
|
||||
{
|
||||
internal static class Extensions
|
||||
{
|
||||
internal static FileSystemElement ToElement(this CefFileDialogMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case CefFileDialogMode.OpenFolder:
|
||||
return FileSystemElement.Folder;
|
||||
default:
|
||||
return FileSystemElement.File;
|
||||
}
|
||||
}
|
||||
|
||||
internal static FileSystemOperation ToOperation(this CefFileDialogMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case CefFileDialogMode.Save:
|
||||
return FileSystemOperation.Save;
|
||||
default:
|
||||
return FileSystemOperation.Open;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using CefSharp.WinForms.Host;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Handlers
|
||||
{
|
||||
internal class DialogHandlerSwitch : IDialogHandler
|
||||
{
|
||||
public bool OnFileDialog(IWebBrowser webBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback)
|
||||
{
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.OnFileDialog(webBrowser, browser, mode, flags, title, defaultFilePath, acceptFilters, selectedAcceptFilter, callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.OnFileDialog(webBrowser, browser, mode, flags, title, defaultFilePath, acceptFilters, selectedAcceptFilter, callback);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using CefSharp.WinForms.Handler;
|
||||
using CefSharp.WinForms.Host;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Handlers
|
||||
{
|
||||
internal class DisplayHandlerSwitch : DisplayHandler
|
||||
{
|
||||
protected override void OnFaviconUrlChange(IWebBrowser chromiumWebBrowser, IBrowser browser, IList<string> urls)
|
||||
{
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.OnFaviconUrlChange(chromiumWebBrowser, browser, urls);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.OnFaviconUrlChange(chromiumWebBrowser, browser, urls);
|
||||
}
|
||||
|
||||
base.OnFaviconUrlChange(chromiumWebBrowser, browser, urls);
|
||||
}
|
||||
|
||||
protected override void OnLoadingProgressChange(IWebBrowser chromiumWebBrowser, IBrowser browser, double progress)
|
||||
{
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.OnLoadingProgressChange(chromiumWebBrowser, browser, progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.OnLoadingProgressChange(chromiumWebBrowser, browser, progress);
|
||||
}
|
||||
|
||||
base.OnLoadingProgressChange(chromiumWebBrowser, browser, progress);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using CefSharp.WinForms.Host;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Handlers
|
||||
{
|
||||
internal class DownloadHandlerSwitch : IDownloadHandler
|
||||
{
|
||||
public void OnBeforeDownload(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
|
||||
{
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.OnBeforeDownload(webBrowser, browser, downloadItem, callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.OnBeforeDownload(webBrowser, browser, downloadItem, callback);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDownloadUpdated(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
|
||||
{
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.OnDownloadUpdated(webBrowser, browser, downloadItem, callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.OnDownloadUpdated(webBrowser, browser, downloadItem, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using CefSharp.WinForms.Host;
|
||||
using SafeExamBrowser.Browser.Wrapper.Events;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Handlers
|
||||
{
|
||||
internal class KeyboardHandlerSwitch : IKeyboardHandler
|
||||
{
|
||||
public bool OnKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
|
||||
{
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.OnKeyEvent(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.OnKeyEvent(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OnPreKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
|
||||
{
|
||||
var args = new GenericEventArgs { Value = false };
|
||||
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.OnPreKeyEvent(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey, ref isKeyboardShortcut, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.OnPreKeyEvent(webBrowser, browser, type, windowsKeyCode, nativeKeyCode, modifiers, isSystemKey, ref isKeyboardShortcut, args);
|
||||
}
|
||||
|
||||
return args.Value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using CefSharp;
|
||||
using CefSharp.Handler;
|
||||
using CefSharp.WinForms;
|
||||
using CefSharp.WinForms.Host;
|
||||
using SafeExamBrowser.Browser.Wrapper.Events;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper.Handlers
|
||||
{
|
||||
internal class RequestHandlerSwitch : RequestHandler
|
||||
{
|
||||
protected override bool GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
|
||||
{
|
||||
var args = new GenericEventArgs { Value = false };
|
||||
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.GetAuthCredentials(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.GetAuthCredentials(webBrowser, browser, originUrl, isProxy, host, port, realm, scheme, callback, args);
|
||||
}
|
||||
|
||||
return args.Value;
|
||||
}
|
||||
|
||||
protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
|
||||
{
|
||||
var args = new ResourceRequestEventArgs();
|
||||
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.GetResourceRequestHandler(chromiumWebBrowser, browser, frame, request, isNavigation, isDownload, requestInitiator, ref disableDefaultHandling, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.GetResourceRequestHandler(chromiumWebBrowser, browser, frame, request, isNavigation, isDownload, requestInitiator, ref disableDefaultHandling, args);
|
||||
}
|
||||
|
||||
return args.Handler;
|
||||
}
|
||||
|
||||
protected override bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect)
|
||||
{
|
||||
var args = new GenericEventArgs { Value = false };
|
||||
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.OnBeforeBrowse(chromiumWebBrowser, browser, frame, request, userGesture, isRedirect, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.OnBeforeBrowse(chromiumWebBrowser, browser, frame, request, userGesture, isRedirect, args);
|
||||
}
|
||||
|
||||
return args.Value;
|
||||
}
|
||||
|
||||
protected override bool OnOpenUrlFromTab(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
|
||||
{
|
||||
var args = new GenericEventArgs { Value = false };
|
||||
|
||||
if (browser.IsPopup)
|
||||
{
|
||||
var control = ChromiumHostControl.FromBrowser(browser) as CefSharpPopupControl;
|
||||
|
||||
control?.OnOpenUrlFromTab(chromiumWebBrowser, browser, frame, targetUrl, targetDisposition, userGesture, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
var control = ChromiumWebBrowser.FromBrowser(browser) as CefSharpBrowserControl;
|
||||
|
||||
control?.OnOpenUrlFromTab(chromiumWebBrowser, browser, frame, targetUrl, targetDisposition, userGesture, args);
|
||||
}
|
||||
|
||||
return args.Value;
|
||||
}
|
||||
}
|
||||
}
|
47
SafeExamBrowser.Browser/Wrapper/ICefSharpControl.cs
Normal file
47
SafeExamBrowser.Browser/Wrapper/ICefSharpControl.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using SafeExamBrowser.Browser.Wrapper.Events;
|
||||
using KeyEventHandler = SafeExamBrowser.Browser.Wrapper.Events.KeyEventHandler;
|
||||
|
||||
namespace SafeExamBrowser.Browser.Wrapper
|
||||
{
|
||||
internal interface ICefSharpControl : IChromiumWebBrowserBase, IWinFormsChromiumWebBrowser, IWin32Window, IComponent, ISynchronizeInvoke
|
||||
{
|
||||
event AuthCredentialsEventHandler AuthCredentialsRequired;
|
||||
event BeforeBrowseEventHandler BeforeBrowse;
|
||||
event BeforeDownloadEventHandler BeforeDownload;
|
||||
event DownloadUpdatedEventHandler DownloadUpdated;
|
||||
event FaviconUrlChangedEventHandler FaviconUrlChanged;
|
||||
event FileDialogRequestedEventHandler FileDialogRequested;
|
||||
event KeyEventHandler KeyEvent;
|
||||
event LoadingProgressChangedEventHandler LoadingProgressChanged;
|
||||
event OpenUrlFromTabEventHandler OpenUrlFromTab;
|
||||
event PreKeyEventHandler PreKeyEvent;
|
||||
event ResourceRequestEventHandler ResourceRequestHandlerRequired;
|
||||
|
||||
void Dispose(bool disposing);
|
||||
void GetAuthCredentials(IWebBrowser webBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback, GenericEventArgs args);
|
||||
void GetResourceRequestHandler(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling, ResourceRequestEventArgs args);
|
||||
void Load(string address);
|
||||
void OnBeforeBrowse(IWebBrowser webBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect, GenericEventArgs args);
|
||||
void OnBeforeDownload(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback);
|
||||
void OnDownloadUpdated(IWebBrowser webBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback);
|
||||
void OnFaviconUrlChange(IWebBrowser webBrowser, IBrowser browser, IList<string> urls);
|
||||
void OnFileDialog(IWebBrowser webBrowser, IBrowser browser, CefFileDialogMode mode, CefFileDialogFlags flags, string title, string defaultFilePath, List<string> acceptFilters, int selectedAcceptFilter, IFileDialogCallback callback);
|
||||
void OnKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey);
|
||||
void OnLoadingProgressChange(IWebBrowser webBrowser, IBrowser browser, double progress);
|
||||
void OnOpenUrlFromTab(IWebBrowser webBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture, GenericEventArgs args);
|
||||
void OnPreKeyEvent(IWebBrowser webBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut, GenericEventArgs args);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="cef.redist.x64" version="97.1.1" targetFramework="net472" />
|
||||
<package id="cef.redist.x86" version="97.1.1" targetFramework="net472" />
|
||||
<package id="CefSharp.Common" version="97.1.11" targetFramework="net472" />
|
||||
<package id="CefSharp.WinForms" version="97.1.11" targetFramework="net472" />
|
||||
<package id="cef.redist.x64" version="98.1.21" targetFramework="net472" />
|
||||
<package id="cef.redist.x86" version="98.1.21" targetFramework="net472" />
|
||||
<package id="CefSharp.Common" version="98.1.210" targetFramework="net472" />
|
||||
<package id="CefSharp.WinForms" version="98.1.210" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
|
||||
<package id="Syroot.Windows.IO.KnownFolders" version="1.2.3" targetFramework="net472" />
|
||||
<package id="System.Security.Principal.Windows" version="5.0.0" targetFramework="net472" />
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace SafeExamBrowser.Client.Notifications
|
|||
internal class AboutNotification : INotification
|
||||
{
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly IText text;
|
||||
private readonly IUserInterfaceFactory uiFactory;
|
||||
|
||||
private IWindow window;
|
||||
|
@ -33,7 +32,6 @@ namespace SafeExamBrowser.Client.Notifications
|
|||
public AboutNotification(AppConfig appConfig, IText text, IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
|
||||
IconResource = new XamlIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/AboutNotification.xaml") };
|
||||
|
@ -42,11 +40,11 @@ namespace SafeExamBrowser.Client.Notifications
|
|||
|
||||
public void Activate()
|
||||
{
|
||||
if (window == default(IWindow))
|
||||
if (window == default)
|
||||
{
|
||||
window = uiFactory.CreateAboutWindow(appConfig);
|
||||
|
||||
window.Closing += () => window = default(IWindow);
|
||||
window.Closed += () => window = default;
|
||||
window.Show();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace SafeExamBrowser.Client.Notifications
|
|||
internal class LogNotification : INotification
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly IText text;
|
||||
private readonly IUserInterfaceFactory uiFactory;
|
||||
|
||||
private IWindow window;
|
||||
|
@ -33,7 +32,6 @@ namespace SafeExamBrowser.Client.Notifications
|
|||
public LogNotification(ILogger logger, IText text, IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
|
||||
IconResource = new BitmapIconResource { Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/LogNotification.ico") };
|
||||
|
@ -42,11 +40,11 @@ namespace SafeExamBrowser.Client.Notifications
|
|||
|
||||
public void Activate()
|
||||
{
|
||||
if (window == default(IWindow))
|
||||
if (window == default)
|
||||
{
|
||||
window = uiFactory.CreateLogWindow(logger);
|
||||
|
||||
window.Closing += () => window = null;
|
||||
window.Closed += () => window = default;
|
||||
window.Show();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -52,14 +52,14 @@
|
|||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Web.WebView2.Core, Version=1.0.1072.54, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1072.54\lib\net45\Microsoft.Web.WebView2.Core.dll</HintPath>
|
||||
<Reference Include="Microsoft.Web.WebView2.Core, Version=1.0.1108.44, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1108.44\lib\net45\Microsoft.Web.WebView2.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.WebView2.WinForms, Version=1.0.1072.54, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1072.54\lib\net45\Microsoft.Web.WebView2.WinForms.dll</HintPath>
|
||||
<Reference Include="Microsoft.Web.WebView2.WinForms, Version=1.0.1108.44, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1108.44\lib\net45\Microsoft.Web.WebView2.WinForms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.WebView2.Wpf, Version=1.0.1072.54, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1072.54\lib\net45\Microsoft.Web.WebView2.Wpf.dll</HintPath>
|
||||
<Reference Include="Microsoft.Web.WebView2.Wpf, Version=1.0.1108.44, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.1108.44\lib\net45\Microsoft.Web.WebView2.Wpf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
|
@ -124,11 +124,11 @@
|
|||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\Microsoft.Web.WebView2.1.0.1072.54\build\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.1072.54\build\Microsoft.Web.WebView2.targets')" />
|
||||
<Import Project="..\packages\Microsoft.Web.WebView2.1.0.1108.44\build\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.1108.44\build\Microsoft.Web.WebView2.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.1072.54\build\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.1072.54\build\Microsoft.Web.WebView2.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.1108.44\build\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.1108.44\build\Microsoft.Web.WebView2.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.1072.54" targetFramework="net472" />
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.1108.44" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
|
||||
</packages>
|
|
@ -120,13 +120,13 @@ namespace SafeExamBrowser.Runtime
|
|||
}
|
||||
|
||||
internal void LogStartupInformation()
|
||||
{
|
||||
{
|
||||
logger.Log($"/* {appConfig.ProgramTitle}, Version {appConfig.ProgramInformationalVersion}, Build {appConfig.ProgramBuildVersion}");
|
||||
logger.Log($"/* {appConfig.ProgramCopyright}");
|
||||
logger.Log($"/* ");
|
||||
logger.Log($"/* Please visit https://www.github.com/SafeExamBrowser for more information.");
|
||||
logger.Log(string.Empty);
|
||||
logger.Log($"# Application started at {appConfig.ApplicationStartTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
logger.Log($"# Application started at {appConfig.ApplicationStartTime:yyyy-MM-dd HH:mm:ss.fff}");
|
||||
logger.Log($"# Running on {systemInfo.OperatingSystemInfo}");
|
||||
logger.Log($"# Computer '{systemInfo.Name}' is a {systemInfo.Model} manufactured by {systemInfo.Manufacturer}");
|
||||
logger.Log($"# Runtime-ID: {appConfig.RuntimeId}");
|
||||
|
@ -135,7 +135,7 @@ namespace SafeExamBrowser.Runtime
|
|||
|
||||
internal void LogShutdownInformation()
|
||||
{
|
||||
logger?.Log($"# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
logger?.Log($"# Application terminated at {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
|
||||
}
|
||||
|
||||
private void InitializeConfiguration()
|
||||
|
|
|
@ -31,6 +31,11 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser
|
|||
/// </summary>
|
||||
bool CanNavigateForwards { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The user interface control to be embedded in an <see cref="IBrowserWindow"/>.
|
||||
/// </summary>
|
||||
object EmbeddableControl { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the address of the browser control changes.
|
||||
/// </summary>
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
<Compile Include="Windows\Data\LockScreenOption.cs" />
|
||||
<Compile Include="Windows\Data\LockScreenResult.cs" />
|
||||
<Compile Include="Windows\Data\ServerFailureDialogResult.cs" />
|
||||
<Compile Include="Windows\Events\WindowClosedEventHandler.cs" />
|
||||
<Compile Include="Windows\Events\WindowClosingEventHandler.cs" />
|
||||
<Compile Include="Windows\IExamSelectionDialog.cs" />
|
||||
<Compile Include="Windows\ILockScreen.cs" />
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Contracts.Windows.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a window has been closed.
|
||||
/// </summary>
|
||||
public delegate void WindowClosedEventHandler();
|
||||
}
|
|
@ -15,6 +15,11 @@ namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
|||
/// </summary>
|
||||
public interface IWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Event fired when the window has been closed;
|
||||
/// </summary>
|
||||
event WindowClosedEventHandler Closed;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the window is closing.
|
||||
/// </summary>
|
||||
|
|
|
@ -18,10 +18,18 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
{
|
||||
internal partial class AboutWindow : Window, IWindow
|
||||
{
|
||||
private AppConfig appConfig;
|
||||
private IText text;
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly IText text;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -44,6 +52,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
|
||||
private void InitializeAboutWindow()
|
||||
{
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += (o, args) => closing?.Invoke();
|
||||
MainText.Inlines.InsertBefore(MainText.Inlines.FirstInline, new Run(text.Get(TextKey.AboutWindow_LicenseInfo)));
|
||||
Title = text.Get(TextKey.AboutWindow_Title);
|
||||
|
|
|
@ -30,9 +30,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
{
|
||||
internal partial class BrowserWindow : Window, IBrowserWindow
|
||||
{
|
||||
private bool isMainWindow;
|
||||
private BrowserSettings settings;
|
||||
private IText text;
|
||||
private readonly bool isMainWindow;
|
||||
private readonly BrowserSettings settings;
|
||||
private readonly IText text;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
private WindowSettings WindowSettings
|
||||
|
@ -55,6 +57,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
public event ActionRequestedEventHandler ZoomOutRequested;
|
||||
public event ActionRequestedEventHandler ZoomResetRequested;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -282,7 +290,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
|
||||
private void InitializeBrowserWindow(IBrowserControl browserControl)
|
||||
{
|
||||
if (browserControl is System.Windows.Forms.Control control)
|
||||
if (browserControl.EmbeddableControl is System.Windows.Forms.Control control)
|
||||
{
|
||||
BrowserControlHost.Child = control;
|
||||
}
|
||||
|
@ -297,6 +305,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
private void RegisterEvents()
|
||||
{
|
||||
BackwardButton.Click += (o, args) => BackwardNavigationRequested?.Invoke();
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += BrowserWindow_Closing;
|
||||
DeveloperConsoleButton.Click += (o, args) => DeveloperConsoleRequested?.Invoke();
|
||||
DownloadsButton.Click += (o, args) => DownloadsPopup.IsOpen = !DownloadsPopup.IsOpen;
|
||||
|
|
|
@ -25,9 +25,16 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
{
|
||||
internal partial class LockScreen : Window, ILockScreen
|
||||
{
|
||||
private AutoResetEvent autoResetEvent;
|
||||
private readonly AutoResetEvent autoResetEvent;
|
||||
private readonly IText text;
|
||||
|
||||
private IList<Window> windows;
|
||||
private IText text;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { throw new NotImplementedException(); }
|
||||
remove { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
|
|
|
@ -19,10 +19,18 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
{
|
||||
internal partial class LogWindow : Window, IWindow
|
||||
{
|
||||
private ILogger logger;
|
||||
private LogViewModel model;
|
||||
private readonly ILogger logger;
|
||||
private readonly LogViewModel model;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -70,6 +78,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
private void InitializeLogWindow()
|
||||
{
|
||||
DataContext = model;
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += LogWindow_Closing;
|
||||
Loaded += LogWindow_Loaded;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,17 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
{
|
||||
internal partial class PasswordDialog : Window, IPasswordDialog
|
||||
{
|
||||
private IText text;
|
||||
private readonly IText text;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -73,6 +81,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
ConfirmButton.Content = text.Get(TextKey.PasswordDialog_Confirm);
|
||||
ConfirmButton.Click += ConfirmButton_Click;
|
||||
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += (o, args) => closing?.Invoke();
|
||||
Loaded += (o, args) => Activate();
|
||||
Password.KeyUp += Password_KeyUp;
|
||||
|
|
|
@ -18,8 +18,15 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
{
|
||||
public partial class ProctoringWindow : Window, IProctoringWindow
|
||||
{
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -99,6 +106,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
control.FullScreenChanged += Control_FullScreenChanged;
|
||||
}
|
||||
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += ProctoringWindow_Closing;
|
||||
Loaded += ProctoringWindow_Loaded;
|
||||
Top = SystemParameters.WorkArea.Height - Height - 15;
|
||||
|
|
|
@ -20,10 +20,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
{
|
||||
internal partial class RuntimeWindow : Window, IRuntimeWindow
|
||||
{
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly IText text;
|
||||
|
||||
private bool allowClose;
|
||||
private AppConfig appConfig;
|
||||
private IText text;
|
||||
private RuntimeWindowViewModel model;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
public bool ShowLog
|
||||
|
@ -48,6 +51,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
set => Dispatcher.Invoke(() => Topmost = value);
|
||||
}
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -74,6 +83,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
{
|
||||
allowClose = true;
|
||||
model.BusyIndication = false;
|
||||
closing?.Invoke();
|
||||
|
||||
base.Close();
|
||||
});
|
||||
|
@ -145,6 +155,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
ProgressBar.DataContext = model;
|
||||
StatusTextBlock.DataContext = model;
|
||||
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += (o, args) => args.Cancel = !allowClose;
|
||||
|
||||
#if DEBUG
|
||||
|
|
|
@ -19,10 +19,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
{
|
||||
internal partial class SplashScreen : Window, ISplashScreen
|
||||
{
|
||||
private bool allowClose;
|
||||
private ProgressIndicatorViewModel model = new ProgressIndicatorViewModel();
|
||||
private readonly ProgressIndicatorViewModel model;
|
||||
private readonly IText text;
|
||||
|
||||
private AppConfig appConfig;
|
||||
private IText text;
|
||||
private bool allowClose;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
public AppConfig AppConfig
|
||||
|
@ -37,6 +40,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
}
|
||||
}
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -46,6 +55,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
internal SplashScreen(IText text, AppConfig appConfig = null)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.model = new ProgressIndicatorViewModel();
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
|
@ -63,6 +73,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
{
|
||||
allowClose = true;
|
||||
model.BusyIndication = false;
|
||||
closing?.Invoke();
|
||||
|
||||
base.Close();
|
||||
});
|
||||
|
@ -116,6 +127,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
|
|||
StatusTextBlock.DataContext = model;
|
||||
ProgressBar.DataContext = model;
|
||||
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += (o, args) => args.Cancel = !allowClose;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,18 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
{
|
||||
internal partial class AboutWindow : Window, IWindow
|
||||
{
|
||||
private AppConfig appConfig;
|
||||
private IText text;
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly IText text;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -44,6 +52,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
|
||||
private void InitializeAboutWindow()
|
||||
{
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += (o, args) => closing?.Invoke();
|
||||
MainText.Inlines.InsertBefore(MainText.Inlines.FirstInline, new Run(text.Get(TextKey.AboutWindow_LicenseInfo)));
|
||||
Title = text.Get(TextKey.AboutWindow_Title);
|
||||
|
|
|
@ -30,9 +30,11 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
{
|
||||
internal partial class BrowserWindow : Window, IBrowserWindow
|
||||
{
|
||||
private bool isMainWindow;
|
||||
private BrowserSettings settings;
|
||||
private IText text;
|
||||
private readonly bool isMainWindow;
|
||||
private readonly BrowserSettings settings;
|
||||
private readonly IText text;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
private WindowSettings WindowSettings
|
||||
|
@ -55,6 +57,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
public event ActionRequestedEventHandler ZoomOutRequested;
|
||||
public event ActionRequestedEventHandler ZoomResetRequested;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -282,7 +290,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
|
||||
private void InitializeBrowserWindow(IBrowserControl browserControl)
|
||||
{
|
||||
if (browserControl is System.Windows.Forms.Control control)
|
||||
if (browserControl.EmbeddableControl is System.Windows.Forms.Control control)
|
||||
{
|
||||
BrowserControlHost.Child = control;
|
||||
}
|
||||
|
@ -297,6 +305,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
private void RegisterEvents()
|
||||
{
|
||||
BackwardButton.Click += (o, args) => BackwardNavigationRequested?.Invoke();
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += BrowserWindow_Closing;
|
||||
DeveloperConsoleButton.Click += (o, args) => DeveloperConsoleRequested?.Invoke();
|
||||
DownloadsButton.Click += (o, args) => DownloadsPopup.IsOpen = !DownloadsPopup.IsOpen;
|
||||
|
|
|
@ -25,9 +25,16 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
{
|
||||
internal partial class LockScreen : Window, ILockScreen
|
||||
{
|
||||
private AutoResetEvent autoResetEvent;
|
||||
private readonly AutoResetEvent autoResetEvent;
|
||||
private readonly IText text;
|
||||
|
||||
private IList<Window> windows;
|
||||
private IText text;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { throw new NotImplementedException(); }
|
||||
remove { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
|
|
|
@ -19,10 +19,18 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
{
|
||||
internal partial class LogWindow : Window, IWindow
|
||||
{
|
||||
private ILogger logger;
|
||||
private LogViewModel model;
|
||||
private readonly ILogger logger;
|
||||
private readonly LogViewModel model;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -70,6 +78,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
private void InitializeLogWindow()
|
||||
{
|
||||
DataContext = model;
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += LogWindow_Closing;
|
||||
Loaded += LogWindow_Loaded;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,17 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
{
|
||||
internal partial class PasswordDialog : Window, IPasswordDialog
|
||||
{
|
||||
private IText text;
|
||||
private readonly IText text;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -83,6 +91,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
ConfirmButton.Content = text.Get(TextKey.PasswordDialog_Confirm);
|
||||
ConfirmButton.Click += ConfirmButton_Click;
|
||||
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += (o, args) => closing?.Invoke();
|
||||
Loaded += (o, args) => Activate();
|
||||
Password.KeyUp += Password_KeyUp;
|
||||
|
|
|
@ -18,8 +18,15 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
{
|
||||
public partial class ProctoringWindow : Window, IProctoringWindow
|
||||
{
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -99,6 +106,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
control.FullScreenChanged += Control_FullScreenChanged;
|
||||
}
|
||||
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += ProctoringWindow_Closing;
|
||||
Loaded += ProctoringWindow_Loaded;
|
||||
Top = SystemParameters.WorkArea.Height - Height - 15;
|
||||
|
|
|
@ -20,10 +20,13 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
{
|
||||
internal partial class RuntimeWindow : Window, IRuntimeWindow
|
||||
{
|
||||
private readonly AppConfig appConfig;
|
||||
private readonly IText text;
|
||||
|
||||
private bool allowClose;
|
||||
private AppConfig appConfig;
|
||||
private IText text;
|
||||
private RuntimeWindowViewModel model;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
public bool ShowLog
|
||||
|
@ -48,6 +51,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
set => Dispatcher.Invoke(() => Topmost = value);
|
||||
}
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -74,6 +83,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
{
|
||||
allowClose = true;
|
||||
model.BusyIndication = false;
|
||||
closing?.Invoke();
|
||||
|
||||
base.Close();
|
||||
});
|
||||
|
@ -145,6 +155,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
ProgressBar.DataContext = model;
|
||||
StatusTextBlock.DataContext = model;
|
||||
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += (o, args) => args.Cancel = !allowClose;
|
||||
|
||||
#if DEBUG
|
||||
|
|
|
@ -19,10 +19,13 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
{
|
||||
internal partial class SplashScreen : Window, ISplashScreen
|
||||
{
|
||||
private readonly ProgressIndicatorViewModel model;
|
||||
private readonly IText text;
|
||||
|
||||
private bool allowClose;
|
||||
private ProgressIndicatorViewModel model = new ProgressIndicatorViewModel();
|
||||
private AppConfig appConfig;
|
||||
private IText text;
|
||||
|
||||
private WindowClosedEventHandler closed;
|
||||
private WindowClosingEventHandler closing;
|
||||
|
||||
public AppConfig AppConfig
|
||||
|
@ -37,6 +40,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
}
|
||||
}
|
||||
|
||||
event WindowClosedEventHandler IWindow.Closed
|
||||
{
|
||||
add { closed += value; }
|
||||
remove { closed -= value; }
|
||||
}
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { closing += value; }
|
||||
|
@ -46,6 +55,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
internal SplashScreen(IText text, AppConfig appConfig = null)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.model = new ProgressIndicatorViewModel();
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
|
@ -63,6 +73,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
{
|
||||
allowClose = true;
|
||||
model.BusyIndication = false;
|
||||
closing?.Invoke();
|
||||
|
||||
base.Close();
|
||||
});
|
||||
|
@ -116,6 +127,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
|
|||
StatusTextBlock.DataContext = model;
|
||||
ProgressBar.DataContext = model;
|
||||
|
||||
Closed += (o, args) => closed?.Invoke();
|
||||
Closing += (o, args) => args.Cancel = !allowClose;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue