Compare commits

...

12 Commits

Author SHA1 Message Date
Robert Muehsig
a2514ed5bc build script updated 2023-03-27 20:04:37 +02:00
Gregor Biswanger
b453278803 Update to new Electron.NET 23.6.1 2023-03-24 14:16:14 +01:00
Gregor Biswanger
a244382383 Add workaround for web-socket communication 2023-03-24 14:15:55 +01:00
Gregor Biswanger
a82e714ef8 Update Changelog für Electron.NET 23.6.1 2023-03-24 13:27:21 +01:00
Gregor Biswanger
b339485fdc Change signature of PrintToPDFOptions 2023-03-24 13:26:15 +01:00
Gregor Biswanger
551635867d Replace deprecated scroll-touch-events with input-event 2023-03-24 01:50:13 +01:00
Gregor Biswanger
941b8cf5c2 Add vscode dev profiles 2023-03-24 01:47:11 +01:00
Gregor Biswanger
06b01f75da Update Demo App to 23.6.1 2023-03-23 20:53:58 +01:00
Gregor Biswanger
e4b1f6586e Update NPM packages 2023-03-23 20:42:42 +01:00
Gregor Biswanger
0657a274d4 Add socket.io client csharp package 2023-03-23 20:29:08 +01:00
Gregor Biswanger
e3acc79c4f Change to .NET 6 build 2023-03-15 23:26:09 +01:00
Gregor Biswanger
73c1d1cd46 Upgrade to .NET 7 2023-02-24 14:56:40 +01:00
44 changed files with 8738 additions and 4993 deletions

32
.vscode/tasks.json vendored
View File

@@ -1,16 +1,18 @@
{
"version": "0.1.0",
"command": "dotnet",
"isShellCommand": true,
"args": [],
"tasks": [
{
"taskName": "build",
"args": [
"${workspaceRoot}/ElectronNET.CLI/ElectronNET.CLI.csproj"
],
"isBuildCommand": true,
"problemMatcher": "$msCompile"
}
]
}
"version": "2.0.0",
"command": "dotnet",
"args": [],
"tasks": [
{
"label": "build",
"type": "shell",
"command": "dotnet",
"args": ["build", "${workspaceRoot}/ElectronNET.CLI/ElectronNET.CLI.csproj"],
"problemMatcher": "$msCompile",
"group": {
"_id": "build",
"isDefault": false
}
}
]
}

View File

@@ -1,5 +1,22 @@
# Not released
# 23.6.2
# Released
# 23.6.1
ElectronNET.CLI:
* New Feature: Upgrade to .NET 6 support
ElectronNET.API:
* New Feature: Native Electron 23.2.0 support, but not all new API features included (we search contributors)
* New Feature: Upgrade to .NET 6 support
* New Feature: Changed Web-Socket .NET Library to [SocketIOClient](https://github.com/doghappy/socket.io-client-csharp)
* Breaking Changes: We removed deprecated API events/methods from ElectronNET.API [(More Details)](https://www.electronjs.org/docs/latest/breaking-changes)
# 13.5.1
ElectronNET.CLI:
@@ -25,9 +42,6 @@ ElectronNET.API:
* Fixed bug: Fix splash screen interaction causing crashes, ghost dragging, and resizable behavior #540 (thanks [MiniguyBrendan](https://github.com/MiniguyBrendan)) [\#540](https://github.com/ElectronNET/Electron.NET/pull/540)
* Fixed bug: Vibrancy serialization fix (thanks [tantumalice](https://github.com/tantumalice)) [\#573](https://github.com/ElectronNET/Electron.NET/pull/573)
# Released
# 11.5.1
ElectronNET.CLI:

View File

@@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using ElectronNET.API.Extensions;
using static System.Collections.Specialized.BitVector32;
namespace ElectronNET.API
{
@@ -1614,29 +1615,29 @@ namespace ElectronNET.API
/// Subscribe to an unmapped event on the <see cref="App"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void On(string eventName, Action fn)
=> Events.Instance.On(ModuleName, eventName, fn);
/// <param name="action">The handler</param>
public void On(string eventName, Action action)
=> Events.Instance.On(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void On(string eventName, Action<object> fn)
=> Events.Instance.On(ModuleName, eventName, fn);
/// <param name="action">The handler</param>
public async Task On(string eventName, Action<object> action)
=> await Events.Instance.On(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void Once(string eventName, Action fn)
=> Events.Instance.Once(ModuleName, eventName, fn);
/// <param name="action">The handler</param>
public void Once(string eventName, Action action)
=> Events.Instance.Once(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="App"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void Once(string eventName, Action<object> fn)
=> Events.Instance.Once(ModuleName, eventName, fn);
/// <param name="action">The handler</param>
public async Task Once(string eventName, Action<object> action)
=> await Events.Instance.Once(ModuleName, eventName, action);
}
}

View File

@@ -1,38 +1,27 @@
using Quobject.SocketIoClientDotNet.Client;
using System;
namespace ElectronNET.API
namespace ElectronNET.API
{
internal static class BridgeConnector
{
private static Socket _socket;
private static object _syncRoot = new object();
private static SocketIoFacade _socket;
private static readonly object SyncRoot = new();
public static Socket Socket
public static SocketIoFacade Socket
{
get
{
if(_socket == null && HybridSupport.IsElectronActive)
if (_socket == null)
{
lock (_syncRoot)
lock (SyncRoot)
{
if (_socket == null && HybridSupport.IsElectronActive)
if (_socket == null)
{
_socket = IO.Socket("http://localhost:" + BridgeSettings.SocketPort);
_socket.On(Socket.EVENT_CONNECT, () =>
{
Console.WriteLine("BridgeConnector connected!");
});
}
}
}
else if(_socket == null && !HybridSupport.IsElectronActive)
{
lock (_syncRoot)
{
if (_socket == null && !HybridSupport.IsElectronActive)
{
_socket = IO.Socket(new Uri("http://localhost"), new IO.Options { AutoConnect = false });
string socketUrl = HybridSupport.IsElectronActive
? $"http://localhost:{BridgeSettings.SocketPort}"
: "http://localhost";
_socket = new SocketIoFacade(socketUrl);
_socket.Connect();
}
}
}
@@ -41,4 +30,4 @@ namespace ElectronNET.API
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ElectronNET.API.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ElectronNET.API.Converter;
/// <summary>
///
/// </summary>
public class ModifierTypeListConverter : JsonConverter<List<ModifierType>>
{
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <param name="objectType"></param>
/// <param name="existingValue"></param>
/// <param name="hasExistingValue"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public override List<ModifierType> ReadJson(JsonReader reader, Type objectType, List<ModifierType> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
if (token.Type == JTokenType.Null)
{
return null;
}
return token.ToObject<List<string>>().Select(m => (ModifierType)Enum.Parse(typeof(ModifierType), m)).ToList();
}
/// <summary>
///
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
/// <param name="serializer"></param>
public override void WriteJson(JsonWriter writer, List<ModifierType> value, JsonSerializer serializer)
{
writer.WriteStartArray();
foreach (var modifier in value)
{
writer.WriteValue(modifier.ToString());
}
writer.WriteEndArray();
}
}

View File

@@ -5,7 +5,6 @@ using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web;
namespace ElectronNET.API
{

View File

@@ -1,11 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageOutputPath>..\artifacts</PackageOutputPath>
<PackageId>ElectronNET.API</PackageId>
<Authors>Gregor Biswanger, Robert Muehsig</Authors>
<Authors>Gregor Biswanger, Florian Rappl</Authors>
<Company />
<Product>Electron.NET</Product>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
@@ -21,11 +20,9 @@ This package contains the API to access the "native" electron API.</Description>
<Version>99.0.0.0</Version>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<None Include="PackageIcon.png" Pack="true" PackagePath="\" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(OS)' == 'Windows_NT'">
<Exec Command="$(ProjectDir)devCleanup.cmd" IgnoreExitCode="true" />
</Target>
@@ -33,15 +30,19 @@ This package contains the API to access the "native" electron API.</Description>
<Exec Command="$(ProjectDir)devCleanup.sh" IgnoreExitCode="true" />
</Target>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SocketIoClientDotNet" Version="1.0.5" />
<PackageReference Include="System.Drawing.Common" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SocketIOClient" Version="3.0.8" />
<PackageReference Include="SocketIOClient.Newtonsoft.Json" Version="3.0.7" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.410601">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
</Project>

View File

@@ -0,0 +1,81 @@
using Newtonsoft.Json.Converters;
using System.Collections.Generic;
using ElectronNET.API.Converter;
using Newtonsoft.Json;
namespace ElectronNET.API.Entities
{
/// <summary>
///
/// </summary>
public class InputEvent
{
/// <summary>
/// Equivalent to KeyboardEvent.key.
/// </summary>
public string Key { get; set; } = "";
/// <summary>
/// Equivalent to KeyboardEvent.code.
/// </summary>
public string Code { get; set; } = "";
/// <summary>
/// Equivalent to KeyboardEvent.repeat.
/// </summary>
public bool IsAutoRepeat { get; set; } = false;
/// <summary>
/// Equivalent to KeyboardEvent.isComposing.
/// </summary>
public bool IsComposing { get; set; } = false;
/// <summary>
/// Equivalent to KeyboardEvent.shiftKey.
/// </summary>
public bool Shift { get; set; } = false;
/// <summary>
/// Equivalent to KeyboardEvent.controlKey.
/// </summary>
public bool Control { get; set; } = false;
/// <summary>
/// Equivalent to KeyboardEvent.altKey.
/// </summary>
public bool Alt { get; set; } = false;
/// <summary>
/// Equivalent to KeyboardEvent.metaKey.
/// </summary>
public bool Meta { get; set; } = false;
/// <summary>
/// Equivalent to KeyboardEvent.location.
/// </summary>
public int Location { get; set; } = 0;
/// <summary>
/// An array of modifiers of the event, can be `shift`, `control`, `ctrl`, `alt`,
/// `meta`, `command`, `cmd`, `isKeypad`, `isAutoRepeat`, `leftButtonDown`,
/// `middleButtonDown`, `rightButtonDown`, `capsLock`, `numLock`, `left`, `right`
/// </summary>
[JsonConverter(typeof(ModifierTypeListConverter))]
public List<ModifierType> Modifiers { get; set; }
/// <summary>
/// Can be `undefined`, `mouseDown`, `mouseUp`, `mouseMove`, `mouseEnter`,
/// `mouseLeave`, `contextMenu`, `mouseWheel`, `rawKeyDown`, `keyDown`, `keyUp`,
/// `gestureScrollBegin`, `gestureScrollEnd`, `gestureScrollUpdate`,
/// `gestureFlingStart`, `gestureFlingCancel`, `gesturePinchBegin`,
/// `gesturePinchEnd`, `gesturePinchUpdate`, `gestureTapDown`, `gestureShowPress`,
/// `gestureTap`, `gestureTapCancel`, `gestureShortPress`, `gestureLongPress`,
/// `gestureLongTap`, `gestureTwoFingerTap`, `gestureTapUnconfirmed`,
/// `gestureDoubleTap`, `touchStart`, `touchMove`, `touchEnd`, `touchCancel`,
/// `touchScrollStarted`, `pointerDown`, `pointerUp`, `pointerMove`,
/// `pointerRawUpdate`, `pointerCancel` or `pointerCausedUaAction`.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public InputEventType Type { get; set; }
}
}

View File

@@ -0,0 +1,201 @@
namespace ElectronNET.API.Entities;
/// <summary>
///
/// </summary>
public enum InputEventType
{
/// <summary>
///
/// </summary>
undefined,
/// <summary>
///
/// </summary>
mouseDown,
/// <summary>
///
/// </summary>
mouseUp,
/// <summary>
///
/// </summary>
mouseMove,
/// <summary>
///
/// </summary>
mouseEnter,
/// <summary>
///
/// </summary>
mouseLeave,
/// <summary>
///
/// </summary>
contextMenu,
/// <summary>
///
/// </summary>
mouseWheel,
/// <summary>
///
/// </summary>
rawKeyDown,
/// <summary>
///
/// </summary>
keyDown,
/// <summary>
///
/// </summary>
keyUp,
/// <summary>
///
/// </summary>
gestureScrollBegin,
/// <summary>
///
/// </summary>
gestureScrollEnd,
/// <summary>
///
/// </summary>
gestureScrollUpdate,
/// <summary>
///
/// </summary>
gestureFlingStart,
/// <summary>
///
/// </summary>
gestureFlingCancel,
/// <summary>
///
/// </summary>
gesturePinchBegin,
/// <summary>
///
/// </summary>
gesturePinchEnd,
/// <summary>
///
/// </summary>
gesturePinchUpdate,
/// <summary>
///
/// </summary>
gestureTapDown,
/// <summary>
///
/// </summary>
gestureShowPress,
/// <summary>
///
/// </summary>
gestureTap,
/// <summary>
///
/// </summary>
gestureTapCancel,
/// <summary>
///
/// </summary>
gestureShortPress,
/// <summary>
///
/// </summary>
gestureLongPress,
/// <summary>
///
/// </summary>
gestureLongTap,
/// <summary>
///
/// </summary>
gestureTwoFingerTap,
/// <summary>
///
/// </summary>
gestureTapUnconfirmed,
/// <summary>
///
/// </summary>
gestureDoubleTap,
/// <summary>
///
/// </summary>
touchStart,
/// <summary>
///
/// </summary>
touchMove,
/// <summary>
///
/// </summary>
touchEnd,
/// <summary>
///
/// </summary>
touchCancel,
/// <summary>
///
/// </summary>
touchScrollStarted,
/// <summary>
///
/// </summary>
pointerDown,
/// <summary>
///
/// </summary>
pointerUp,
/// <summary>
///
/// </summary>
pointerMove,
/// <summary>
///
/// </summary>
pointerRawUpdate,
/// <summary>
///
/// </summary>
pointerCancel,
/// <summary>
///
/// </summary>
pointerCausedUaAction
}

View File

@@ -0,0 +1,33 @@
namespace ElectronNET.API.Entities;
/// <summary>
///
/// </summary>
public class Margins
{
/// <summary>
/// Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen,
/// you will also need to specify `top`, `bottom`, `left`, and `right`.
/// </summary>
public string MarginType { get; set; }
/// <summary>
/// The top margin of the printed web page, in pixels.
/// </summary>
public int Top { get; set; }
/// <summary>
/// The bottom margin of the printed web page, in pixels.
/// </summary>
public int Bottom { get; set; }
/// <summary>
/// The left margin of the printed web page, in pixels.
/// </summary>
public int Left { get; set; }
/// <summary>
/// The right margin of the printed web page, in pixels.
/// </summary>
public int Right { get; set; }
}

View File

@@ -0,0 +1,87 @@
namespace ElectronNET.API.Entities;
/// <summary>
/// Specifies the possible modifier keys for a keyboard input.
/// </summary>
public enum ModifierType
{
/// <summary>
/// The Shift key.
/// </summary>
shift,
/// <summary>
/// The Control key.
/// </summary>
control,
/// <summary>
/// The Control key (alias for control).
/// </summary>
ctrl,
/// <summary>
/// The Alt key.
/// </summary>
alt,
/// <summary>
/// The Meta key.
/// </summary>
meta,
/// <summary>
/// The Command key.
/// </summary>
command,
/// <summary>
/// The Command key (alias for command).
/// </summary>
cmd,
/// <summary>
/// Indicates whether the keypad modifier key is pressed.
/// </summary>
isKeypad,
/// <summary>
/// Indicates whether the key is an auto-repeated key.
/// </summary>
isAutoRepeat,
/// <summary>
/// Indicates whether the left mouse button is pressed.
/// </summary>
leftButtonDown,
/// <summary>
/// Indicates whether the middle mouse button is pressed.
/// </summary>
middleButtonDown,
/// <summary>
/// Indicates whether the right mouse button is pressed.
/// </summary>
rightButtonDown,
/// <summary>
/// The Caps Lock key.
/// </summary>
capsLock,
/// <summary>
/// The Num Lock key.
/// </summary>
numlock,
/// <summary>
/// The Left key.
/// </summary>
left,
/// <summary>
/// The Right key.
/// </summary>
right
}

View File

@@ -1,35 +1,63 @@
namespace ElectronNET.API.Entities
namespace ElectronNET.API.Entities;
/// <summary>
///
/// </summary>
public class PrintToPDFOptions
{
/// <summary>
///
/// Paper orientation. `true` for landscape, `false` for portrait. Defaults to false.
/// </summary>
public class PrintToPDFOptions
{
/// <summary>
/// Specifies the type of margins to use. Uses 0 for default margin, 1 for no
/// margin, and 2 for minimum margin.
/// </summary>
public int MarginsType { get; set; }
public bool Landscape { get; set; } = false;
/// <summary>
/// Specify page size of the generated PDF. Can be A3, A4, A5, Legal, Letter,
/// Tabloid or an Object containing height and width in microns.
/// </summary>
public string PageSize { get; set; }
/// <summary>
/// Whether to display header and footer. Defaults to false.
/// </summary>
public bool DisplayHeaderFooter { get; set; } = false;
/// <summary>
/// Whether to print CSS backgrounds.
/// </summary>
public bool PrintBackground { get; set; }
/// <summary>
/// Whether to print background graphics. Defaults to false.
/// </summary>
public bool PrintBackground { get; set; } = false;
/// <summary>
/// Whether to print selection only.
/// </summary>
public bool PrintSelectionOnly { get; set; }
/// <summary>
/// Scale of the webpage rendering. Defaults to 1.
/// </summary>
public double Scale { get; set; } = 1;
/// <summary>
/// true for landscape, false for portrait.
/// </summary>
public bool Landscape { get; set; }
}
/// <summary>
/// Specify page size of the generated PDF. Can be `A0`, `A1`, `A2`, `A3`, `A4`,
/// `A5`, `A6`, `Legal`, `Letter`, `Tabloid`, `Ledger`, or an Object containing
/// `height` and `width` in inches. Defaults to `Letter`.
/// </summary>
public string PageSize { get; set; } = "Letter";
/// <summary>
/// Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string,
/// which means print all pages.
/// </summary>
public string PageRanges { get; set; } = "";
/// <summary>
/// HTML template for the print header. Should be valid HTML markup with following
/// classes used to inject printing values into them: `date` (formatted print date),
/// `title` (document title), `url` (document location), `pageNumber` (current page
/// number) and `totalPages` (total pages in the document). For example, `<span class="title"></span>`
/// would generate span containing the title.
/// </summary>
public string HeaderTemplate { get; set; }
/// <summary>
/// HTML template for the print footer. Should use the same format as the
/// `headerTemplate`.
/// </summary>
public string FooterTemplate { get; set; }
/// <summary>
/// Whether or not to prefer page size as defined by css. Defaults to false, in
/// which case the content will be scaled to fit the paper size.
/// </summary>
public bool PreferCSSPageSize { get; set; } = false;
public Margins Margins { get; set; }
}

View File

@@ -1,6 +1,6 @@
using System;
using System.Globalization;
using Quobject.EngineIoClientDotNet.ComponentEmitter;
using System.Threading.Tasks;
namespace ElectronNET.API
{
@@ -10,12 +10,11 @@ namespace ElectronNET.API
internal class Events
{
private static Events _events;
private static object _syncRoot = new object();
private TextInfo _ti = new CultureInfo("en-US", false).TextInfo;
private static readonly object SyncRoot = new();
private readonly TextInfo _textInfo = new CultureInfo("en-US", false).TextInfo;
private Events()
{
}
{}
public static Events Instance
{
@@ -23,7 +22,7 @@ namespace ElectronNET.API
{
if (_events == null)
{
lock (_syncRoot)
lock (SyncRoot)
{
if (_events == null)
{
@@ -41,32 +40,24 @@ namespace ElectronNET.API
/// </summary>
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
/// <param name="eventName">The name of the event</param>
/// <param name="fn">The event handler</param>
public void On(string moduleName, string eventName, Action fn)
=> On(moduleName, eventName, new ListenerImpl(fn));
/// <param name="action">The event handler</param>
public void On(string moduleName, string eventName, Action action)
=> On(moduleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped electron event.
/// </summary>
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
/// <param name="eventName">The name of the event</param>
/// <param name="fn">The event handler</param>
public void On(string moduleName, string eventName, Action<object> fn)
=> On(moduleName, eventName, new ListenerImpl(fn));
/// <summary>
/// Subscribe to an unmapped electron event.
/// </summary>
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
/// <param name="eventName">The name of the event</param>
/// <param name="fn">The event handler</param>
private void On(string moduleName, string eventName, IListener fn)
/// <param name="action">The event handler</param>
public async Task On<T>(string moduleName, string eventName, Action<T> action)
{
var listener = $"{moduleName}{_ti.ToTitleCase(eventName)}Completed";
var listener = $"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed";
var subscriber = $"register-{moduleName}-on-event";
BridgeConnector.Socket.On(listener, fn);
BridgeConnector.Socket.Emit(subscriber, eventName, listener);
BridgeConnector.Socket.On(listener, action);
await BridgeConnector.Socket.Emit(subscriber, eventName, listener);
}
/// <summary>
@@ -75,30 +66,22 @@ namespace ElectronNET.API
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
/// <param name="eventName">The name of the event</param>
/// <param name="fn">The event handler</param>
public void Once(string moduleName, string eventName, Action fn)
=> Once(moduleName, eventName, new ListenerImpl(fn));
public void Once(string moduleName, string eventName, Action action)
=> Once(moduleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped electron event.
/// </summary>
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
/// <param name="eventName">The name of the event</param>
/// <param name="fn">The event handler</param>
public void Once(string moduleName, string eventName, Action<object> fn)
=> Once(moduleName, eventName, new ListenerImpl(fn));
/// <summary>
/// Subscribe to an unmapped electron event.
/// </summary>
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
/// <param name="eventName">The name of the event</param>
/// <param name="fn">The event handler</param>
private void Once(string moduleName, string eventName, IListener fn)
/// <param name="action">The event handler</param>
public async Task Once<T>(string moduleName, string eventName, Action<T> action)
{
var listener = $"{moduleName}{_ti.ToTitleCase(eventName)}Completed";
var listener = $"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed";
var subscriber = $"register-{moduleName}-once-event";
BridgeConnector.Socket.Once(listener, fn);
BridgeConnector.Socket.Emit(subscriber, eventName, listener);
BridgeConnector.Socket.Once(listener, action);
await BridgeConnector.Socket.Emit(subscriber, eventName, listener);
}
}

View File

@@ -0,0 +1,3 @@
// Global using directives
global using System.Web;

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ElectronNET.API
{
@@ -43,9 +44,9 @@ namespace ElectronNET.API
/// </summary>
/// <param name="channel">Channelname.</param>
/// <param name="listener">Callback Method.</param>
public void On(string channel, Action<object> listener)
public async Task On(string channel, Action<object> listener)
{
BridgeConnector.Socket.Emit("registerIpcMainChannel", channel);
await BridgeConnector.Socket.Emit("registerIpcMainChannel", channel);
BridgeConnector.Socket.Off(channel);
BridgeConnector.Socket.On(channel, (args) =>
{

View File

@@ -0,0 +1,93 @@
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using SocketIOClient;
using SocketIOClient.Newtonsoft.Json;
namespace ElectronNET.API;
internal class SocketIoFacade
{
private readonly SocketIO _socket;
public SocketIoFacade(string uri)
{
_socket = new SocketIO(uri);
var jsonSerializer = new NewtonsoftJsonSerializer(new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
});
_socket.JsonSerializer = jsonSerializer;
}
public void Connect()
{
_socket.OnError += (sender, e) =>
{
Console.WriteLine($"BridgeConnector Error: {sender} {e}");
};
_socket.OnConnected += (_, _) =>
{
Console.WriteLine("BridgeConnector connected!");
};
_socket.OnDisconnected += (_, _) =>
{
Console.WriteLine("BridgeConnector disconnected!");
};
_socket.ConnectAsync().GetAwaiter().GetResult();
}
public void On(string eventName, Action action)
{
_socket.On(eventName, response =>
{
Task.Run(action);
});
}
public void On<T>(string eventName, Action<T> action)
{
_socket.On(eventName, response =>
{
var value = response.GetValue<T>();
Task.Run(() => action(value));
});
}
// TODO: Remove this method when SocketIoClient supports object deserialization
public void On(string eventName, Action<object> action)
{
_socket.On(eventName, response =>
{
var value = response.GetValue<object>();
Console.WriteLine($"Called Event {eventName} - data {value}");
Task.Run(() => action(value));
});
}
public void Once<T>(string eventName, Action<T> action)
{
_socket.On(eventName, (socketIoResponse) =>
{
_socket.Off(eventName);
Task.Run(() => action(socketIoResponse.GetValue<T>()));
});
}
public void Off(string eventName)
{
_socket.Off(eventName);
}
public async Task Emit(string eventName, params object[] args)
{
await _socket.EmitAsync(eventName, args);
}
}

View File

@@ -23,7 +23,7 @@ namespace ElectronNET.API
{
if (_click == null)
{
BridgeConnector.Socket.On("tray-click-event" + GetHashCode(), (result) =>
BridgeConnector.Socket.On<dynamic>("tray-click-event" + GetHashCode(), (result) =>
{
var args = ((JArray)result).ToObject<object[]>();
var trayClickEventArgs = ((JObject)args[0]).ToObject<TrayClickEventArgs>();
@@ -55,7 +55,7 @@ namespace ElectronNET.API
{
if (_rightClick == null)
{
BridgeConnector.Socket.On("tray-right-click-event" + GetHashCode(), (result) =>
BridgeConnector.Socket.On<dynamic>("tray-right-click-event" + GetHashCode(), (result) =>
{
var args = ((JArray)result).ToObject<object[]>();
var trayClickEventArgs = ((JObject)args[0]).ToObject<TrayClickEventArgs>();
@@ -87,7 +87,7 @@ namespace ElectronNET.API
{
if (_doubleClick == null)
{
BridgeConnector.Socket.On("tray-double-click-event" + GetHashCode(), (result) =>
BridgeConnector.Socket.On<dynamic>("tray-double-click-event" + GetHashCode(), (result) =>
{
var args = ((JArray)result).ToObject<object[]>();
var trayClickEventArgs = ((JObject)args[0]).ToObject<TrayClickEventArgs>();
@@ -182,7 +182,7 @@ namespace ElectronNET.API
{
_balloonClosed();
});
BridgeConnector.Socket.Emit("register-tray-balloon-closed", GetHashCode());
}
_balloonClosed += value;
@@ -201,7 +201,7 @@ namespace ElectronNET.API
// TODO: Implement macOS Events
private static Tray _tray;
private static object _syncRoot = new object();
private static readonly object _syncRoot = new();
internal Tray() { }
@@ -230,17 +230,18 @@ namespace ElectronNET.API
/// <value>
/// The menu items.
/// </value>
public IReadOnlyCollection<MenuItem> MenuItems { get { return _items.AsReadOnly(); } }
private List<MenuItem> _items = new List<MenuItem>();
public IReadOnlyCollection<MenuItem> MenuItems => _items.AsReadOnly();
private readonly List<MenuItem> _items = new();
/// <summary>
/// Shows the Traybar.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="menuItem">The menu item.</param>
public void Show(string image, MenuItem menuItem)
public async Task Show(string image, MenuItem menuItem)
{
Show(image, new MenuItem[] { menuItem });
await Show(image, new MenuItem[] { menuItem });
}
/// <summary>
@@ -248,17 +249,17 @@ namespace ElectronNET.API
/// </summary>
/// <param name="image">The image.</param>
/// <param name="menuItems">The menu items.</param>
public void Show(string image, MenuItem[] menuItems)
public async Task Show(string image, MenuItem[] menuItems)
{
menuItems.AddMenuItemsId();
BridgeConnector.Socket.Emit("create-tray", image, JArray.FromObject(menuItems, _jsonSerializer));
await BridgeConnector.Socket.Emit("create-tray", image, JArray.FromObject(menuItems, _jsonSerializer));
_items.Clear();
_items.AddRange(menuItems);
BridgeConnector.Socket.Off("trayMenuItemClicked");
BridgeConnector.Socket.On("trayMenuItemClicked", (id) =>
BridgeConnector.Socket.On<string>("trayMenuItemClicked", (id) =>
{
MenuItem menuItem = _items.GetMenuItem(id.ToString());
MenuItem menuItem = _items.GetMenuItem(id);
menuItem?.Click();
});
}
@@ -267,17 +268,17 @@ namespace ElectronNET.API
/// Shows the Traybar (empty).
/// </summary>
/// <param name="image">The image.</param>
public void Show(string image)
public async Task Show(string image)
{
BridgeConnector.Socket.Emit("create-tray", image);
await BridgeConnector.Socket.Emit("create-tray", image);
}
/// <summary>
/// Destroys the tray icon immediately.
/// </summary>
public void Destroy()
public async Task Destroy()
{
BridgeConnector.Socket.Emit("tray-destroy");
await BridgeConnector.Socket.Emit("tray-destroy");
_items.Clear();
}
@@ -285,68 +286,68 @@ namespace ElectronNET.API
/// Sets the image associated with this tray icon.
/// </summary>
/// <param name="image"></param>
public void SetImage(string image)
public async Task SetImage(string image)
{
BridgeConnector.Socket.Emit("tray-setImage", image);
await BridgeConnector.Socket.Emit("tray-setImage", image);
}
/// <summary>
/// Sets the image associated with this tray icon when pressed on macOS.
/// </summary>
/// <param name="image"></param>
public void SetPressedImage(string image)
public async Task SetPressedImage(string image)
{
BridgeConnector.Socket.Emit("tray-setPressedImage", image);
await BridgeConnector.Socket.Emit("tray-setPressedImage", image);
}
/// <summary>
/// Sets the hover text for this tray icon.
/// </summary>
/// <param name="toolTip"></param>
public void SetToolTip(string toolTip)
public async Task SetToolTip(string toolTip)
{
BridgeConnector.Socket.Emit("tray-setToolTip", toolTip);
await BridgeConnector.Socket.Emit("tray-setToolTip", toolTip);
}
/// <summary>
/// macOS: Sets the title displayed aside of the tray icon in the status bar.
/// </summary>
/// <param name="title"></param>
public void SetTitle(string title)
public async Task SetTitle(string title)
{
BridgeConnector.Socket.Emit("tray-setTitle", title);
await BridgeConnector.Socket.Emit("tray-setTitle", title);
}
/// <summary>
/// Windows: Displays a tray balloon.
/// </summary>
/// <param name="options"></param>
public void DisplayBalloon(DisplayBalloonOptions options)
public async Task DisplayBalloon(DisplayBalloonOptions options)
{
BridgeConnector.Socket.Emit("tray-displayBalloon", JObject.FromObject(options, _jsonSerializer));
await BridgeConnector.Socket.Emit("tray-displayBalloon", JObject.FromObject(options, _jsonSerializer));
}
/// <summary>
/// Whether the tray icon is destroyed.
/// </summary>
/// <returns></returns>
public Task<bool> IsDestroyedAsync()
public async Task<bool> IsDestroyedAsync()
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("tray-isDestroyedCompleted", (isDestroyed) =>
BridgeConnector.Socket.On<bool>("tray-isDestroyedCompleted", (isDestroyed) =>
{
BridgeConnector.Socket.Off("tray-isDestroyedCompleted");
taskCompletionSource.SetResult((bool)isDestroyed);
taskCompletionSource.SetResult(isDestroyed);
});
BridgeConnector.Socket.Emit("tray-isDestroyed");
await BridgeConnector.Socket.Emit("tray-isDestroyed");
return taskCompletionSource.Task;
return await taskCompletionSource.Task;
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
private readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
@@ -357,29 +358,29 @@ namespace ElectronNET.API
/// Subscribe to an unmapped event on the <see cref="Tray"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void On(string eventName, Action fn)
=> Events.Instance.On(ModuleName, eventName, fn);
/// <param name="action">The handler</param>
public void On(string eventName, Action action)
=> Events.Instance.On(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void On(string eventName, Action<object> fn)
=> Events.Instance.On(ModuleName, eventName, fn);
/// <param name="action">The handler</param>
public async Task On<T>(string eventName, Action<T> action)
=> await Events.Instance.On(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void Once(string eventName, Action fn)
=> Events.Instance.Once(ModuleName, eventName, fn);
/// <param name="action">The handler</param>
public void Once(string eventName, Action action)
=> Events.Instance.Once(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
/// <param name="fn">The handler</param>
public void Once(string eventName, Action<object> fn)
=> Events.Instance.Once(ModuleName, eventName, fn);
/// <param name="action">The handler</param>
public async Task Once<T>(string eventName, Action<T> action)
=> await Events.Instance.Once(ModuleName, eventName, action);
}
}

View File

@@ -5,276 +5,305 @@ using Newtonsoft.Json.Serialization;
using System;
using System.Threading.Tasks;
namespace ElectronNET.API
namespace ElectronNET.API;
/// <summary>
/// Render and control web pages.
/// </summary>
public class WebContents
{
/// <summary>
/// Render and control web pages.
/// Gets the identifier.
/// </summary>
public class WebContents
/// <value>
/// The identifier.
/// </value>
public int Id { get; private set; }
/// <summary>
/// Manage browser sessions, cookies, cache, proxy settings, etc.
/// </summary>
public Session Session { get; internal set; }
/// <summary>
/// Emitted when the renderer process crashes or is killed.
/// </summary>
public event Action<bool> OnCrashed
{
/// <summary>
/// Gets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
public int Id { get; private set; }
/// <summary>
/// Manage browser sessions, cookies, cache, proxy settings, etc.
/// </summary>
public Session Session { get; internal set; }
/// <summary>
/// Emitted when the renderer process crashes or is killed.
/// </summary>
public event Action<bool> OnCrashed
add
{
add
if (_crashed == null)
{
if (_crashed == null)
BridgeConnector.Socket.On("webContents-crashed" + Id, (killed) =>
{
BridgeConnector.Socket.On("webContents-crashed" + Id, (killed) =>
{
_crashed((bool)killed);
});
_crashed((bool)killed);
});
BridgeConnector.Socket.Emit("register-webContents-crashed", Id);
}
_crashed += value;
}
remove
{
_crashed -= value;
if (_crashed == null)
BridgeConnector.Socket.Off("webContents-crashed" + Id);
BridgeConnector.Socket.Emit("register-webContents-crashed", Id);
}
_crashed += value;
}
private event Action<bool> _crashed;
/// <summary>
/// Emitted when the navigation is done, i.e. the spinner of the tab has
/// stopped spinning, and the onload event was dispatched.
/// </summary>
public event Action OnDidFinishLoad
remove
{
add
{
if (_didFinishLoad == null)
{
BridgeConnector.Socket.On("webContents-didFinishLoad" + Id, () =>
{
_didFinishLoad();
});
_crashed -= value;
BridgeConnector.Socket.Emit("register-webContents-didFinishLoad", Id);
}
_didFinishLoad += value;
}
remove
{
_didFinishLoad -= value;
if (_didFinishLoad == null)
BridgeConnector.Socket.Off("webContents-didFinishLoad" + Id);
}
if (_crashed == null)
BridgeConnector.Socket.Off("webContents-crashed" + Id);
}
private event Action _didFinishLoad;
internal WebContents(int id)
{
Id = id;
Session = new Session(id);
}
/// <summary>
/// Opens the devtools.
/// </summary>
public void OpenDevTools()
{
BridgeConnector.Socket.Emit("webContentsOpenDevTools", Id);
}
/// <summary>
/// Opens the devtools.
/// </summary>
/// <param name="openDevToolsOptions"></param>
public void OpenDevTools(OpenDevToolsOptions openDevToolsOptions)
{
BridgeConnector.Socket.Emit("webContentsOpenDevTools", Id, JObject.FromObject(openDevToolsOptions, _jsonSerializer));
}
/// <summary>
/// Get system printers.
/// </summary>
/// <returns>printers</returns>
public Task<PrinterInfo[]> GetPrintersAsync()
{
var taskCompletionSource = new TaskCompletionSource<PrinterInfo[]>();
BridgeConnector.Socket.On("webContents-getPrinters-completed", (printers) =>
{
BridgeConnector.Socket.Off("webContents-getPrinters-completed");
taskCompletionSource.SetResult(((Newtonsoft.Json.Linq.JArray)printers).ToObject<PrinterInfo[]>());
});
BridgeConnector.Socket.Emit("webContents-getPrinters", Id);
return taskCompletionSource.Task;
}
/// <summary>
/// Prints window's web page.
/// </summary>
/// <param name="options"></param>
/// <returns>success</returns>
public Task<bool> PrintAsync(PrintOptions options = null)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("webContents-print-completed", (success) =>
{
BridgeConnector.Socket.Off("webContents-print-completed");
taskCompletionSource.SetResult((bool)success);
});
if(options == null)
{
BridgeConnector.Socket.Emit("webContents-print", Id, "");
}
else
{
BridgeConnector.Socket.Emit("webContents-print", Id, JObject.FromObject(options, _jsonSerializer));
}
return taskCompletionSource.Task;
}
/// <summary>
/// Prints window's web page as PDF with Chromium's preview printing custom
/// settings.The landscape will be ignored if @page CSS at-rule is used in the web page.
/// By default, an empty options will be regarded as: Use page-break-before: always;
/// CSS style to force to print to a new page.
/// </summary>
/// <param name="path"></param>
/// <param name="options"></param>
/// <returns>success</returns>
public Task<bool> PrintToPDFAsync(string path, PrintToPDFOptions options = null)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("webContents-printToPDF-completed", (success) =>
{
BridgeConnector.Socket.Off("webContents-printToPDF-completed");
taskCompletionSource.SetResult((bool)success);
});
if(options == null)
{
BridgeConnector.Socket.Emit("webContents-printToPDF", Id, "", path);
}
else
{
BridgeConnector.Socket.Emit("webContents-printToPDF", Id, JObject.FromObject(options, _jsonSerializer), path);
}
return taskCompletionSource.Task;
}
/// <summary>
/// Is used to get the Url of the loaded page.
/// It's usefull if a web-server redirects you and you need to know where it redirects. For instance, It's useful in case of Implicit Authorization.
/// </summary>
/// <returns>URL of the loaded page</returns>
public Task<string> GetUrl()
{
var taskCompletionSource = new TaskCompletionSource<string>();
var eventString = "webContents-getUrl" + Id;
BridgeConnector.Socket.On(eventString, (url) =>
{
BridgeConnector.Socket.Off(eventString);
taskCompletionSource.SetResult((string)url);
});
BridgeConnector.Socket.Emit("webContents-getUrl", Id);
return taskCompletionSource.Task;
}
/// <summary>
/// The async method will resolve when the page has finished loading,
/// and rejects if the page fails to load.
///
/// A noop rejection handler is already attached, which avoids unhandled rejection
/// errors.
///
/// Loads the `url` in the window. The `url` must contain the protocol prefix, e.g.
/// the `http://` or `file://`. If the load should bypass http cache then use the
/// `pragma` header to achieve it.
/// </summary>
/// <param name="url"></param>
public Task LoadURLAsync(string url)
{
return LoadURLAsync(url, new LoadURLOptions());
}
/// <summary>
/// The async method will resolve when the page has finished loading,
/// and rejects if the page fails to load.
///
/// A noop rejection handler is already attached, which avoids unhandled rejection
/// errors.
///
/// Loads the `url` in the window. The `url` must contain the protocol prefix, e.g.
/// the `http://` or `file://`. If the load should bypass http cache then use the
/// `pragma` header to achieve it.
/// </summary>
/// <param name="url"></param>
/// <param name="options"></param>
public Task LoadURLAsync(string url, LoadURLOptions options)
{
var taskCompletionSource = new TaskCompletionSource<object>();
BridgeConnector.Socket.On("webContents-loadURL-complete" + Id, () =>
{
BridgeConnector.Socket.Off("webContents-loadURL-complete" + Id);
BridgeConnector.Socket.Off("webContents-loadURL-error" + Id);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.On("webContents-loadURL-error" + Id, (error) =>
{
BridgeConnector.Socket.Off("webContents-loadURL-error" + Id);
taskCompletionSource.SetException(new InvalidOperationException(error.ToString()));
});
BridgeConnector.Socket.Emit("webContents-loadURL", Id, url, JObject.FromObject(options, _jsonSerializer));
return taskCompletionSource.Task;
}
/// <summary>
/// Inserts CSS into the web page.
/// See: https://www.electronjs.org/docs/api/web-contents#contentsinsertcsscss-options
/// Works for both BrowserWindows and BrowserViews.
/// </summary>
/// <param name="isBrowserWindow">Whether the webContents belong to a BrowserWindow or not (the other option is a BrowserView)</param>
/// <param name="path">Absolute path to the CSS file location</param>
public void InsertCSS(bool isBrowserWindow, string path)
{
BridgeConnector.Socket.Emit("webContents-insertCSS", Id, isBrowserWindow, path);
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}
private event Action<bool> _crashed;
/// <summary>
/// Emitted when the navigation is done, i.e. the spinner of the tab has
/// stopped spinning, and the onload event was dispatched.
/// </summary>
public event Action OnDidFinishLoad
{
add
{
if (_didFinishLoad == null)
{
BridgeConnector.Socket.On("webContents-didFinishLoad" + Id, () =>
{
_didFinishLoad();
});
BridgeConnector.Socket.Emit("register-webContents-didFinishLoad", Id);
}
_didFinishLoad += value;
}
remove
{
_didFinishLoad -= value;
if (_didFinishLoad == null)
BridgeConnector.Socket.Off("webContents-didFinishLoad" + Id);
}
}
private event Action _didFinishLoad;
/// <summary>
/// Emitted when an input event is sent to the WebContents.
/// </summary>
public event Action<InputEvent> InputEvent
{
add
{
if (_inputEvent == null)
{
BridgeConnector.Socket.On("webContents-input-event" + Id, (eventArgs) =>
{
var inputEvent = ((JObject)eventArgs).ToObject<InputEvent>();
_inputEvent(inputEvent);
});
BridgeConnector.Socket.Emit("register-webContents-input-event", Id);
}
_inputEvent += value;
}
remove
{
_inputEvent -= value;
if (_inputEvent == null)
BridgeConnector.Socket.Off("webContents-input-event" + Id);
}
}
private event Action<InputEvent> _inputEvent;
internal WebContents(int id)
{
Id = id;
Session = new Session(id);
}
/// <summary>
/// Opens the devtools.
/// </summary>
public void OpenDevTools()
{
BridgeConnector.Socket.Emit("webContentsOpenDevTools", Id);
}
/// <summary>
/// Opens the devtools.
/// </summary>
/// <param name="openDevToolsOptions"></param>
public void OpenDevTools(OpenDevToolsOptions openDevToolsOptions)
{
BridgeConnector.Socket.Emit("webContentsOpenDevTools", Id, JObject.FromObject(openDevToolsOptions, _jsonSerializer));
}
/// <summary>
/// Get system printers.
/// </summary>
/// <returns>printers</returns>
public Task<PrinterInfo[]> GetPrintersAsync()
{
var taskCompletionSource = new TaskCompletionSource<PrinterInfo[]>();
BridgeConnector.Socket.On("webContents-getPrinters-completed", (printers) =>
{
BridgeConnector.Socket.Off("webContents-getPrinters-completed");
taskCompletionSource.SetResult(((Newtonsoft.Json.Linq.JArray)printers).ToObject<PrinterInfo[]>());
});
BridgeConnector.Socket.Emit("webContents-getPrinters", Id);
return taskCompletionSource.Task;
}
/// <summary>
/// Prints window's web page.
/// </summary>
/// <param name="options"></param>
/// <returns>success</returns>
public Task<bool> PrintAsync(PrintOptions options = null)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("webContents-print-completed", (success) =>
{
BridgeConnector.Socket.Off("webContents-print-completed");
taskCompletionSource.SetResult((bool)success);
});
if(options == null)
{
BridgeConnector.Socket.Emit("webContents-print", Id, "");
}
else
{
BridgeConnector.Socket.Emit("webContents-print", Id, JObject.FromObject(options, _jsonSerializer));
}
return taskCompletionSource.Task;
}
/// <summary>
/// Prints window's web page as PDF with Chromium's preview printing custom
/// settings.The landscape will be ignored if @page CSS at-rule is used in the web page.
/// By default, an empty options will be regarded as: Use page-break-before: always;
/// CSS style to force to print to a new page.
/// </summary>
/// <param name="path"></param>
/// <param name="options"></param>
/// <returns>success</returns>
public Task<bool> PrintToPDFAsync(string path, PrintToPDFOptions options = null)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
BridgeConnector.Socket.On("webContents-printToPDF-completed", (success) =>
{
BridgeConnector.Socket.Off("webContents-printToPDF-completed");
taskCompletionSource.SetResult((bool)success);
});
if(options == null)
{
BridgeConnector.Socket.Emit("webContents-printToPDF", Id, "", path);
}
else
{
BridgeConnector.Socket.Emit("webContents-printToPDF", Id, JObject.FromObject(options, _jsonSerializer), path);
}
return taskCompletionSource.Task;
}
/// <summary>
/// Is used to get the Url of the loaded page.
/// It's usefull if a web-server redirects you and you need to know where it redirects. For instance, It's useful in case of Implicit Authorization.
/// </summary>
/// <returns>URL of the loaded page</returns>
public Task<string> GetUrl()
{
var taskCompletionSource = new TaskCompletionSource<string>();
var eventString = "webContents-getUrl" + Id;
BridgeConnector.Socket.On(eventString, (url) =>
{
BridgeConnector.Socket.Off(eventString);
taskCompletionSource.SetResult((string)url);
});
BridgeConnector.Socket.Emit("webContents-getUrl", Id);
return taskCompletionSource.Task;
}
/// <summary>
/// The async method will resolve when the page has finished loading,
/// and rejects if the page fails to load.
///
/// A noop rejection handler is already attached, which avoids unhandled rejection
/// errors.
///
/// Loads the `url` in the window. The `url` must contain the protocol prefix, e.g.
/// the `http://` or `file://`. If the load should bypass http cache then use the
/// `pragma` header to achieve it.
/// </summary>
/// <param name="url"></param>
public Task LoadURLAsync(string url)
{
return LoadURLAsync(url, new LoadURLOptions());
}
/// <summary>
/// The async method will resolve when the page has finished loading,
/// and rejects if the page fails to load.
///
/// A noop rejection handler is already attached, which avoids unhandled rejection
/// errors.
///
/// Loads the `url` in the window. The `url` must contain the protocol prefix, e.g.
/// the `http://` or `file://`. If the load should bypass http cache then use the
/// `pragma` header to achieve it.
/// </summary>
/// <param name="url"></param>
/// <param name="options"></param>
public Task LoadURLAsync(string url, LoadURLOptions options)
{
var taskCompletionSource = new TaskCompletionSource<object>();
BridgeConnector.Socket.On("webContents-loadURL-complete" + Id, () =>
{
BridgeConnector.Socket.Off("webContents-loadURL-complete" + Id);
BridgeConnector.Socket.Off("webContents-loadURL-error" + Id);
taskCompletionSource.SetResult(null);
});
BridgeConnector.Socket.On("webContents-loadURL-error" + Id, (error) =>
{
BridgeConnector.Socket.Off("webContents-loadURL-error" + Id);
taskCompletionSource.SetException(new InvalidOperationException(error.ToString()));
});
BridgeConnector.Socket.Emit("webContents-loadURL", Id, url, JObject.FromObject(options, _jsonSerializer));
return taskCompletionSource.Task;
}
/// <summary>
/// Inserts CSS into the web page.
/// See: https://www.electronjs.org/docs/api/web-contents#contentsinsertcsscss-options
/// Works for both BrowserWindows and BrowserViews.
/// </summary>
/// <param name="isBrowserWindow">Whether the webContents belong to a BrowserWindow or not (the other option is a BrowserView)</param>
/// <param name="path">Absolute path to the CSS file location</param>
public void InsertCSS(bool isBrowserWindow, string path)
{
BridgeConnector.Socket.Emit("webContents-insertCSS", Id, isBrowserWindow, path);
}
private readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
}

View File

@@ -5,6 +5,7 @@ using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
@@ -16,7 +17,7 @@ namespace ElectronNET.API
public sealed class WindowManager
{
private static WindowManager _windowManager;
private static object _syncRoot = new object();
private static readonly object SyncRoot = new();
internal WindowManager() { }
@@ -26,7 +27,7 @@ namespace ElectronNET.API
{
if (_windowManager == null)
{
lock (_syncRoot)
lock (SyncRoot)
{
if (_windowManager == null)
{
@@ -47,7 +48,7 @@ namespace ElectronNET.API
/// </value>
public bool IsQuitOnWindowAllClosed
{
get { return _isQuitOnWindowAllClosed; }
get => _isQuitOnWindowAllClosed;
set
{
BridgeConnector.Socket.Emit("quit-app-window-all-closed-event", value);
@@ -62,8 +63,9 @@ namespace ElectronNET.API
/// <value>
/// The browser windows.
/// </value>
public IReadOnlyCollection<BrowserWindow> BrowserWindows { get { return _browserWindows.AsReadOnly(); } }
private List<BrowserWindow> _browserWindows = new List<BrowserWindow>();
public IReadOnlyCollection<BrowserWindow> BrowserWindows => _browserWindows.AsReadOnly();
private readonly List<BrowserWindow> _browserWindows = new();
/// <summary>
/// Gets the browser views.
@@ -71,8 +73,9 @@ namespace ElectronNET.API
/// <value>
/// The browser view.
/// </value>
public IReadOnlyCollection<BrowserView> BrowserViews { get { return _browserViews.AsReadOnly(); } }
private List<BrowserView> _browserViews = new List<BrowserView>();
public IReadOnlyCollection<BrowserView> BrowserViews => _browserViews.AsReadOnly();
private readonly List<BrowserView> _browserViews = new();
/// <summary>
/// Creates the window asynchronous.
@@ -90,7 +93,7 @@ namespace ElectronNET.API
/// <param name="options">The options.</param>
/// <param name="loadUrl">The load URL.</param>
/// <returns></returns>
public Task<BrowserWindow> CreateWindowAsync(BrowserWindowOptions options, string loadUrl = "http://localhost")
public async Task<BrowserWindow> CreateWindowAsync(BrowserWindowOptions options, string loadUrl = "http://localhost")
{
var taskCompletionSource = new TaskCompletionSource<BrowserWindow>();
@@ -98,16 +101,18 @@ namespace ElectronNET.API
{
BridgeConnector.Socket.Off("BrowserWindowCreated");
string windowId = id.ToString();
BrowserWindow browserWindow = new BrowserWindow(int.Parse(windowId));
var browserWindowId = int.Parse(id.ToString()!);
var browserWindow = new BrowserWindow(browserWindowId);
_browserWindows.Add(browserWindow);
taskCompletionSource.SetResult(browserWindow);
});
BridgeConnector.Socket.Off("BrowserWindowClosed");
BridgeConnector.Socket.On("BrowserWindowClosed", (ids) =>
BridgeConnector.Socket.On<object>("BrowserWindowClosed", (ids) =>
{
BridgeConnector.Socket.Off("BrowserWindowClosed");
var browserWindowIds = ((JArray)ids).ToObject<int[]>();
for (int index = 0; index < _browserWindows.Count; index++)
@@ -126,10 +131,10 @@ namespace ElectronNET.API
// Workaround Windows 10 / Electron Bug
// https://github.com/electron/electron/issues/4045
if (isWindows10())
if (IsWindows10())
{
options.Width = options.Width + 14;
options.Height = options.Height + 7;
options.Width += 14;
options.Height += 7;
}
if (options.X == -1 && options.Y == -1)
@@ -137,15 +142,15 @@ namespace ElectronNET.API
options.X = 0;
options.Y = 0;
BridgeConnector.Socket.Emit("createBrowserWindow", JObject.FromObject(options, _jsonSerializer), loadUrl);
await BridgeConnector.Socket.Emit("createBrowserWindow", JObject.FromObject(options, _jsonSerializer), loadUrl);
}
else
{
// Workaround Windows 10 / Electron Bug
// https://github.com/electron/electron/issues/4045
if (isWindows10())
if (IsWindows10())
{
options.X = options.X - 7;
options.X -= 7;
}
var ownjsonSerializer = new JsonSerializer()
@@ -153,13 +158,13 @@ namespace ElectronNET.API
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
BridgeConnector.Socket.Emit("createBrowserWindow", JObject.FromObject(options, ownjsonSerializer), loadUrl);
await BridgeConnector.Socket.Emit("createBrowserWindow", JObject.FromObject(options, ownjsonSerializer), loadUrl);
}
return taskCompletionSource.Task;
return await taskCompletionSource.Task;
}
private bool isWindows10()
private bool IsWindows10()
{
return RuntimeInformation.OSDescription.Contains("Windows 10");
}
@@ -182,7 +187,7 @@ namespace ElectronNET.API
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
public Task<BrowserView> CreateBrowserViewAsync(BrowserViewConstructorOptions options)
public async Task<BrowserView> CreateBrowserViewAsync(BrowserViewConstructorOptions options)
{
var taskCompletionSource = new TaskCompletionSource<BrowserView>();
@@ -203,12 +208,12 @@ namespace ElectronNET.API
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
BridgeConnector.Socket.Emit("createBrowserView", JObject.FromObject(options, ownjsonSerializer));
await BridgeConnector.Socket.Emit("createBrowserView", JObject.FromObject(options, ownjsonSerializer));
return taskCompletionSource.Task;
return await taskCompletionSource.Task;
}
private JsonSerializer _jsonSerializer = new JsonSerializer()
private readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,

View File

@@ -10,11 +10,20 @@ namespace ElectronNET.CLI.Commands.Actions
EmbeddedFileHelper.DeployEmbeddedFile(tempPath, "package.json");
EmbeddedFileHelper.DeployEmbeddedFile(tempPath, "build-helper.js");
string vscodeFolder = Path.Combine(tempPath, ".vscode");
if (Directory.Exists(vscodeFolder) == false)
{
Directory.CreateDirectory(vscodeFolder);
}
EmbeddedFileHelper.DeployEmbeddedFile(vscodeFolder, "launch.json", ".vscode.");
EmbeddedFileHelper.DeployEmbeddedFile(vscodeFolder, "tasks.json", ".vscode.");
string hostApiFolder = Path.Combine(tempPath, "api");
if (Directory.Exists(hostApiFolder) == false)
{
Directory.CreateDirectory(hostApiFolder);
}
EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "ipc.js", "api.");
EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "app.js", "api.");
EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "browserWindows.js", "api.");

View File

@@ -198,7 +198,7 @@ namespace ElectronNET.CLI.Commands
: $"node build-helper.js {manifestFileName} {version}", tempPath);
Console.WriteLine($"Package Electron App for Platform {platformInfo.ElectronPackerPlatform}...");
ProcessHelper.CmdExecute($"npx electron-builder --config=./bin/electron-builder.json --{platformInfo.ElectronPackerPlatform} --{electronArch} -c.electronVersion=13.1.5 {electronParams}", tempPath);
ProcessHelper.CmdExecute($"npx electron-builder --config=./bin/electron-builder.json --{platformInfo.ElectronPackerPlatform} --{electronArch} -c.electronVersion=23.2.0 {electronParams}", tempPath);
Console.WriteLine("... done");

View File

@@ -1,19 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>dotnet-electronize</AssemblyName>
<ToolCommandName>electronize</ToolCommandName>
<PackageType>DotnetCliTool</PackageType>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageOutputPath>..\artifacts</PackageOutputPath>
<PackageId>ElectronNET.CLI</PackageId>
<!-- Version 99 is just set for local development stuff to avoid a conflict with "real" packages on NuGet.org -->
<Version>99.0.0.0</Version>
<Authors>Gregor Biswanger, Robert Muehsig</Authors>
<Authors>Gregor Biswanger, Florian Rappl</Authors>
<Product>Electron.NET</Product>
<Company />
<Description>
@@ -29,22 +26,19 @@
<PackageReleaseNotes>Changelog: https://github.com/ElectronNET/Electron.NET/blob/master/Changelog.md</PackageReleaseNotes>
<PackageIcon>PackageIcon.png</PackageIcon>
<PackAsTool>true</PackAsTool>
<StartupObject></StartupObject>
<StartupObject>
</StartupObject>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<None Remove="ElectronHost\package-lock.json" />
<None Remove="ElectronHost\package.json" />
</ItemGroup>
<ItemGroup>
<None Include="PackageIcon.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\ElectronNET.Host\electron.manifest.json" Link="ElectronHost\electron.manifest.json" />
<EmbeddedResource Include="..\ElectronNET.Host\package.json" Link="ElectronHost\package.json" />
@@ -74,13 +68,17 @@
<EmbeddedResource Include="..\ElectronNET.Host\api\browserView.js" Link="ElectronHost\api\browserView.js" />
<EmbeddedResource Include="..\ElectronNET.Host\api\powerMonitor.js" Link="ElectronHost\api\powerMonitor.js" />
<EmbeddedResource Include="..\ElectronNET.Host\api\nativeTheme.js" Link="ElectronHost\api\nativeTheme.js" />
<EmbeddedResource Include="..\ElectronNET.Host\.vscode\launch.json" Link="ElectronHost\.vscode\launch.json" />
<EmbeddedResource Include="..\ElectronNET.Host\.vscode\tasks.json" Link="ElectronHost\.vscode\tasks.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.410601">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(OS)' == 'Windows_NT'">
<Exec Command="$(ProjectDir)devCleanup.cmd" IgnoreExitCode="true" />
@@ -88,4 +86,4 @@
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(OS)' != 'Windows_NT'">
<Exec Command="$(ProjectDir)devCleanup.sh" IgnoreExitCode="true" />
</Target>
</Project>
</Project>

View File

@@ -1,5 +1,7 @@
import { Socket } from 'socket.io';
export class Connector {
constructor(private socket: SocketIO.Socket,
constructor(private socket: Socket,
// @ts-ignore
public app: Electron.App) { }

View File

@@ -1,9 +1,10 @@
// @ts-ignore
import * as Electron from "electron";
import { Socket } from "socket.io";
import { Connector } from "./connector";
export class HookService extends Connector {
constructor(socket: SocketIO.Socket, public app: Electron.App) {
constructor(socket: Socket, public app: Electron.App) {
super(socket, app);
}

View File

@@ -0,0 +1,441 @@
{
"name": "electron-host-hook",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "electron-host-hook",
"version": "1.0.0",
"license": "MIT",
"devDependencies": {
"socket.io": "^4.6.1",
"typescript": "^5.0.2"
}
},
"node_modules/@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==",
"dev": true
},
"node_modules/@types/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
"dev": true
},
"node_modules/@types/cors": {
"version": "2.8.13",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
"integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": {
"version": "18.15.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz",
"integrity": "sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==",
"dev": true
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"dev": true,
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
"dev": true,
"engines": {
"node": "^4.5.0 || >= 5.9"
}
},
"node_modules/cookie": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
"dev": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"dev": true,
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/engine.io": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz",
"integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==",
"dev": true,
"dependencies": {
"@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.4.1",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.0.3",
"ws": "~8.11.0"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/engine.io-parser": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz",
"integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==",
"dev": true,
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"dev": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/socket.io": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.1.tgz",
"integrity": "sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==",
"dev": true,
"dependencies": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"debug": "~4.3.2",
"engine.io": "~6.4.1",
"socket.io-adapter": "~2.5.2",
"socket.io-parser": "~4.2.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-adapter": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz",
"integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==",
"dev": true,
"dependencies": {
"ws": "~8.11.0"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz",
"integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==",
"dev": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/typescript": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
"integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=12.20"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"dev": true,
"engines": {
"node": ">= 0.8"
}
},
"node_modules/ws": {
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"dev": true,
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
},
"dependencies": {
"@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==",
"dev": true
},
"@types/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
"dev": true
},
"@types/cors": {
"version": "2.8.13",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
"integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/node": {
"version": "18.15.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz",
"integrity": "sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==",
"dev": true
},
"accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"dev": true,
"requires": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
}
},
"base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
"dev": true
},
"cookie": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
"dev": true
},
"cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"dev": true,
"requires": {
"object-assign": "^4",
"vary": "^1"
}
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
}
},
"engine.io": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz",
"integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==",
"dev": true,
"requires": {
"@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.4.1",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.0.3",
"ws": "~8.11.0"
}
},
"engine.io-parser": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.6.tgz",
"integrity": "sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==",
"dev": true
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"requires": {
"mime-db": "1.52.0"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"dev": true
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true
},
"socket.io": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.1.tgz",
"integrity": "sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==",
"dev": true,
"requires": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"debug": "~4.3.2",
"engine.io": "~6.4.1",
"socket.io-adapter": "~2.5.2",
"socket.io-parser": "~4.2.1"
}
},
"socket.io-adapter": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz",
"integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==",
"dev": true,
"requires": {
"ws": "~8.11.0"
}
},
"socket.io-parser": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz",
"integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==",
"dev": true,
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
}
},
"typescript": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
"integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
"dev": true
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"dev": true
},
"ws": {
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"dev": true,
"requires": {}
}
}
}

View File

@@ -13,7 +13,7 @@
"author": "Gregor Biswanger",
"license": "MIT",
"devDependencies": {
"@types/socket.io": "^2.1.12",
"typescript": "^4.3.5"
"socket.io": "^4.6.1",
"typescript": "^5.0.2"
}
}

View File

@@ -140,21 +140,6 @@ module.exports = (socket, app) => {
electronSocket.emit('browserWindow-app-command' + id, command);
});
});
socket.on('register-browserWindow-scroll-touch-begin', (id) => {
getWindowById(id).on('scroll-touch-begin', () => {
electronSocket.emit('browserWindow-scroll-touch-begin' + id);
});
});
socket.on('register-browserWindow-scroll-touch-end', (id) => {
getWindowById(id).on('scroll-touch-end', () => {
electronSocket.emit('browserWindow-scroll-touch-end' + id);
});
});
socket.on('register-browserWindow-scroll-touch-edge', (id) => {
getWindowById(id).on('scroll-touch-edge', () => {
electronSocket.emit('browserWindow-scroll-touch-edge' + id);
});
});
socket.on('register-browserWindow-swipe', (id) => {
getWindowById(id).on('swipe', (event, direction) => {
electronSocket.emit('browserWindow-swipe' + id, direction);
@@ -596,7 +581,7 @@ module.exports = (socket, app) => {
getWindowById(id).setVibrancy(type);
});
socket.on('browserWindow-setBrowserView', (id, browserViewId) => {
getWindowById(id).setBrowserView(browserView_1.browserViewMediateService(browserViewId));
getWindowById(id).setBrowserView((0, browserView_1.browserViewMediateService)(browserViewId));
});
function getWindowById(id) {
for (let index = 0; index < windows.length; index++) {

File diff suppressed because one or more lines are too long

View File

@@ -167,24 +167,6 @@ export = (socket: Socket, app: Electron.App) => {
});
});
socket.on('register-browserWindow-scroll-touch-begin', (id) => {
getWindowById(id).on('scroll-touch-begin', () => {
electronSocket.emit('browserWindow-scroll-touch-begin' + id);
});
});
socket.on('register-browserWindow-scroll-touch-end', (id) => {
getWindowById(id).on('scroll-touch-end', () => {
electronSocket.emit('browserWindow-scroll-touch-end' + id);
});
});
socket.on('register-browserWindow-scroll-touch-edge', (id) => {
getWindowById(id).on('scroll-touch-edge', () => {
electronSocket.emit('browserWindow-scroll-touch-edge' + id);
});
});
socket.on('register-browserWindow-swipe', (id) => {
getWindowById(id).on('swipe', (event, direction) => {
electronSocket.emit('browserWindow-swipe' + id, direction);

View File

@@ -1 +1 @@
{"version":3,"file":"dialog.js","sourceRoot":"","sources":["dialog.ts"],"names":[],"mappings":";AACA,uCAAiD;AACjD,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC/D,IAAI,IAAI,IAAI,aAAa,EAAE;YACvB,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YAEtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC3E,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,IAAI,EAAE,CAAC,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAC,CAAC;SACjI;aAAM;YACH,MAAM,EAAE,GAAG,IAAI,IAAI,OAAO,CAAC;YAC3B,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAEzE,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,EAAE,EAAE,CAAC,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAC,CAAC;SAC/H;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC/D,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE3E,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,IAAI,EAAE,qBAAqB,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAChG,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC/D,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE3E,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,IAAI,EAAE,qBAAqB,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACzC,iBAAM,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC3E,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,iBAAM,CAAC,0BAA0B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAEzD,cAAc,CAAC,IAAI,CAAC,oCAAoC,GAAG,IAAI,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
{"version":3,"file":"dialog.js","sourceRoot":"","sources":["dialog.ts"],"names":[],"mappings":";AACA,uCAAiD;AACjD,IAAI,cAAsB,CAAC;AAE3B,iBAAS,CAAC,MAAc,EAAE,EAAE;IACxB,cAAc,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC/D,IAAI,IAAI,IAAI,aAAa,EAAE;YACvB,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YAEtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC3E,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,IAAI,EAAE,CAAC,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAC,CAAC;SACjI;aAAM;YACH,MAAM,EAAE,GAAG,IAAI,IAAI,OAAO,CAAC;YAC3B,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAEzE,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,EAAE,EAAE,CAAC,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,CAAC,eAAe,CAAC,CAAC,CAAC;SAC/H;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC/D,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE3E,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,IAAI,EAAE,qBAAqB,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAChG,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC/D,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,qBAAqB,GAAG,MAAM,iBAAM,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE3E,cAAc,CAAC,IAAI,CAAC,wBAAwB,GAAG,IAAI,EAAE,qBAAqB,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACzC,iBAAM,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC3E,MAAM,MAAM,GAAG,wBAAa,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,iBAAM,CAAC,0BAA0B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAEzD,cAAc,CAAC,IAAI,CAAC,oCAAoC,GAAG,IAAI,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}

View File

@@ -1,6 +1,6 @@
import { Socket } from 'net';
import { BrowserWindow, dialog } from 'electron';
let electronSocket;
let electronSocket: Socket;
export = (socket: Socket) => {
electronSocket = socket;

View File

@@ -19,6 +19,15 @@ module.exports = (socket) => {
electronSocket.emit('webContents-didFinishLoad' + id);
});
});
socket.on('register-webContents-input-event', (id) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.removeAllListeners('input-event');
browserWindow.webContents.on('input-event', (_, eventArgs) => {
if (eventArgs.type !== 'char') {
electronSocket.emit('webContents-input-event' + id, eventArgs);
}
});
});
socket.on('webContentsOpenDevTools', (id, options) => {
if (options) {
getWindowById(id).webContents.openDevTools(options);
@@ -28,7 +37,7 @@ module.exports = (socket) => {
}
});
socket.on('webContents-getPrinters', async (id) => {
const printers = await getWindowById(id).webContents.getPrinters();
const printers = await getWindowById(id).webContents.getPrintersAsync();
electronSocket.emit('webContents-getPrinters-completed', printers);
});
socket.on('webContents-print', async (id, options = {}) => {
@@ -166,9 +175,12 @@ module.exports = (socket) => {
});
socket.on('webContents-loadURL', (id, url, options) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.loadURL(url, options).then(() => {
browserWindow.webContents
.loadURL(url, options)
.then(() => {
electronSocket.emit('webContents-loadURL-complete' + id);
}).catch((error) => {
})
.catch((error) => {
console.error(error);
electronSocket.emit('webContents-loadURL-error' + id, error);
});
@@ -198,7 +210,7 @@ module.exports = (socket) => {
const browserWindow = getWindowById(id);
const extensionsList = browserWindow.webContents.session.getAllExtensions();
const chromeExtensionInfo = [];
Object.keys(extensionsList).forEach(key => {
Object.keys(extensionsList).forEach((key) => {
chromeExtensionInfo.push(extensionsList[key]);
});
electronSocket.emit('webContents-session-getAllExtensions-completed', chromeExtensionInfo);
@@ -214,7 +226,7 @@ module.exports = (socket) => {
});
function getWindowById(id) {
if (id >= 1000) {
return browserView_1.browserViewMediateService(id - 1000);
return (0, browserView_1.browserViewMediateService)(id - 1000);
}
return electron_1.BrowserWindow.fromId(id);
}

File diff suppressed because one or more lines are too long

View File

@@ -5,275 +5,288 @@ const fs = require('fs');
let electronSocket;
export = (socket: Socket) => {
electronSocket = socket;
socket.on('register-webContents-crashed', (id) => {
const browserWindow = getWindowById(id);
electronSocket = socket;
socket.on('register-webContents-crashed', (id) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.removeAllListeners('crashed');
browserWindow.webContents.on('crashed', (event, killed) => {
electronSocket.emit('webContents-crashed' + id, killed);
});
browserWindow.webContents.removeAllListeners('crashed');
browserWindow.webContents.on('crashed', (event, killed) => {
electronSocket.emit('webContents-crashed' + id, killed);
});
});
socket.on('register-webContents-didFinishLoad', (id) => {
const browserWindow = getWindowById(id);
socket.on('register-webContents-didFinishLoad', (id) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.removeAllListeners('did-finish-load');
browserWindow.webContents.on('did-finish-load', () => {
electronSocket.emit('webContents-didFinishLoad' + id);
});
browserWindow.webContents.removeAllListeners('did-finish-load');
browserWindow.webContents.on('did-finish-load', () => {
electronSocket.emit('webContents-didFinishLoad' + id);
});
});
socket.on('webContentsOpenDevTools', (id, options) => {
if (options) {
getWindowById(id).webContents.openDevTools(options);
} else {
getWindowById(id).webContents.openDevTools();
}
socket.on('register-webContents-input-event', (id) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.removeAllListeners('input-event');
browserWindow.webContents.on('input-event', (_, eventArgs) => {
if (eventArgs.type !== 'char') {
electronSocket.emit('webContents-input-event' + id, eventArgs);
}
});
});
socket.on('webContents-getPrinters', async (id) => {
const printers = await getWindowById(id).webContents.getPrinters();
electronSocket.emit('webContents-getPrinters-completed', printers);
});
socket.on('webContents-print', async (id, options = {}) => {
await getWindowById(id).webContents.print(options);
electronSocket.emit('webContents-print-completed', true);
});
socket.on('webContents-printToPDF', async (id, options = {}, path) => {
const buffer = await getWindowById(id).webContents.printToPDF(options);
fs.writeFile(path, buffer, (error) => {
if (error) {
electronSocket.emit('webContents-printToPDF-completed', false);
} else {
electronSocket.emit('webContents-printToPDF-completed', true);
}
});
});
socket.on('webContents-getUrl', function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-getUrl' + id, browserWindow.webContents.getURL());
});
socket.on('webContents-session-allowNTLMCredentialsForDomains', (id, domains) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.allowNTLMCredentialsForDomains(domains);
});
socket.on('webContents-session-clearAuthCache', async (id, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.clearAuthCache();
electronSocket.emit('webContents-session-clearAuthCache-completed' + guid);
});
socket.on('webContents-session-clearCache', async (id, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.clearCache();
electronSocket.emit('webContents-session-clearCache-completed' + guid);
});
socket.on('webContents-session-clearHostResolverCache', async (id, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.clearHostResolverCache();
electronSocket.emit('webContents-session-clearHostResolverCache-completed' + guid);
});
socket.on('webContents-session-clearStorageData', async (id, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.clearStorageData({});
electronSocket.emit('webContents-session-clearStorageData-completed' + guid);
});
socket.on('webContents-session-clearStorageData-options', async (id, options, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.clearStorageData(options);
electronSocket.emit('webContents-session-clearStorageData-options-completed' + guid);
});
socket.on('webContents-session-createInterruptedDownload', (id, options) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.createInterruptedDownload(options);
});
socket.on('webContents-session-disableNetworkEmulation', (id) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.disableNetworkEmulation();
});
socket.on('webContents-session-enableNetworkEmulation', (id, options) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.enableNetworkEmulation(options);
});
socket.on('webContents-session-flushStorageData', (id) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.flushStorageData();
});
socket.on('webContents-session-getBlobData', async (id, identifier, guid) => {
const browserWindow = getWindowById(id);
const buffer = await browserWindow.webContents.session.getBlobData(identifier);
electronSocket.emit('webContents-session-getBlobData-completed' + guid, buffer.buffer);
});
socket.on('webContents-session-getCacheSize', async (id, guid) => {
const browserWindow = getWindowById(id);
const size = await browserWindow.webContents.session.getCacheSize();
electronSocket.emit('webContents-session-getCacheSize-completed' + guid, size);
});
socket.on('webContents-session-getPreloads', (id, guid) => {
const browserWindow = getWindowById(id);
const preloads = browserWindow.webContents.session.getPreloads();
electronSocket.emit('webContents-session-getPreloads-completed' + guid, preloads);
});
socket.on('webContents-session-getUserAgent', (id, guid) => {
const browserWindow = getWindowById(id);
const userAgent = browserWindow.webContents.session.getUserAgent();
electronSocket.emit('webContents-session-getUserAgent-completed' + guid, userAgent);
});
socket.on('webContents-session-resolveProxy', async (id, url, guid) => {
const browserWindow = getWindowById(id);
const proxy = await browserWindow.webContents.session.resolveProxy(url);
electronSocket.emit('webContents-session-resolveProxy-completed' + guid, proxy);
});
socket.on('webContents-session-setDownloadPath', (id, path) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.setDownloadPath(path);
});
socket.on('webContents-session-setPreloads', (id, preloads) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.setPreloads(preloads);
});
socket.on('webContents-session-setProxy', async (id, configuration, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.setProxy(configuration);
electronSocket.emit('webContents-session-setProxy-completed' + guid);
});
socket.on('webContents-session-setUserAgent', (id, userAgent, acceptLanguages) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.setUserAgent(userAgent, acceptLanguages);
});
socket.on('register-webContents-session-cookies-changed', (id) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.cookies.removeAllListeners('changed');
browserWindow.webContents.session.cookies.on('changed', (event, cookie, cause, removed) => {
electronSocket.emit('webContents-session-cookies-changed' + id, [cookie, cause, removed]);
});
});
socket.on('webContents-session-cookies-get', async (id, filter, guid) => {
const browserWindow = getWindowById(id);
const cookies = await browserWindow.webContents.session.cookies.get(filter);
electronSocket.emit('webContents-session-cookies-get-completed' + guid, cookies);
});
socket.on('webContents-session-cookies-set', async (id, details, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.cookies.set(details);
electronSocket.emit('webContents-session-cookies-set-completed' + guid);
});
socket.on('webContents-session-cookies-remove', async (id, url, name, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.cookies.remove(url, name);
electronSocket.emit('webContents-session-cookies-remove-completed' + guid);
});
socket.on('webContents-session-cookies-flushStore', async (id, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.cookies.flushStore();
electronSocket.emit('webContents-session-cookies-flushStore-completed' + guid);
});
socket.on('webContents-loadURL', (id, url, options) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.loadURL(url, options).then(() => {
electronSocket.emit('webContents-loadURL-complete' + id);
}).catch((error) => {
console.error(error);
electronSocket.emit('webContents-loadURL-error' + id, error);
});
});
socket.on('webContents-insertCSS', (id, isBrowserWindow, path) => {
if (isBrowserWindow) {
const browserWindow = getWindowById(id);
if (browserWindow) {
browserWindow.webContents.insertCSS(fs.readFileSync(path, 'utf8'));
}
} else {
const browserViews: BrowserView[] = (global['browserViews'] = global['browserViews'] || []) as BrowserView[];
let view: BrowserView = null;
for (let i = 0; i < browserViews.length; i++) {
if (browserViews[i]['id'] + 1000 === id) {
view = browserViews[i];
break;
}
}
if (view) {
view.webContents.insertCSS(fs.readFileSync(path, 'utf8'));
}
}
});
socket.on('webContents-session-getAllExtensions', (id) => {
const browserWindow = getWindowById(id);
const extensionsList = browserWindow.webContents.session.getAllExtensions();
const chromeExtensionInfo = [];
Object.keys(extensionsList).forEach(key => {
chromeExtensionInfo.push(extensionsList[key]);
});
electronSocket.emit('webContents-session-getAllExtensions-completed', chromeExtensionInfo);
});
socket.on('webContents-session-removeExtension', (id, name) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.removeExtension(name);
});
socket.on('webContents-session-loadExtension', async (id, path, allowFileAccess = false) => {
const browserWindow = getWindowById(id);
const extension = await browserWindow.webContents.session.loadExtension(path, { allowFileAccess: allowFileAccess });
electronSocket.emit('webContents-session-loadExtension-completed', extension);
});
function getWindowById(id: number): Electron.BrowserWindow | Electron.BrowserView {
if (id >= 1000) {
return browserViewMediateService(id - 1000);
}
return BrowserWindow.fromId(id);
socket.on('webContentsOpenDevTools', (id, options) => {
if (options) {
getWindowById(id).webContents.openDevTools(options);
} else {
getWindowById(id).webContents.openDevTools();
}
});
socket.on('webContents-getPrinters', async (id) => {
const printers = await getWindowById(id).webContents.getPrintersAsync();
electronSocket.emit('webContents-getPrinters-completed', printers);
});
socket.on('webContents-print', async (id, options = {}) => {
await getWindowById(id).webContents.print(options);
electronSocket.emit('webContents-print-completed', true);
});
socket.on('webContents-printToPDF', async (id, options = {}, path) => {
const buffer = await getWindowById(id).webContents.printToPDF(options);
fs.writeFile(path, buffer, (error) => {
if (error) {
electronSocket.emit('webContents-printToPDF-completed', false);
} else {
electronSocket.emit('webContents-printToPDF-completed', true);
}
});
});
socket.on('webContents-getUrl', function (id) {
const browserWindow = getWindowById(id);
electronSocket.emit('webContents-getUrl' + id, browserWindow.webContents.getURL());
});
socket.on('webContents-session-allowNTLMCredentialsForDomains', (id, domains) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.allowNTLMCredentialsForDomains(domains);
});
socket.on('webContents-session-clearAuthCache', async (id, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.clearAuthCache();
electronSocket.emit('webContents-session-clearAuthCache-completed' + guid);
});
socket.on('webContents-session-clearCache', async (id, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.clearCache();
electronSocket.emit('webContents-session-clearCache-completed' + guid);
});
socket.on('webContents-session-clearHostResolverCache', async (id, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.clearHostResolverCache();
electronSocket.emit('webContents-session-clearHostResolverCache-completed' + guid);
});
socket.on('webContents-session-clearStorageData', async (id, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.clearStorageData({});
electronSocket.emit('webContents-session-clearStorageData-completed' + guid);
});
socket.on('webContents-session-clearStorageData-options', async (id, options, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.clearStorageData(options);
electronSocket.emit('webContents-session-clearStorageData-options-completed' + guid);
});
socket.on('webContents-session-createInterruptedDownload', (id, options) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.createInterruptedDownload(options);
});
socket.on('webContents-session-disableNetworkEmulation', (id) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.disableNetworkEmulation();
});
socket.on('webContents-session-enableNetworkEmulation', (id, options) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.enableNetworkEmulation(options);
});
socket.on('webContents-session-flushStorageData', (id) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.flushStorageData();
});
socket.on('webContents-session-getBlobData', async (id, identifier, guid) => {
const browserWindow = getWindowById(id);
const buffer = await browserWindow.webContents.session.getBlobData(identifier);
electronSocket.emit('webContents-session-getBlobData-completed' + guid, buffer.buffer);
});
socket.on('webContents-session-getCacheSize', async (id, guid) => {
const browserWindow = getWindowById(id);
const size = await browserWindow.webContents.session.getCacheSize();
electronSocket.emit('webContents-session-getCacheSize-completed' + guid, size);
});
socket.on('webContents-session-getPreloads', (id, guid) => {
const browserWindow = getWindowById(id);
const preloads = browserWindow.webContents.session.getPreloads();
electronSocket.emit('webContents-session-getPreloads-completed' + guid, preloads);
});
socket.on('webContents-session-getUserAgent', (id, guid) => {
const browserWindow = getWindowById(id);
const userAgent = browserWindow.webContents.session.getUserAgent();
electronSocket.emit('webContents-session-getUserAgent-completed' + guid, userAgent);
});
socket.on('webContents-session-resolveProxy', async (id, url, guid) => {
const browserWindow = getWindowById(id);
const proxy = await browserWindow.webContents.session.resolveProxy(url);
electronSocket.emit('webContents-session-resolveProxy-completed' + guid, proxy);
});
socket.on('webContents-session-setDownloadPath', (id, path) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.setDownloadPath(path);
});
socket.on('webContents-session-setPreloads', (id, preloads) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.setPreloads(preloads);
});
socket.on('webContents-session-setProxy', async (id, configuration, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.setProxy(configuration);
electronSocket.emit('webContents-session-setProxy-completed' + guid);
});
socket.on('webContents-session-setUserAgent', (id, userAgent, acceptLanguages) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.setUserAgent(userAgent, acceptLanguages);
});
socket.on('register-webContents-session-cookies-changed', (id) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.cookies.removeAllListeners('changed');
browserWindow.webContents.session.cookies.on('changed', (event, cookie, cause, removed) => {
electronSocket.emit('webContents-session-cookies-changed' + id, [cookie, cause, removed]);
});
});
socket.on('webContents-session-cookies-get', async (id, filter, guid) => {
const browserWindow = getWindowById(id);
const cookies = await browserWindow.webContents.session.cookies.get(filter);
electronSocket.emit('webContents-session-cookies-get-completed' + guid, cookies);
});
socket.on('webContents-session-cookies-set', async (id, details, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.cookies.set(details);
electronSocket.emit('webContents-session-cookies-set-completed' + guid);
});
socket.on('webContents-session-cookies-remove', async (id, url, name, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.cookies.remove(url, name);
electronSocket.emit('webContents-session-cookies-remove-completed' + guid);
});
socket.on('webContents-session-cookies-flushStore', async (id, guid) => {
const browserWindow = getWindowById(id);
await browserWindow.webContents.session.cookies.flushStore();
electronSocket.emit('webContents-session-cookies-flushStore-completed' + guid);
});
socket.on('webContents-loadURL', (id, url, options) => {
const browserWindow = getWindowById(id);
browserWindow.webContents
.loadURL(url, options)
.then(() => {
electronSocket.emit('webContents-loadURL-complete' + id);
})
.catch((error) => {
console.error(error);
electronSocket.emit('webContents-loadURL-error' + id, error);
});
});
socket.on('webContents-insertCSS', (id, isBrowserWindow, path) => {
if (isBrowserWindow) {
const browserWindow = getWindowById(id);
if (browserWindow) {
browserWindow.webContents.insertCSS(fs.readFileSync(path, 'utf8'));
}
} else {
const browserViews: BrowserView[] = (global['browserViews'] = global['browserViews'] || []) as BrowserView[];
let view: BrowserView = null;
for (let i = 0; i < browserViews.length; i++) {
if (browserViews[i]['id'] + 1000 === id) {
view = browserViews[i];
break;
}
}
if (view) {
view.webContents.insertCSS(fs.readFileSync(path, 'utf8'));
}
}
});
socket.on('webContents-session-getAllExtensions', (id) => {
const browserWindow = getWindowById(id);
const extensionsList = browserWindow.webContents.session.getAllExtensions();
const chromeExtensionInfo = [];
Object.keys(extensionsList).forEach((key) => {
chromeExtensionInfo.push(extensionsList[key]);
});
electronSocket.emit('webContents-session-getAllExtensions-completed', chromeExtensionInfo);
});
socket.on('webContents-session-removeExtension', (id, name) => {
const browserWindow = getWindowById(id);
browserWindow.webContents.session.removeExtension(name);
});
socket.on('webContents-session-loadExtension', async (id, path, allowFileAccess = false) => {
const browserWindow = getWindowById(id);
const extension = await browserWindow.webContents.session.loadExtension(path, { allowFileAccess: allowFileAccess });
electronSocket.emit('webContents-session-loadExtension-completed', extension);
});
function getWindowById(id: number): Electron.BrowserWindow | Electron.BrowserView {
if (id >= 1000) {
return browserViewMediateService(id - 1000);
}
return BrowserWindow.fromId(id);
}
};

View File

@@ -19,317 +19,331 @@ let launchUrl;
let manifestJsonFileName = 'electron.manifest.json';
let watchable = false;
if (app.commandLine.hasSwitch('manifest')) {
manifestJsonFileName = app.commandLine.getSwitchValue('manifest');
};
manifestJsonFileName = app.commandLine.getSwitchValue('manifest');
}
if (app.commandLine.hasSwitch('watch')) {
watchable = true;
};
watchable = true;
}
let currentBinPath = path.join(__dirname.replace('app.asar', ''), 'bin');
let manifestJsonFilePath = path.join(currentBinPath, manifestJsonFileName);
// if watch is enabled lets change the path
if (watchable) {
currentBinPath = path.join(__dirname, '../../'); // go to project directory
manifestJsonFilePath = path.join(currentBinPath, manifestJsonFileName);
currentBinPath = path.join(__dirname, '../../'); // go to project directory
manifestJsonFilePath = path.join(currentBinPath, manifestJsonFileName);
}
// handle macOS events for opening the app with a file, etc
app.on('will-finish-launching', () => {
app.on('open-file', (evt, file) => {
evt.preventDefault();
launchFile = file;
})
app.on('open-url', (evt, url) => {
evt.preventDefault();
launchUrl = url;
})
app.on('open-file', (evt, file) => {
evt.preventDefault();
launchFile = file;
});
app.on('open-url', (evt, url) => {
evt.preventDefault();
launchUrl = url;
});
});
const manifestJsonFile = require(manifestJsonFilePath);
if (manifestJsonFile.singleInstance || manifestJsonFile.aspCoreBackendPort) {
const mainInstance = app.requestSingleInstanceLock();
app.on('second-instance', (events, args = []) => {
args.forEach(parameter => {
const words = parameter.split('=');
const mainInstance = app.requestSingleInstanceLock();
app.on('second-instance', (events, args = []) => {
args.forEach((parameter) => {
const words = parameter.split('=');
if(words.length > 1) {
app.commandLine.appendSwitch(words[0].replace('--', ''), words[1]);
} else {
app.commandLine.appendSwitch(words[0].replace('--', ''));
}
});
const windows = BrowserWindow.getAllWindows();
if (windows.length) {
if (windows[0].isMinimized()) {
windows[0].restore();
}
windows[0].focus();
}
if (words.length > 1) {
app.commandLine.appendSwitch(words[0].replace('--', ''), words[1]);
} else {
app.commandLine.appendSwitch(words[0].replace('--', ''));
}
});
if (!mainInstance) {
app.quit();
const windows = BrowserWindow.getAllWindows();
if (windows.length) {
if (windows[0].isMinimized()) {
windows[0].restore();
}
windows[0].focus();
}
});
if (!mainInstance) {
app.quit();
}
}
app.on('ready', () => {
// Fix ERR_UNKNOWN_URL_SCHEME using file protocol
// https://github.com/electron/electron/issues/23757
protocol.registerFileProtocol('file', (request, callback) => {
const pathname = request.url.replace('file:///', '');
callback(pathname);
});
// Fix ERR_UNKNOWN_URL_SCHEME using file protocol
// https://github.com/electron/electron/issues/23757
protocol.registerFileProtocol('file', (request, callback) => {
const pathname = request.url.replace('file:///', '');
callback(pathname);
});
if (isSplashScreenEnabled()) {
startSplashScreen();
}
// Added default port as configurable for port restricted environments.
let defaultElectronPort = 8000;
if (manifestJsonFile.electronPort) {
defaultElectronPort = (manifestJsonFile.electronPort)
}
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
portscanner.findAPortNotInUse(defaultElectronPort, 65535, 'localhost', function (error, port) {
console.log('Electron Socket IO Port: ' + port);
startSocketApiBridge(port);
});
if (isSplashScreenEnabled()) {
startSplashScreen();
}
// Added default port as configurable for port restricted environments.
let defaultElectronPort = 8000;
if (manifestJsonFile.electronPort) {
defaultElectronPort = manifestJsonFile.electronPort;
}
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
portscanner.findAPortNotInUse(defaultElectronPort, 65535, 'localhost', function (error, port) {
console.log('Electron Socket IO Port: ' + port);
startSocketApiBridge(port);
});
});
app.on('quit', async (event, exitCode) => {
await server.close();
apiProcess.kill();
await server.close();
apiProcess.kill();
});
function isSplashScreenEnabled() {
if (manifestJsonFile.hasOwnProperty('splashscreen')) {
if (manifestJsonFile.splashscreen.hasOwnProperty('imageFile')) {
return Boolean(manifestJsonFile.splashscreen.imageFile);
}
if (manifestJsonFile.hasOwnProperty('splashscreen')) {
if (manifestJsonFile.splashscreen.hasOwnProperty('imageFile')) {
return Boolean(manifestJsonFile.splashscreen.imageFile);
}
}
return false;
return false;
}
function startSplashScreen() {
let imageFile = path.join(currentBinPath, manifestJsonFile.splashscreen.imageFile);
imageSize(imageFile, (error, dimensions) => {
if (error) {
console.log(`load splashscreen error:`);
console.error(error);
let imageFile = path.join(currentBinPath, manifestJsonFile.splashscreen.imageFile);
imageSize(imageFile, (error, dimensions) => {
if (error) {
console.log(`load splashscreen error:`);
console.error(error);
throw new Error(error.message);
}
throw new Error(error.message);
}
splashScreen = new BrowserWindow({
width: dimensions.width,
height: dimensions.height,
transparent: true,
center: true,
frame: false,
closable: false,
resizable: false,
skipTaskbar: true,
alwaysOnTop: true,
show: true
});
splashScreen.setIgnoreMouseEvents(true);
app.once('browser-window-created', () => {
splashScreen.destroy();
});
const loadSplashscreenUrl = path.join(__dirname, 'splashscreen', 'index.html') + '?imgPath=' + imageFile;
splashScreen.loadURL('file://' + loadSplashscreenUrl);
splashScreen.once('closed', () => {
splashScreen = null;
});
splashScreen = new BrowserWindow({
width: dimensions.width,
height: dimensions.height,
transparent: true,
center: true,
frame: false,
closable: false,
resizable: false,
skipTaskbar: true,
alwaysOnTop: true,
show: true,
});
splashScreen.setIgnoreMouseEvents(true);
app.once('browser-window-created', () => {
splashScreen.destroy();
});
const loadSplashscreenUrl = path.join(__dirname, 'splashscreen', 'index.html') + '?imgPath=' + imageFile;
splashScreen.loadURL('file://' + loadSplashscreenUrl);
splashScreen.once('closed', () => {
splashScreen = null;
});
});
}
function startSocketApiBridge(port) {
// instead of 'require('socket.io')(port);' we need to use this workaround
// otherwise the Windows Firewall will be triggered
server = require('http').createServer();
const { Server } = require('socket.io');
io = new Server({
pingTimeout: 60000, // in ms, default is 5000
pingInterval: 10000, // in ms, default is 25000
});
io.attach(server);
// instead of 'require('socket.io')(port);' we need to use this workaround
// otherwise the Windows Firewall will be triggered
server = require('http').createServer();
io = require('socket.io')();
io.attach(server);
server.listen(port, 'localhost');
server.on('listening', function () {
console.log('Electron Socket started on port %s at %s', server.address().port, server.address().address);
// Now that socket connection is established, we can guarantee port will not be open for portscanner
if (watchable) {
startAspCoreBackendWithWatch(port);
} else {
startAspCoreBackend(port);
}
});
server.listen(port, 'localhost');
server.on('listening', function () {
console.log('Electron Socket started on port %s at %s', server.address().port, server.address().address);
// Now that socket connection is established, we can guarantee port will not be open for portscanner
if (watchable) {
startAspCoreBackendWithWatch(port);
} else {
startAspCoreBackend(port);
// prototype
app['mainWindowURL'] = '';
app['mainWindow'] = null;
// @ts-ignore
io.on('connection', (socket) => {
socket.on('disconnect', function (reason) {
console.log('Got disconnect! Reason: ' + reason);
try {
if (hostHook) {
const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js');
delete require.cache[require.resolve(hostHookScriptFilePath)];
hostHook = undefined;
}
} catch (error) {
console.error(error.message);
}
});
// prototype
app['mainWindowURL'] = "";
app['mainWindow'] = null;
if (global['electronsocket'] === undefined) {
global['electronsocket'] = socket;
global['electronsocket'].setMaxListeners(0);
}
// @ts-ignore
io.on('connection', (socket) => {
console.log(
'ASP.NET Core Application connected...',
'global.electronsocket',
global['electronsocket'].id,
new Date()
);
socket.on('disconnect', function (reason) {
console.log('Got disconnect! Reason: ' + reason);
try {
if (hostHook) {
const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js');
delete require.cache[require.resolve(hostHookScriptFilePath)];
hostHook = undefined;
}
if (appApi === undefined) appApi = require('./api/app')(socket, app);
if (browserWindows === undefined) browserWindows = require('./api/browserWindows')(socket, app);
if (commandLine === undefined) commandLine = require('./api/commandLine')(socket, app);
if (autoUpdater === undefined) autoUpdater = require('./api/autoUpdater')(socket);
if (ipc === undefined) ipc = require('./api/ipc')(socket);
if (menu === undefined) menu = require('./api/menu')(socket);
if (dialogApi === undefined) dialogApi = require('./api/dialog')(socket);
if (notification === undefined) notification = require('./api/notification')(socket);
if (tray === undefined) tray = require('./api/tray')(socket);
if (webContents === undefined) webContents = require('./api/webContents')(socket);
if (globalShortcut === undefined) globalShortcut = require('./api/globalShortcut')(socket);
if (shellApi === undefined) shellApi = require('./api/shell')(socket);
if (screen === undefined) screen = require('./api/screen')(socket);
if (clipboard === undefined) clipboard = require('./api/clipboard')(socket);
if (browserView === undefined) browserView = require('./api/browserView').browserViewApi(socket);
if (powerMonitor === undefined) powerMonitor = require('./api/powerMonitor')(socket);
if (nativeTheme === undefined) nativeTheme = require('./api/nativeTheme')(socket);
if (dock === undefined) dock = require('./api/dock')(socket);
} catch (error) {
console.error(error.message);
}
});
socket.on('register-app-open-file-event', (id) => {
global['electronsocket'] = socket;
app.on('open-file', (event, file) => {
event.preventDefault();
if (global['electronsocket'] === undefined) {
global['electronsocket'] = socket;
global['electronsocket'].setMaxListeners(0);
}
global['electronsocket'].emit('app-open-file' + id, file);
});
console.log('ASP.NET Core Application connected...', 'global.electronsocket', global['electronsocket'].id, new Date());
if (appApi === undefined) appApi = require('./api/app')(socket, app);
if (browserWindows === undefined) browserWindows = require('./api/browserWindows')(socket, app);
if (commandLine === undefined) commandLine = require('./api/commandLine')(socket, app);
if (autoUpdater === undefined) autoUpdater = require('./api/autoUpdater')(socket);
if (ipc === undefined) ipc = require('./api/ipc')(socket);
if (menu === undefined) menu = require('./api/menu')(socket);
if (dialogApi === undefined) dialogApi = require('./api/dialog')(socket);
if (notification === undefined) notification = require('./api/notification')(socket);
if (tray === undefined) tray = require('./api/tray')(socket);
if (webContents === undefined) webContents = require('./api/webContents')(socket);
if (globalShortcut === undefined) globalShortcut = require('./api/globalShortcut')(socket);
if (shellApi === undefined) shellApi = require('./api/shell')(socket);
if (screen === undefined) screen = require('./api/screen')(socket);
if (clipboard === undefined) clipboard = require('./api/clipboard')(socket);
if (browserView === undefined) browserView = require('./api/browserView').browserViewApi(socket);
if (powerMonitor === undefined) powerMonitor = require('./api/powerMonitor')(socket);
if (nativeTheme === undefined) nativeTheme = require('./api/nativeTheme')(socket);
if (dock === undefined) dock = require('./api/dock')(socket);
socket.on('register-app-open-file-event', (id) => {
global['electronsocket'] = socket;
app.on('open-file', (event, file) => {
event.preventDefault();
global['electronsocket'].emit('app-open-file' + id, file);
});
if (launchFile) {
global['electronsocket'].emit('app-open-file' + id, launchFile);
}
});
socket.on('register-app-open-url-event', (id) => {
global['electronsocket'] = socket;
app.on('open-url', (event, url) => {
event.preventDefault();
global['electronsocket'].emit('app-open-url' + id, url);
});
if (launchUrl) {
global['electronsocket'].emit('app-open-url' + id, launchUrl);
}
});
try {
const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js');
if (isModuleAvailable(hostHookScriptFilePath) && hostHook === undefined) {
const { HookService } = require(hostHookScriptFilePath);
hostHook = new HookService(socket, app);
hostHook.onHostReady();
}
} catch (error) {
console.error(error.message);
}
if (launchFile) {
global['electronsocket'].emit('app-open-file' + id, launchFile);
}
});
socket.on('register-app-open-url-event', (id) => {
global['electronsocket'] = socket;
app.on('open-url', (event, url) => {
event.preventDefault();
global['electronsocket'].emit('app-open-url' + id, url);
});
if (launchUrl) {
global['electronsocket'].emit('app-open-url' + id, launchUrl);
}
});
try {
const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js');
if (isModuleAvailable(hostHookScriptFilePath) && hostHook === undefined) {
const { HookService } = require(hostHookScriptFilePath);
hostHook = new HookService(socket, app);
hostHook.onHostReady();
}
} catch (error) {
console.error(error.message);
}
});
}
function isModuleAvailable(name) {
try {
require.resolve(name);
return true;
} catch (e) { }
return false;
try {
require.resolve(name);
return true;
} catch (e) {}
return false;
}
function startAspCoreBackend(electronPort) {
if (manifestJsonFile.aspCoreBackendPort) {
startBackend(manifestJsonFile.aspCoreBackendPort)
} else {
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
portscanner.findAPortNotInUse(electronPort + 1, 65535, 'localhost', function (error, electronWebPort) {
startBackend(electronWebPort);
});
if (manifestJsonFile.aspCoreBackendPort) {
startBackend(manifestJsonFile.aspCoreBackendPort);
} else {
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
portscanner.findAPortNotInUse(electronPort + 1, 65535, 'localhost', function (error, electronWebPort) {
startBackend(electronWebPort);
});
}
function startBackend(aspCoreBackendPort) {
console.log('ASP.NET Core Port: ' + aspCoreBackendPort);
loadURL = `http://localhost:${aspCoreBackendPort}`;
const parameters = [
getEnvironmentParameter(),
`/electronPort=${electronPort}`,
`/electronWebPort=${aspCoreBackendPort}`,
];
let binaryFile = manifestJsonFile.executable;
const os = require('os');
if (os.platform() === 'win32') {
binaryFile = binaryFile + '.exe';
}
function startBackend(aspCoreBackendPort) {
console.log('ASP.NET Core Port: ' + aspCoreBackendPort);
loadURL = `http://localhost:${aspCoreBackendPort}`;
const parameters = [getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`];
let binaryFile = manifestJsonFile.executable;
let binFilePath = path.join(currentBinPath, binaryFile);
var options = { cwd: currentBinPath };
apiProcess = cProcess(binFilePath, parameters, options);
const os = require('os');
if (os.platform() === 'win32') {
binaryFile = binaryFile + '.exe';
}
let binFilePath = path.join(currentBinPath, binaryFile);
var options = { cwd: currentBinPath };
apiProcess = cProcess(binFilePath, parameters, options);
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
});
}
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
});
}
}
function startAspCoreBackendWithWatch(electronPort) {
if (manifestJsonFile.aspCoreBackendPort) {
startBackend(manifestJsonFile.aspCoreBackendPort)
} else {
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
portscanner.findAPortNotInUse(electronPort + 1, 65535, 'localhost', function (error, electronWebPort) {
startBackend(electronWebPort);
});
}
if (manifestJsonFile.aspCoreBackendPort) {
startBackend(manifestJsonFile.aspCoreBackendPort);
} else {
// hostname needs to be localhost, otherwise Windows Firewall will be triggered.
portscanner.findAPortNotInUse(electronPort + 1, 65535, 'localhost', function (error, electronWebPort) {
startBackend(electronWebPort);
});
}
function startBackend(aspCoreBackendPort) {
console.log('ASP.NET Core Watch Port: ' + aspCoreBackendPort);
loadURL = `http://localhost:${aspCoreBackendPort}`;
const parameters = ['watch', 'run', getEnvironmentParameter(), `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`];
function startBackend(aspCoreBackendPort) {
console.log('ASP.NET Core Watch Port: ' + aspCoreBackendPort);
loadURL = `http://localhost:${aspCoreBackendPort}`;
const parameters = [
'watch',
'run',
getEnvironmentParameter(),
`/electronPort=${electronPort}`,
`/electronWebPort=${aspCoreBackendPort}`,
];
var options = {
cwd: currentBinPath,
env: process.env,
};
apiProcess = cProcess('dotnet', parameters, options);
var options = {
cwd: currentBinPath,
env: process.env,
};
apiProcess = cProcess('dotnet', parameters, options);
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
});
}
apiProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data.toString()}`);
});
}
}
function getEnvironmentParameter() {
if (manifestJsonFile.environment) {
return '--environment=' + manifestJsonFile.environment;
}
if (manifestJsonFile.environment) {
return '--environment=' + manifestJsonFile.environment;
}
return '';
return '';
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,27 @@
{
"name": "electron.net.host",
"version": "1.0.0",
"description": "Electron-Host for Electron.NET.",
"repository": {
"url": "https://github.com/ElectronNET/Electron.NET"
},
"main": "main.js",
"author": "Gregor Biswanger",
"license": "MIT",
"scripts": {
"start": "tsc -p ."
},
"dependencies": {
"dasherize": "^2.0.0",
"electron-updater": "^4.3.9",
"image-size": "^1.0.0",
"portscanner": "^2.2.0",
"socket.io": "^2.4.0"
},
"devDependencies": {
"@types/node": "^15.14.0",
"electron": "^13.1.5",
"tslint": "^6.1.3",
"typescript": "^4.3.5"
}
"name": "electron.net.host",
"version": "1.0.0",
"description": "Electron-Host for Electron.NET.",
"repository": {
"url": "https://github.com/ElectronNET/Electron.NET"
},
"main": "main.js",
"author": "Gregor Biswanger, Florian Rappl",
"license": "MIT",
"scripts": {
"start": "tsc -p ."
},
"dependencies": {
"dasherize": "^2.0.0",
"electron-updater": "^5.3.0",
"image-size": "^1.0.2",
"portscanner": "^2.2.0",
"socket.io": "^4.6.1"
},
"devDependencies": {
"@types/node": "^18.15.5",
"electron": "^23.2.0",
"tslint": "^6.1.3",
"typescript": "^5.0.2"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -13,8 +13,8 @@
"author": "Gregor Biswanger",
"license": "MIT",
"devDependencies": {
"@types/socket.io": "^2.1.2",
"typescript": "^3.4.5"
"socket.io": "^4.6.1",
"typescript": "^5.0.2"
},
"dependencies": {
"exceljs": "^1.10.0"

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
<AspNetCoreModuleName>AspNetCoreModule</AspNetCoreModuleName>
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
@@ -16,7 +16,14 @@
<Folder Include="wwwroot\assets\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.13" />
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.410601">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.15" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SocketIOClient" Version="3.0.8" />
<PackageReference Include="SocketIOClient.Newtonsoft.Json" Version="3.0.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ElectronNET.API\ElectronNET.API.csproj" />

View File

@@ -8,8 +8,8 @@
"build": {
"appId": "com.electronnetapidemos.app",
"productName": "ElectronNET API Demos",
"copyright": "Copyright <20> 2019-2021",
"buildVersion": "13.5.1",
"copyright": "Copyright <20> 2019-2023",
"buildVersion": "23.6.1",
"compression": "maximum",
"win": {
"icon": "Assets/electron.ico",

View File

@@ -9,9 +9,9 @@ AppVeyor (Win/Linux): [![Build status](https://ci.appveyor.com/api/projects/stat
Travis-CI (Win/macOS/Linux): [![Build Status](https://travis-ci.org/ElectronNET/Electron.NET.svg?branch=master)](https://travis-ci.org/ElectronNET/Electron.NET)
Build cross platform desktop apps with .NET 5 and ASP.NET NET Core (Razor Pages, MVC), Blazor.
Build cross platform desktop apps with .NET 6 and Blazor, ASP.NET Core (Razor Pages, MVC).
Electron.NET is a __wrapper__ around a "normal" Electron application with an embedded ASP.NET Core application. Via our Electron.NET IPC bridge we can invoke Electron APIs from .NET.
Electron.NET is a __wrapper__ around a native Electron application with an embedded ASP.NET Core application. Via our Electron.NET IPC bridge we can invoke Electron APIs from .NET.
The CLI extensions hosts our toolset to build and start Electron.NET applications.
@@ -26,11 +26,11 @@ Well... there are lots of different approaches how to get a X-plat desktop app r
## 🛠 Requirements to run:
The current Electron.NET CLI builds Windows/macOS/Linux binaries. Our API uses .NET 5, so our minimum base OS is the same as [.NET 5](https://github.com/dotnet/core/blob/master/release-notes/5.0/5.0-supported-os.md).
The current Electron.NET CLI builds Windows/macOS/Linux binaries. Our API uses .NET 6, so our minimum base OS is the same as [.NET 6](https://github.com/dotnet/core/blob/main/release-notes/6.0/supported-os.md).
Also you should have installed:
* npm [contained in nodejs](https://nodejs.org)
* npm [contained in nodejs (at least Version 16.17.1)](https://nodejs.org)
## 💬 Community
@@ -49,6 +49,35 @@ To activate and communicate with the "native" (sort of native...) Electron API i
````
PM> Install-Package ElectronNET.API
````
## Minimal-API
You start Electron.NET up with an `UseElectron` WebHostBuilder-Extension and open the Electron Window:
### Program.cs
```csharp
using ElectronNET.API;
using ElectronNET.API.Entities;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseElectron(args);
// Is optional, but you can use the Electron.NET API-Classes directly with DI (relevant if you wont more encoupled code)
builder.Services.AddElectron();
var app = builder.Build();
...
await app.StartAsync();
// Open the Electron-Window here
Task.Run(async () => await Electron.WindowManager.CreateWindowAsync());
app.WaitForShutdown();
```
## Conventional
### Program.cs
You start Electron.NET up with an `UseElectron` WebHostBuilder-Extension.
@@ -152,10 +181,19 @@ The end result should be an electron app under your __/bin/desktop__ folder.
### Note
> macOS builds can't be created on Windows machines because they require symlinks that aren't supported on Windows (per [this Electron issue](https://github.com/electron-userland/electron-packager/issues/71)). macOS builds can be produced on either Linux or macOS machines.
## 🔄 Update
After an update to the latest Electron.API package, an update to the latest Electron.CLI is always required. In addition, always update the CLI via NuGet:
```
dotnet tool update ElectronNET.CLI -g
```
## 👨‍💻 Authors
* **Gregor Biswanger** - (Microsoft MVP, Intel Black Belt and Intel Software Innovator) is a freelance lecturer, consultant, trainer, author and speaker. He is a consultant for large and medium-sized companies, organizations and agencies for software architecture, web- and cross-platform development. You can find Gregor often on the road attending or speaking at international conferences. - [Cross-Platform-Blog](http://www.cross-platform-blog.com) - Twitter [@BFreakout](https://www.twitter.com/BFreakout)
* **Dr. Florian Rappl** - Software Developer - from Munich, Germany. Microsoft MVP & Web Geek. - [Florian Rappl](https://florianrappl.de) - Twitter [@florianrappl](https://twitter.com/florianrappl)
* **Robert Muehsig** - Software Developer - from Dresden, Germany, now living & working in Switzerland. Microsoft MVP & Web Geek. - [codeinside Blog](https://blog.codeinside.eu) - Twitter [@robert0muehsig](https://twitter.com/robert0muehsig)
See also the list of [contributors](https://github.com/ElectronNET/Electron.NET/graphs/contributors) who participated in this project.
@@ -185,7 +223,9 @@ We do this open source work in our free time. If you'd like us to invest more ti
MIT-licensed
**Enjoy!**
## 📝 Important notes
### ElectronNET.API & ElectronNET.CLI Version 9.31.2

View File

@@ -1,4 +1,4 @@
set ENETVER=13.5.1
set ENETVER=23.6.1
echo "Start building Electron.NET dev stack..."
echo "Restore & Build API"
cd ElectronNet.API