mirror of
https://github.com/ElectronNET/Electron.NET.git
synced 2026-07-20 15:46:15 +00:00
implement Demo App sections: Dialogs, Menu, Tray, Shell, CrashHang, Notification, Shortcuts etc. Fix some API bugs and implement GlobalShortcut-, Shell- and WebContents-API.
This commit is contained in:
76
ElectronNET.WebApp/Controllers/CrashHangController.cs
Normal file
76
ElectronNET.WebApp/Controllers/CrashHangController.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ElectronNET.API;
|
||||
using ElectronNET.API.Entities;
|
||||
|
||||
namespace ElectronNET.WebApp.Controllers
|
||||
{
|
||||
public class CrashHangController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
Electron.IpcMain.On("process-crash", async (args) =>
|
||||
{
|
||||
string viewPath = $"http://localhost:{BridgeSettings.WebPort}/crashhang/processcrash";
|
||||
|
||||
var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);
|
||||
browserWindow.WebContents.OnCrashed += async (killed) =>
|
||||
{
|
||||
var options = new MessageBoxOptions("This process has crashed.")
|
||||
{
|
||||
Type = MessageBoxType.info,
|
||||
Title = "Renderer Process Crashed",
|
||||
Buttons = new string[] { "Reload", "Close" }
|
||||
};
|
||||
var result = await Electron.Dialog.ShowMessageBoxAsync(options);
|
||||
|
||||
if (result.Response == 0)
|
||||
{
|
||||
browserWindow.Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
browserWindow.Close();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Electron.IpcMain.On("process-hang", async (args) =>
|
||||
{
|
||||
string viewPath = $"http://localhost:{BridgeSettings.WebPort}/crashhang/processhang";
|
||||
|
||||
var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);
|
||||
browserWindow.OnUnresponsive += async () =>
|
||||
{
|
||||
var options = new MessageBoxOptions("This process is hanging.")
|
||||
{
|
||||
Type = MessageBoxType.info,
|
||||
Title = "Renderer Process Hanging",
|
||||
Buttons = new string[] { "Reload", "Close" }
|
||||
};
|
||||
var result = await Electron.Dialog.ShowMessageBoxAsync(options);
|
||||
|
||||
if (result.Response == 0)
|
||||
{
|
||||
browserWindow.Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
browserWindow.Close();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult ProcessCrash()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult ProcessHang()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
67
ElectronNET.WebApp/Controllers/DialogsController.cs
Normal file
67
ElectronNET.WebApp/Controllers/DialogsController.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ElectronNET.API;
|
||||
using ElectronNET.API.Entities;
|
||||
|
||||
namespace ElectronNET.WebApp.Controllers
|
||||
{
|
||||
public class DialogsController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
Electron.IpcMain.On("select-directory", async (args) => {
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
var options = new OpenDialogOptions {
|
||||
Properties = new OpenDialogProperty[] {
|
||||
OpenDialogProperty.openFile,
|
||||
OpenDialogProperty.openDirectory
|
||||
}
|
||||
};
|
||||
|
||||
string[] files = await Electron.Dialog.ShowOpenDialogAsync(mainWindow, options);
|
||||
Electron.IpcMain.Send(mainWindow, "select-directory-reply", files);
|
||||
});
|
||||
|
||||
Electron.IpcMain.On("error-dialog", (args) =>
|
||||
{
|
||||
Electron.Dialog.ShowErrorBox("An Error Message", "Demonstrating an error message.");
|
||||
});
|
||||
|
||||
Electron.IpcMain.On("information-dialog", async (args) =>
|
||||
{
|
||||
var options = new MessageBoxOptions("This is an information dialog. Isn't it nice?")
|
||||
{
|
||||
Type = MessageBoxType.info,
|
||||
Title = "Information",
|
||||
Buttons = new string[] { "Yes", "No" }
|
||||
};
|
||||
|
||||
var result = await Electron.Dialog.ShowMessageBoxAsync(options);
|
||||
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
Electron.IpcMain.Send(mainWindow, "information-dialog-reply", result.Response);
|
||||
});
|
||||
|
||||
Electron.IpcMain.On("save-dialog", async (args) =>
|
||||
{
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
var options = new SaveDialogOptions
|
||||
{
|
||||
Title = "Save an Image",
|
||||
Filters = new FileFilter[]
|
||||
{
|
||||
new FileFilter { Name = "Images", Extensions = new string[] {"jpg", "png", "gif" } }
|
||||
}
|
||||
};
|
||||
|
||||
var result = await Electron.Dialog.ShowSaveDialogAsync(mainWindow, options);
|
||||
Electron.IpcMain.Send(mainWindow, "save-dialog-reply", result);
|
||||
});
|
||||
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,119 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ElectronNET.API;
|
||||
using ElectronNET.API.Entities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Linq;
|
||||
|
||||
namespace ElectronNET.WebApp.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
{
|
||||
var menu = new MenuItem[] {
|
||||
new MenuItem { Label = "Edit", Submenu = new MenuItem[] {
|
||||
new MenuItem { Label = "Undo", Accelerator = "CmdOrCtrl+Z", Role = MenuRole.undo },
|
||||
new MenuItem { Label = "Redo", Accelerator = "Shift+CmdOrCtrl+Z", Role = MenuRole.redo },
|
||||
new MenuItem { Type = MenuType.separator },
|
||||
new MenuItem { Label = "Cut", Accelerator = "CmdOrCtrl+X", Role = MenuRole.cut },
|
||||
new MenuItem { Label = "Copy", Accelerator = "CmdOrCtrl+C", Role = MenuRole.copy },
|
||||
new MenuItem { Label = "Paste", Accelerator = "CmdOrCtrl+V", Role = MenuRole.paste },
|
||||
new MenuItem { Label = "Select All", Accelerator = "CmdOrCtrl+A", Role = MenuRole.selectall }
|
||||
}
|
||||
},
|
||||
new MenuItem { Label = "View", Submenu = new MenuItem[] {
|
||||
new MenuItem
|
||||
{
|
||||
Label = "Reload",
|
||||
Accelerator = "CmdOrCtrl+R",
|
||||
Click = () =>
|
||||
{
|
||||
// on reload, start fresh and close any old
|
||||
// open secondary windows
|
||||
Electron.WindowManager.BrowserWindows.ToList().ForEach(browserWindow => {
|
||||
if(browserWindow.Id != 1)
|
||||
{
|
||||
browserWindow.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
browserWindow.Reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Label = "Toggle Full Screen",
|
||||
Accelerator = "CmdOrCtrl+F",
|
||||
Click = async () =>
|
||||
{
|
||||
bool isFullScreen = await Electron.WindowManager.BrowserWindows.First().IsFullScreenAsync();
|
||||
Electron.WindowManager.BrowserWindows.First().SetFullScreen(!isFullScreen);
|
||||
}
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Label = "Open Developer Tools",
|
||||
Accelerator = "CmdOrCtrl+I",
|
||||
Click = () => Electron.WindowManager.BrowserWindows.First().WebContents.OpenDevTools()
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Type = MenuType.separator
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Label = "App Menu Demo",
|
||||
Click = async () => {
|
||||
var options = new MessageBoxOptions("This demo is for the Menu section, showing how to create a clickable menu item in the application menu.");
|
||||
options.Type = MessageBoxType.info;
|
||||
options.Title = "Application Menu Demo";
|
||||
await Electron.Dialog.ShowMessageBoxAsync(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new MenuItem { Label = "Window", Role = MenuRole.window, Submenu = new MenuItem[] {
|
||||
new MenuItem { Label = "Minimize", Accelerator = "CmdOrCtrl+M", Role = MenuRole.minimize },
|
||||
new MenuItem { Label = "Close", Accelerator = "CmdOrCtrl+W", Role = MenuRole.close }
|
||||
}
|
||||
},
|
||||
new MenuItem { Label = "Help", Role = MenuRole.help, Submenu = new MenuItem[] {
|
||||
new MenuItem
|
||||
{
|
||||
Label = "Learn More",
|
||||
Click = async () => await Electron.Shell.OpenExternalAsync("https://github.com/ElectronNET")
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Electron.Menu.SetApplicationMenu(menu);
|
||||
|
||||
CreateContextMenu();
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
private void CreateContextMenu()
|
||||
{
|
||||
var menu = new MenuItem[]
|
||||
{
|
||||
new MenuItem
|
||||
{
|
||||
Label = "Hello",
|
||||
Click = async () => await Electron.Dialog.ShowMessageBoxAsync("Electron.NET rocks!")
|
||||
},
|
||||
new MenuItem { Type = MenuType.separator },
|
||||
new MenuItem { Label = "Electron.NET", Type = MenuType.checkbox, Checked = true }
|
||||
};
|
||||
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
Electron.Menu.SetContextMenu(mainWindow, menu);
|
||||
|
||||
Electron.IpcMain.On("show-context-menu", (args) => {
|
||||
Electron.Menu.ContextMenuPopup(mainWindow);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ElectronNET.WebApp/Controllers/IpcController.cs
Normal file
25
ElectronNET.WebApp/Controllers/IpcController.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ElectronNET.API;
|
||||
using System.Linq;
|
||||
|
||||
namespace ElectronNET.WebApp.Controllers
|
||||
{
|
||||
public class IpcController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
Electron.IpcMain.On("async-msg", (args) =>
|
||||
{
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
Electron.IpcMain.Send(mainWindow, "asynchronous-reply", "pong");
|
||||
});
|
||||
|
||||
Electron.IpcMain.OnSync("sync-msg", (args) =>
|
||||
{
|
||||
return "pong";
|
||||
});
|
||||
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
67
ElectronNET.WebApp/Controllers/ManageWindowsController.cs
Normal file
67
ElectronNET.WebApp/Controllers/ManageWindowsController.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ElectronNET.API;
|
||||
using ElectronNET.API.Entities;
|
||||
|
||||
namespace ElectronNET.WebApp.Controllers
|
||||
{
|
||||
public class WindowsController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
string viewPath = $"http://localhost:{BridgeSettings.WebPort}/windows/demowindow";
|
||||
|
||||
Electron.IpcMain.On("new-window", async (args) => {
|
||||
|
||||
await Electron.WindowManager.CreateWindowAsync(viewPath);
|
||||
|
||||
});
|
||||
|
||||
Electron.IpcMain.On("manage-window", async (args) => {
|
||||
|
||||
var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);
|
||||
browserWindow.OnMove += UpdateReply;
|
||||
browserWindow.OnResize += UpdateReply;
|
||||
});
|
||||
|
||||
Electron.IpcMain.On("listen-to-window", async (args) => {
|
||||
var mainBrowserWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
|
||||
var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);
|
||||
browserWindow.OnFocus += () => Electron.IpcMain.Send(mainBrowserWindow, "listen-to-window-focus");
|
||||
browserWindow.OnBlur += () => Electron.IpcMain.Send(mainBrowserWindow, "listen-to-window-blur");
|
||||
|
||||
Electron.IpcMain.On("listen-to-window-set-focus", (x) => browserWindow.Focus());
|
||||
});
|
||||
|
||||
Electron.IpcMain.On("frameless-window", async (args) => {
|
||||
var options = new BrowserWindowOptions
|
||||
{
|
||||
Frame = false
|
||||
};
|
||||
await Electron.WindowManager.CreateWindowAsync(options, viewPath);
|
||||
});
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
private async void UpdateReply()
|
||||
{
|
||||
var browserWindow = Electron.WindowManager.BrowserWindows.Last();
|
||||
var size = await browserWindow.GetSizeAsync();
|
||||
var position = await browserWindow.GetPositionAsync();
|
||||
string message = $"Size: {size[0]},{size[1]} Position: {position[0]},{position[1]}";
|
||||
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
Electron.IpcMain.Send(mainWindow, "manage-window-reply", message);
|
||||
}
|
||||
|
||||
public IActionResult DemoWindow()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
16
ElectronNET.WebApp/Controllers/MenusController.cs
Normal file
16
ElectronNET.WebApp/Controllers/MenusController.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ElectronNET.WebApp.Controllers
|
||||
{
|
||||
public class MenusController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
40
ElectronNET.WebApp/Controllers/NotificationsController.cs
Normal file
40
ElectronNET.WebApp/Controllers/NotificationsController.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ElectronNET.API;
|
||||
using ElectronNET.API.Entities;
|
||||
|
||||
namespace ElectronNET.WebApp.Controllers
|
||||
{
|
||||
public class NotificationsController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
Electron.IpcMain.On("basic-noti", (args) => {
|
||||
|
||||
var options = new NotificationOptions("Basic Notification", "Short message part")
|
||||
{
|
||||
OnClick = async () => await Electron.Dialog.ShowMessageBoxAsync("Notification clicked")
|
||||
};
|
||||
|
||||
Electron.Notification.Show(options);
|
||||
|
||||
});
|
||||
|
||||
Electron.IpcMain.On("advanced-noti", (args) => {
|
||||
|
||||
var options = new NotificationOptions("Notification with image", "Short message plus a custom image")
|
||||
{
|
||||
OnClick = async () => await Electron.Dialog.ShowMessageBoxAsync("Notification clicked"),
|
||||
Icon = "/assets/img/programming.png"
|
||||
};
|
||||
|
||||
Electron.Notification.Show(options);
|
||||
});
|
||||
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
27
ElectronNET.WebApp/Controllers/ShellController.cs
Normal file
27
ElectronNET.WebApp/Controllers/ShellController.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using ElectronNET.API;
|
||||
using ElectronNET.API.Entities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ElectronNET.WebApp.Controllers
|
||||
{
|
||||
public class ShellController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
Electron.IpcMain.On("open-file-manager", async (args) => {
|
||||
|
||||
string path = await Electron.App.GetPathAsync(PathName.home);
|
||||
await Electron.Shell.ShowItemInFolderAsync(path);
|
||||
|
||||
});
|
||||
|
||||
Electron.IpcMain.On("open-ex-links", async (args) => {
|
||||
|
||||
await Electron.Shell.OpenExternalAsync("https://github.com/ElectronNET");
|
||||
|
||||
});
|
||||
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
26
ElectronNET.WebApp/Controllers/ShortcutsController.cs
Normal file
26
ElectronNET.WebApp/Controllers/ShortcutsController.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using ElectronNET.API;
|
||||
using ElectronNET.API.Entities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ElectronNET.WebApp.Controllers
|
||||
{
|
||||
public class ShortcutsController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
Electron.GlobalShortcut.Register("CommandOrControl+Alt+K", async () => {
|
||||
var options = new MessageBoxOptions("You pressed the registered global shortcut keybinding.")
|
||||
{
|
||||
Type = MessageBoxType.info,
|
||||
Title = "Success!"
|
||||
};
|
||||
|
||||
await Electron.Dialog.ShowMessageBoxAsync(options);
|
||||
});
|
||||
|
||||
Electron.App.WillQuit += () => Electron.GlobalShortcut.UnregisterAll();
|
||||
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
34
ElectronNET.WebApp/Controllers/TrayController.cs
Normal file
34
ElectronNET.WebApp/Controllers/TrayController.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ElectronNET.API;
|
||||
using ElectronNET.API.Entities;
|
||||
|
||||
namespace ElectronNET.WebApp.Controllers
|
||||
{
|
||||
public class TrayController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
Electron.IpcMain.On("put-in-tray", (args) => {
|
||||
|
||||
if (Electron.Tray.Items.Count == 0)
|
||||
{
|
||||
var menu = new MenuItem
|
||||
{
|
||||
Label = "Remove",
|
||||
Click = () => Electron.Tray.Destroy()
|
||||
};
|
||||
|
||||
Electron.Tray.Show("/Assets/electron_32x32.png", menu);
|
||||
Electron.Tray.SetToolTip("Electron Demo in the tray.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Electron.Tray.Destroy();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ElectronNET.API;
|
||||
using ElectronNET.API.Entities;
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Controllers\ManageWindowsController.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="Views\Windows\HandleErrorCrashes.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Assets\" />
|
||||
<Folder Include="wwwroot\assets\" />
|
||||
|
||||
113
ElectronNET.WebApp/Views/CrashHang/Index.cshtml
Normal file
113
ElectronNET.WebApp/Views/CrashHang/Index.cshtml
Normal file
@@ -0,0 +1,113 @@
|
||||
<template class="task-template">
|
||||
<section id="crash-hang-section" class="section js-section u-category-windows">
|
||||
<header class="section-header">
|
||||
<div class="section-wrapper">
|
||||
<h1>
|
||||
<svg class="section-icon"><use xlink:href="assets/img/icons.svg#icon-windows"></use></svg>
|
||||
Handling Window Crashes and Hangs
|
||||
</h1>
|
||||
<h3>The <code>Electron.WindowManager</code> will emit events when the renderer process crashes or hangs. You can listen for these events and give users the chance to reload, wait or close that window.</h3>
|
||||
|
||||
<p>You find the sample source code in <code>Controllers\CrashHangController.cs</code>.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="new-window-crashes-demo-toggle" class="js-container-target demo-toggle-button">Relaunch window after the process crashes
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="process-crash">View Demo</button>
|
||||
</div>
|
||||
<p>In this demo we create a new window and provide a link that will force a crash using <code>process.crash()</code>.</p>
|
||||
<p>The window is listening for the crash event and when the event occurs it prompts the user with two options: reload or close.</p>
|
||||
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="csharp">var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath);
|
||||
browserWindow.WebContents.OnCrashed += async (killed) => {
|
||||
var options = new MessageBoxOptions("This process has crashed.") {
|
||||
Type = MessageBoxType.info,
|
||||
Title = "Renderer Process Crashed",
|
||||
Buttons = new string[] { "Reload", "Close" }
|
||||
};
|
||||
var result = await Electron.Dialog.ShowMessageBoxAsync(options);
|
||||
|
||||
if (result.Response == 0)
|
||||
{
|
||||
browserWindow.Reload();
|
||||
} else
|
||||
{
|
||||
browserWindow.Close();
|
||||
}
|
||||
};</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="new-window-hangs-demo-toggle" class="js-container-target demo-toggle-button">Relaunch window after the process hangs
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="process-hang">View Demo</button>
|
||||
</div>
|
||||
<p>In this demo we create a new window and provide a link that will force the process to hang using <code>process.hang()</code>.</p>
|
||||
<p>The window is listening for the process to become officially unresponsive (this can take up to 30 seconds). When this event occurs it prompts the user with two options: reload or close.</p>
|
||||
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="csharp">var browserWindow = await Electron.WindowManager.CreateWindowAsync();
|
||||
browserWindow.OnUnresponsive += async () => {
|
||||
var options = new MessageBoxOptions("This process is hanging.")
|
||||
{
|
||||
Type = MessageBoxType.info,
|
||||
Title = "Renderer Process Hanging",
|
||||
Buttons = new string[] { "Reload", "Close" }
|
||||
};
|
||||
var result = await Electron.Dialog.ShowMessageBoxAsync(options);
|
||||
|
||||
if (result.Response == 0)
|
||||
{
|
||||
browserWindow.Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
browserWindow.Close();
|
||||
}
|
||||
};</code></pre>
|
||||
|
||||
<div class="demo-protip">
|
||||
<h2>ProTip</h2>
|
||||
<strong>Wait for the process to become responsive again.</strong>
|
||||
<p>A third option in the case of a process that is hanging is to wait and see if the problem resolves, allowing the process to become responsive again. To do this, use the <code>BrowserWindow</code> event 'OnResponsive' as shown below.</p>
|
||||
<pre><code class="csharp">browserWindow.OnResponsive += () =>
|
||||
{
|
||||
// Do something when the window is responsive again
|
||||
};</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
(function(){
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("process-crash").addEventListener("click", () => {
|
||||
ipcRenderer.send("process-crash");
|
||||
});
|
||||
|
||||
document.getElementById("process-hang").addEventListener("click", () => {
|
||||
ipcRenderer.send("process-hang");
|
||||
});
|
||||
|
||||
}());
|
||||
</script>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
24
ElectronNET.WebApp/Views/CrashHang/ProcessCrash.cshtml
Normal file
24
ElectronNET.WebApp/Views/CrashHang/ProcessCrash.cshtml
Normal file
@@ -0,0 +1,24 @@
|
||||
<style>
|
||||
body {
|
||||
padding: 20px;
|
||||
font-family: system, -apple-system, '.SFNSText-Regular', 'SF UI Text', 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif;
|
||||
color: #fff;
|
||||
background-color: #8aba87;
|
||||
text-align: center;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
#crash {
|
||||
color: white;
|
||||
opacity: 0.7;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Click the text below to crash and then reload this process.</p>
|
||||
<a id="crash" href="javascript:process.crash()">Crash this process</a>
|
||||
29
ElectronNET.WebApp/Views/CrashHang/ProcessHang.cshtml
Normal file
29
ElectronNET.WebApp/Views/CrashHang/ProcessHang.cshtml
Normal file
@@ -0,0 +1,29 @@
|
||||
<style>
|
||||
body {
|
||||
padding: 20px;
|
||||
font-family: system, -apple-system, '.SFNSText-Regular', 'SF UI Text', 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif;
|
||||
color: #fff;
|
||||
background-color: #8aba87;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
#crash {
|
||||
color: white;
|
||||
opacity: 0.7;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>Click the text below to hang and then reload this process.</p>
|
||||
<small>(This will take up to 30 seconds.)</small>
|
||||
|
||||
<a id="crash" href="javascript:process.hang()">Hang this process</a>
|
||||
222
ElectronNET.WebApp/Views/Dialogs/Index.cshtml
Normal file
222
ElectronNET.WebApp/Views/Dialogs/Index.cshtml
Normal file
@@ -0,0 +1,222 @@
|
||||
<template class="task-template">
|
||||
<section id="dialogs-section" class="section js-section u-category-native-ui">
|
||||
<header class="section-header">
|
||||
<div class="section-wrapper">
|
||||
<h1>
|
||||
<svg class="section-icon"><use xlink:href="assets/img/icons.svg#icon-native-ui"></use></svg>
|
||||
Use system dialogs
|
||||
</h1>
|
||||
<h3>The <code>Electron.Dialog</code> in Electron.NET allows you to use native system dialogs for opening files or directories, saving a file or displaying informational messages.</h3>
|
||||
|
||||
<p>This is a main process module because this process is more efficient with native utilities and it allows the call to happen without interupting the visible elements in your page's renderer process.</p>
|
||||
|
||||
<p>You find the sample source code in <code>Controllers\DialogsController.cs</code>.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="open-file-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Open a File or Directory
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="select-directory">View Demo</button>
|
||||
<span class="demo-response" id="selected-file"></span>
|
||||
</div>
|
||||
<p>In this demo, the <code>ipcRenderer</code> is used to send a message from the renderer process instructing the main process to launch the open file (or directory) dialog. If a file is selected, the main process can send that information back to the renderer process.</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="language-js">const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("select-directory").addEventListener("click", () => {
|
||||
ipcRenderer.send("select-directory");
|
||||
});
|
||||
|
||||
ipcRenderer.on("select-directory-reply", (sender, path) => {
|
||||
document.getElementById("selected-file").innerText = `You selected: ${path}`;;
|
||||
});</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code class="csharp">Electron.IpcMain.On("select-directory", async (args) => {
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
var options = new OpenDialogOptions {
|
||||
Properties = new OpenDialogProperty[] {
|
||||
OpenDialogProperty.openFile,
|
||||
OpenDialogProperty.openDirectory
|
||||
}
|
||||
};
|
||||
|
||||
string[] files = await Electron.Dialog.ShowOpenDialogAsync(mainWindow, options);
|
||||
Electron.IpcMain.Send(mainWindow, "select-directory-reply", files);
|
||||
});</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="error-dialog-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Error Dialog
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button id="error-dialog" class="demo-button">View Demo</button>
|
||||
</div>
|
||||
<p>In this demo, the <code>ipcRenderer</code> is used to send a message from the renderer process instructing the main process to launch the error dialog.</p>
|
||||
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="language-js">const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("error-dialog").addEventListener("click", () => {
|
||||
ipcRenderer.send("error-dialog");
|
||||
});</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code class="csharp">Electron.IpcMain.On("error-dialog", (args) =>
|
||||
{
|
||||
Electron.Dialog.ShowErrorBox("An Error Message", "Demonstrating an error message.");
|
||||
});</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="information-dialog-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Information Dialog
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="information-dialog">View Demo</button>
|
||||
<span class="demo-response" id="info-selection"></span>
|
||||
</div>
|
||||
<p>In this demo, the <code>ipcRenderer</code> is used to send a message from the renderer process instructing the main process to launch the information dialog. Options may be provided for responses which can then be relayed back to the renderer process.</p>
|
||||
|
||||
<p>Note: The <code>title</code> property is not displayed in macOS.</p>
|
||||
|
||||
<p>An information dialog can contain an icon, your choice of buttons, title and message.</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="javascript">document.getElementById("information-dialog").addEventListener("click", () => {
|
||||
ipcRenderer.send("information-dialog");
|
||||
});
|
||||
|
||||
ipcRenderer.on("information-dialog-reply", (sender, index) => {
|
||||
let message = 'You selected ';
|
||||
|
||||
if(index == 0) {
|
||||
message += 'yes.'
|
||||
} else {
|
||||
message += 'no.'
|
||||
}
|
||||
|
||||
document.getElementById("info-selection").innerText = message;
|
||||
});</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code class="csharp">Electron.IpcMain.On("information-dialog", async (args) =>
|
||||
{
|
||||
var options = new MessageBoxOptions("This is an information dialog. Isn't it nice?")
|
||||
{
|
||||
Type = MessageBoxType.info,
|
||||
Title = "Information",
|
||||
Buttons = new string[] { "Yes", "No" }
|
||||
};
|
||||
|
||||
var result = await Electron.Dialog.ShowMessageBoxAsync(options);
|
||||
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
Electron.IpcMain.Send(mainWindow, "information-dialog-reply", result.Response);
|
||||
});</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="save-dialog-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Save Dialog
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="save-dialog">View Demo</button>
|
||||
<span class="demo-response" id="file-saved"></span>
|
||||
</div>
|
||||
<p>In this demo, the <code>ipcRenderer</code> is used to send a message from the renderer process instructing the main process to launch the save dialog. It returns the path selected by the user which can be relayed back to the renderer process.</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="javascript">const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("save-dialog").addEventListener("click", () => {
|
||||
ipcRenderer.send("save-dialog");
|
||||
});
|
||||
|
||||
ipcRenderer.on("save-dialog-reply", (sender, path) => {
|
||||
if (!path) path = 'No path';
|
||||
document.getElementById('file-saved').innerHTML = `Path selected: ${path}`;
|
||||
});</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code class="csharp">Electron.IpcMain.On("save-dialog", async (args) =>
|
||||
{
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
var options = new SaveDialogOptions
|
||||
{
|
||||
Title = "Save an Image",
|
||||
Filters = new FileFilter[]
|
||||
{
|
||||
new FileFilter { Name = "Images", Extensions = new string[] {"jpg", "png", "gif" } }
|
||||
}
|
||||
};
|
||||
|
||||
var result = await Electron.Dialog.ShowSaveDialogAsync(mainWindow, options);
|
||||
Electron.IpcMain.Send(mainWindow, "save-dialog-reply", result);
|
||||
});</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("select-directory").addEventListener("click", () => {
|
||||
ipcRenderer.send("select-directory");
|
||||
});
|
||||
|
||||
ipcRenderer.on("select-directory-reply", (sender, path) => {
|
||||
document.getElementById("selected-file").innerText = `You selected: ${path}`;
|
||||
});
|
||||
|
||||
document.getElementById("error-dialog").addEventListener("click", () => {
|
||||
ipcRenderer.send("error-dialog");
|
||||
});
|
||||
|
||||
document.getElementById("information-dialog").addEventListener("click", () => {
|
||||
ipcRenderer.send("information-dialog");
|
||||
});
|
||||
|
||||
ipcRenderer.on("information-dialog-reply", (sender, index) => {
|
||||
let message = 'You selected ';
|
||||
|
||||
if(index == 0) {
|
||||
message += 'yes.'
|
||||
} else {
|
||||
message += 'no.'
|
||||
}
|
||||
|
||||
document.getElementById("info-selection").innerText = message;
|
||||
});
|
||||
|
||||
document.getElementById("save-dialog").addEventListener("click", () => {
|
||||
ipcRenderer.send("save-dialog");
|
||||
});
|
||||
|
||||
ipcRenderer.on("save-dialog-reply", (sender, path) => {
|
||||
if (!path) path = 'No path';
|
||||
document.getElementById('file-saved').innerHTML = `Path selected: ${path}`;
|
||||
});
|
||||
|
||||
}());
|
||||
</script>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
@@ -14,6 +14,14 @@
|
||||
|
||||
<link rel="import" href="about">
|
||||
<link rel="import" href="windows">
|
||||
<link rel="import" href="crashhang">
|
||||
<link rel="import" href="menus">
|
||||
<link rel="import" href="shortcuts">
|
||||
<link rel="import" href="shell">
|
||||
<link rel="import" href="notifications">
|
||||
<link rel="import" href="dialogs">
|
||||
<link rel="import" href="tray">
|
||||
<link rel="import" href="ipc">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
104
ElectronNET.WebApp/Views/Ipc/Index.cshtml
Normal file
104
ElectronNET.WebApp/Views/Ipc/Index.cshtml
Normal file
@@ -0,0 +1,104 @@
|
||||
<template class="task-template">
|
||||
<section id="ipc-section" class="section js-section u-category-communication">
|
||||
<header class="communication">
|
||||
<div class="section-wrapper">
|
||||
<h1>
|
||||
<svg class="section-icon"><use xlink:href="assets/img/icons.svg#icon-communication"></use></svg>
|
||||
Communication between processes
|
||||
</h1>
|
||||
<h3>The <code>ipc</code> (inter-process communication) module allows you to send and receive synchronous and asynchronous messages between the main and renderer processes.</h3>
|
||||
|
||||
<p>There is a version of this module available for both processes: <code>Electron.IpcMain</code> and <code>ipcRenderer</code>.</p>
|
||||
<p>You find the sample source code in <code>Controllers\IpcController.cs</code>.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="async-msg-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Asynchronous messages
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Both</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="async-msg">Ping</button>
|
||||
<span class="demo-response" id="async-reply"></span>
|
||||
</div>
|
||||
<p>Using <code>ipc</code> to send messages between processes asynchronously is the preferred method since it will return when finished without blocking other operations in the same process.</p>
|
||||
|
||||
<p>This example sends a "ping" from this process (renderer) to the main process. The main process then replies with "pong".</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="javascript">const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("async-msg").addEventListener("click", () => {
|
||||
ipcRenderer.send("async-msg", 'ping');
|
||||
});
|
||||
|
||||
ipcRenderer.on('asynchronous-reply', (event, arg) => {
|
||||
const message = `Asynchronous message reply: ${arg}`;
|
||||
document.getElementById('async-reply').innerHTML = message;
|
||||
});</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code class="csharp">Electron.IpcMain.On("async-msg", (args) =>
|
||||
{
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
Electron.IpcMain.Send(mainWindow, "asynchronous-reply", "pong");
|
||||
});</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="sync-msg-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Synchronous messages
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Both</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="sync-msg">Ping</button>
|
||||
<span class="demo-response" id="sync-reply"></span>
|
||||
</div>
|
||||
<p>You can use the <code>ipc</code> module to send synchronous messages between processes as well, but note that the synchronous nature of this method means that it <b>will block</b> other operations while completing its task.</p>
|
||||
<p>This example sends a synchronous message, "ping", from this process (renderer) to the main process. The main process then replies with "pong".</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="javascript">const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("sync-msg").addEventListener("click", () => {
|
||||
const reply = ipcRenderer.sendSync("sync-msg", "ping");
|
||||
const message = `Synchronous message reply: ${reply}`;
|
||||
document.getElementById('sync-reply').innerHTML = message;
|
||||
});</code></pre>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code class="csharp">Electron.IpcMain.OnSync("sync-msg", (args) =>
|
||||
{
|
||||
return "pong";
|
||||
});</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("async-msg").addEventListener("click", () => {
|
||||
ipcRenderer.send("async-msg", 'ping');
|
||||
});
|
||||
|
||||
ipcRenderer.on('asynchronous-reply', (event, arg) => {
|
||||
const message = `Asynchronous message reply: ${arg}`;
|
||||
document.getElementById('async-reply').innerHTML = message;
|
||||
});
|
||||
|
||||
document.getElementById("sync-msg").addEventListener("click", () => {
|
||||
const reply = ipcRenderer.sendSync("sync-msg", "ping");
|
||||
const message = `Synchronous message reply: ${reply}`;
|
||||
document.getElementById('sync-reply').innerHTML = message;
|
||||
});
|
||||
|
||||
}());
|
||||
</script>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
189
ElectronNET.WebApp/Views/Menus/Index.cshtml
Normal file
189
ElectronNET.WebApp/Views/Menus/Index.cshtml
Normal file
@@ -0,0 +1,189 @@
|
||||
<template class="task-template">
|
||||
<section id="menus-section" class="section js-section u-category-menu">
|
||||
<header class="section-header">
|
||||
<div class="section-wrapper">
|
||||
<h1>
|
||||
<svg class="section-icon"><use xlink:href="assets/img/icons.svg#icon-menu"></use></svg>
|
||||
Customize Menus
|
||||
</h1>
|
||||
<h3>The <code>Electron.Menu</code> and <code>MenuItem</code> can be used to create custom native menus.</h3>
|
||||
|
||||
<p>There are two kinds of menus: the application (top) menu and context (right-click) menu.</p>
|
||||
|
||||
<p>You find the sample source code in <code>Controllers\HomeController.cs</code>.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="application-menu-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Create an application menu
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<p>The <code>Electron.Menu</code> and <code>MenuItem</code> allow you to customize your application menu. If you don't set any menu, Electron will generate a minimal menu for your app by default.</p>
|
||||
|
||||
<p>This app uses the code below to set the application menu. If you click the 'View' option in the application menu and then the 'App Menu Demo', you'll see an information box displayed.</p>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code class="csharp">var menu = new MenuItem[] {
|
||||
new MenuItem { Label = "Edit", Submenu = new MenuItem[] {
|
||||
new MenuItem { Label = "Undo", Accelerator = "CmdOrCtrl+Z", Role = MenuRole.undo },
|
||||
new MenuItem { Label = "Redo", Accelerator = "Shift+CmdOrCtrl+Z", Role = MenuRole.redo },
|
||||
new MenuItem { Type = MenuType.separator },
|
||||
new MenuItem { Label = "Cut", Accelerator = "CmdOrCtrl+X", Role = MenuRole.cut },
|
||||
new MenuItem { Label = "Copy", Accelerator = "CmdOrCtrl+C", Role = MenuRole.copy },
|
||||
new MenuItem { Label = "Paste", Accelerator = "CmdOrCtrl+V", Role = MenuRole.paste },
|
||||
new MenuItem { Label = "Select All", Accelerator = "CmdOrCtrl+A", Role = MenuRole.selectall }
|
||||
}
|
||||
},
|
||||
new MenuItem { Label = "View", Submenu = new MenuItem[] {
|
||||
new MenuItem
|
||||
{
|
||||
Label = "Reload",
|
||||
Accelerator = "CmdOrCtrl+R",
|
||||
Click = () =>
|
||||
{
|
||||
// on reload, start fresh and close any old
|
||||
// open secondary windows
|
||||
Electron.WindowManager.BrowserWindows.ToList().ForEach(browserWindow => {
|
||||
if(browserWindow.Id != 1)
|
||||
{
|
||||
browserWindow.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
browserWindow.Reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Label = "Toggle Full Screen",
|
||||
Accelerator = "CmdOrCtrl+F",
|
||||
Click = async () =>
|
||||
{
|
||||
bool isFullScreen = await Electron.WindowManager.BrowserWindows.First().IsFullScreenAsync();
|
||||
Electron.WindowManager.BrowserWindows.First().SetFullScreen(!isFullScreen);
|
||||
}
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Label = "Open Developer Tools",
|
||||
Accelerator = "CmdOrCtrl+I",
|
||||
Click = () => Electron.WindowManager.BrowserWindows.First().WebContents.OpenDevTools()
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Type = MenuType.separator
|
||||
},
|
||||
new MenuItem
|
||||
{
|
||||
Label = "App Menu Demo",
|
||||
Click = async () => {
|
||||
var options = new MessageBoxOptions("This demo is for the Menu section, showing how to create a clickable menu item in the application menu.");
|
||||
options.Type = MessageBoxType.info;
|
||||
options.Title = "Application Menu Demo";
|
||||
await Electron.Dialog.ShowMessageBoxAsync(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new MenuItem { Label = "Window", Role = MenuRole.window, Submenu = new MenuItem[] {
|
||||
new MenuItem { Label = "Minimize", Accelerator = "CmdOrCtrl+M", Role = MenuRole.minimize },
|
||||
new MenuItem { Label = "Close", Accelerator = "CmdOrCtrl+W", Role = MenuRole.close }
|
||||
}
|
||||
},
|
||||
new MenuItem { Label = "Help", Role = MenuRole.help, Submenu = new MenuItem[] {
|
||||
new MenuItem
|
||||
{
|
||||
Label = "Learn More",
|
||||
Click = async () => await Electron.Shell.OpenExternalAsync("https://github.com/ElectronNET")
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Electron.Menu.SetApplicationMenu(menu);</code></pre>
|
||||
|
||||
<div class="demo-protip">
|
||||
<h2>ProTip</h2>
|
||||
<strong>Know operating system menu differences.</strong>
|
||||
<p>When designing an app for multiple operating systems it's important to be mindful of the ways application menu conventions differ on each operating system.</p>
|
||||
<p>For instance, on Windows, accelerators are set with an <code>&</code>. Naming conventions also vary, like between "Settings" or "Preferences". Below are resources for learning operating system specific standards.</p>
|
||||
<ul>
|
||||
<li><a href="https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/MenuBarMenus.html#//apple_ref/doc/uid/20000957-CH29-SW1">macOS<span class="u-visible-to-screen-reader">(opens in new window)</span></a></li>
|
||||
<li><a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb226797(v=vs.85).aspx">Windows<span class="u-visible-to-screen-reader">(opens in new window)</span></a></li>
|
||||
<li><a href="https://developer.gnome.org/hig/stable/menu-bars.html.en">Linux<span class="u-visible-to-screen-reader">(opens in new window)</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="context-menu-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Create a context menu
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="context-menu">View Demo</button>
|
||||
</div>
|
||||
<p>A context, or right-click, menu can be created with the <code>Electron.Menu.SetContextMenu()</code> and <code>MenuItem</code> as well. You can right-click anywhere in this app or click the demo button to see an example context menu.</p>
|
||||
|
||||
<p>In this demo we use the <code>ipcRenderer</code> module to show the context menu when explicitly calling it from the renderer process.</p>
|
||||
<p>See the full <a href="http://electron.atom.io/docs/api/web-contents/#event-context-menu">context-menu event documentation</a> for all the available properties.</p>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code class="csharp">var menu = new MenuItem[]
|
||||
{
|
||||
new MenuItem
|
||||
{
|
||||
Label = "Hello",
|
||||
Click = async () => await Electron.Dialog.ShowMessageBoxAsync("Electron.NET rocks!")
|
||||
},
|
||||
new MenuItem { Type = MenuType.separator },
|
||||
new MenuItem { Label = "Electron.NET", Type = MenuType.checkbox, Checked = true }
|
||||
};
|
||||
|
||||
var mainWindow = Electron.WindowManager.BrowserWindows.First();
|
||||
Electron.Menu.SetContextMenu(mainWindow, menu);
|
||||
|
||||
Electron.IpcMain.On("show-context-menu", (args) => {
|
||||
Electron.Menu.ContextMenuPopup(mainWindow);
|
||||
});</code></pre>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="javascript">const { ipcRenderer } = require("electron");
|
||||
|
||||
window.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault()
|
||||
ipcRenderer.send('show-context-menu');
|
||||
}, false);</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function(){
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("process-crash").addEventListener("click", () => {
|
||||
ipcRenderer.send("process-crash");
|
||||
});
|
||||
|
||||
const contextMenuBtn = document.getElementById('context-menu')
|
||||
contextMenuBtn.addEventListener('click', function () {
|
||||
ipcRenderer.send('show-context-menu');
|
||||
})
|
||||
|
||||
window.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault()
|
||||
ipcRenderer.send('show-context-menu');
|
||||
}, false);
|
||||
|
||||
}());
|
||||
</script>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
78
ElectronNET.WebApp/Views/Notifications/Index.cshtml
Normal file
78
ElectronNET.WebApp/Views/Notifications/Index.cshtml
Normal file
@@ -0,0 +1,78 @@
|
||||
<template class="task-template">
|
||||
<section id="notifications-section" class="section js-section u-category-native-ui">
|
||||
<header class="notifications">
|
||||
<div class="section-wrapper">
|
||||
<h1>
|
||||
<svg class="section-icon"><use xlink:href="assets/img/icons.svg#icon-notification"></use></svg>
|
||||
Desktop notifications
|
||||
</h1>
|
||||
<h3>The <code>Electron.Notification</code> in Electron.NET allows you to add basic desktop notifications.</h3>
|
||||
|
||||
<p>Electron conveniently allows developers to send notifications with the <a href="https://notifications.spec.whatwg.org/">HTML5 Notification API</a>, using the currently running operating system’s native notification APIs to display it.</p>
|
||||
|
||||
<p><b>Note:</b> Since this is an HTML5 API it is only available in the renderer process.</p>
|
||||
|
||||
<p>You find the sample source code in <code>Controllers\NotificationsController.cs</code>.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="basic-notification-demo-toggle" class="js-container-target demo-toggle-button">Basic notification
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win 7+, macOS, Linux (that supports libnotify)<span class="demo-meta-divider">|</span> Process: Renderer</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="basic-noti">View demo</button>
|
||||
</div>
|
||||
<p>This demo demonstrates a basic notification. Text only.</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="csharp">var options = new NotificationOptions("Basic Notification", "Short message part")
|
||||
{
|
||||
OnClick = async () => await Electron.Dialog.ShowMessageBoxAsync("Notification clicked")
|
||||
};
|
||||
|
||||
Electron.Notification.Show(options);</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="advanced-notification-demo-toggle" class="js-container-target demo-toggle-button">Notification with image
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win 7+, macOS, Linux (that supports libnotify) <span class="demo-meta-divider">|</span> Process: Renderer</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="advanced-noti">View demo</button>
|
||||
</div>
|
||||
<p>This demo demonstrates a basic notification. Both text and a image</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="csharp">var options = new NotificationOptions("Notification with image", "Short message plus a custom image")
|
||||
{
|
||||
OnClick = async () => await Electron.Dialog.ShowMessageBoxAsync("Notification clicked"),
|
||||
Icon = "/assets/img/programming.png"
|
||||
};
|
||||
|
||||
Electron.Notification.Show(options);</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function(){
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("basic-noti").addEventListener("click", () => {
|
||||
ipcRenderer.send("basic-noti");
|
||||
});
|
||||
|
||||
document.getElementById("advanced-noti").addEventListener("click", () => {
|
||||
ipcRenderer.send("advanced-noti");
|
||||
});
|
||||
|
||||
}());
|
||||
</script>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
71
ElectronNET.WebApp/Views/Shell/Index.cshtml
Normal file
71
ElectronNET.WebApp/Views/Shell/Index.cshtml
Normal file
@@ -0,0 +1,71 @@
|
||||
<template class="task-template">
|
||||
<section id="ex-links-file-manager-section" class="section js-section u-category-native-ui">
|
||||
<header class="section-header">
|
||||
<div class="section-wrapper">
|
||||
<h1>
|
||||
<svg class="section-icon"><use xlink:href="assets/img/icons.svg#icon-native-ui"></use></svg>
|
||||
Open external links and the file manager
|
||||
</h1>
|
||||
<h3>The <code>Electron.Shell</code> in Electron.NET allows you to access certain native elements like the file manager and default web browser.</h3>
|
||||
|
||||
<p>This module works in both the main and renderer process.</p>
|
||||
|
||||
<p>You find the sample source code in <code>Controllers\ShellController.cs</code>.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="open-file-manager-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Open Path in File Manager
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Both</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="open-file-manager">View Demo</button>
|
||||
</div>
|
||||
<p>This demonstrates using the <code>Electron.Shell</code> to open the system file manager at a particular location.</p>
|
||||
<p>Clicking the demo button will open your file manager at the root.</p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="csharp">string path = await Electron.App.GetPathAsync(PathName.home);
|
||||
await Electron.Shell.ShowItemInFolderAsync(path);</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="open-ex-links-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Open External Links
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Both</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="open-ex-links">View Demo</button>
|
||||
</div>
|
||||
<p>If you do not want your app to open website links <em>within</em> the app, you can use the <code>Electron.Shell</code> to open them externally. When clicked, the links will open outside of your app and in the user's default web browser.</p>
|
||||
<p>When the demo button is clicked, the electron website will open in your browser.<p>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="csharp">await Electron.Shell.OpenExternalAsync("https://github.com/ElectronNET");</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("open-file-manager").addEventListener("click", () => {
|
||||
ipcRenderer.send("open-file-manager");
|
||||
});
|
||||
|
||||
document.getElementById("open-ex-links").addEventListener("click", () => {
|
||||
ipcRenderer.send("open-ex-links");
|
||||
});
|
||||
|
||||
}());
|
||||
</script>
|
||||
|
||||
|
||||
</section>
|
||||
</template>
|
||||
74
ElectronNET.WebApp/Views/Shortcuts/Index.cshtml
Normal file
74
ElectronNET.WebApp/Views/Shortcuts/Index.cshtml
Normal file
@@ -0,0 +1,74 @@
|
||||
<template class="task-template">
|
||||
<section id="shortcuts-section" class="section js-section u-category-menu">
|
||||
<header class="section-header">
|
||||
<div class="section-wrapper">
|
||||
<h1>
|
||||
<svg class="section-icon"><use xlink:href="assets/img/icons.svg#icon-menu"></use></svg>
|
||||
Keyboard Shortcuts
|
||||
</h1>
|
||||
|
||||
<h3>The <code>Electron.GlobalShortcut</code> and <code>MenuItem</code> can be used to define keyboard shortcuts.</h3>
|
||||
|
||||
<p>
|
||||
In Electron.NET, keyboard shortcuts are called accelerators.
|
||||
They can be assigned to actions in your application's Menu,
|
||||
or they can be assigned globally so they'll be triggered even when
|
||||
your app doesn't have keyboard focus.
|
||||
</p>
|
||||
|
||||
<p>You find the sample source code in <code>Controllers\ShortcutsController.cs</code>.</p>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="shortcuts-demo-toggle" class="js-container-target demo-toggle-button">Register a global keyboard shortcut
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux <span class="demo-meta-divider">|</span> Process: Main</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<p>
|
||||
To try this demo, press <kbd class="normalize-to-platform">CommandOrControl+Alt+K</kbd> on your keyboard.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Global shortcuts are detected even when the app doesn't have
|
||||
keyboard focus.
|
||||
</p>
|
||||
|
||||
<h5>Main Process</h5>
|
||||
<pre><code class="csharp">Electron.GlobalShortcut.Register("CommandOrControl+Alt+K", async () => {
|
||||
var options = new MessageBoxOptions("You pressed the registered global shortcut keybinding.")
|
||||
{
|
||||
Type = MessageBoxType.info,
|
||||
Title = "Success!"
|
||||
};
|
||||
|
||||
await Electron.Dialog.ShowMessageBoxAsync(options);
|
||||
});
|
||||
|
||||
Electron.App.WillQuit += () => Electron.GlobalShortcut.UnregisterAll();</code></pre>
|
||||
|
||||
<div class="demo-protip">
|
||||
<h2>ProTip</h2>
|
||||
<strong>Avoid overriding system-wide keyboard shortcuts.</strong>
|
||||
<p>
|
||||
When registering global shortcuts, it's important to be aware of
|
||||
existing defaults in the target operating system, so as not to
|
||||
override any existing behaviors. For an overview of each
|
||||
operating system's keyboard shortcuts, view these documents:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><a class="u-exlink" href="https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/Keyboard.html">macOS</a></li>
|
||||
<li><a class="u-exlink" href="http://windows.microsoft.com/en-us/windows-10/keyboard-shortcuts">Windows</a></li>
|
||||
<li><a class="u-exlink" href="https://developer.gnome.org/hig/stable/keyboard-input.html.en">Linux</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
100
ElectronNET.WebApp/Views/Tray/Index.cshtml
Normal file
100
ElectronNET.WebApp/Views/Tray/Index.cshtml
Normal file
@@ -0,0 +1,100 @@
|
||||
<template class="task-template">
|
||||
<section id="tray-section" class="section js-section u-category-native-ui">
|
||||
<header class="section-header">
|
||||
<div class="section-wrapper">
|
||||
<h1>
|
||||
<svg class="section-icon"><use xlink:href="assets/img/icons.svg#icon-native-ui"></use></svg>
|
||||
Tray
|
||||
</h1>
|
||||
<h3>The <code>Electron.Tray</code> allows you to create an icon in the operating system's notification area.</h3>
|
||||
<p>This icon can also have a context menu attached.</p>
|
||||
|
||||
<p>You find the sample source code in <code>Controllers\TrayController.cs</code>.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="demo">
|
||||
<div class="demo-wrapper">
|
||||
<button id="tray-demo-toggle" class="js-container-target demo-toggle-button">
|
||||
Tray
|
||||
<div class="demo-meta u-avoid-clicks">Supports: Win, macOS, Linux | Process: Main</div>
|
||||
</button>
|
||||
<div class="demo-box">
|
||||
<div class="demo-controls">
|
||||
<button class="demo-button" id="put-in-tray">View Demo</button>
|
||||
<span class="demo-response" id="tray-countdown"></span>
|
||||
</div>
|
||||
<p>The demo button sends a message to the main process using the <code>ipcRenderer</code>. In the main process the app is told to place an icon, with a context menu, in the tray.</p>
|
||||
|
||||
<p>In this example the tray icon can be removed by clicking 'Remove' in the context menu or selecting the demo button again.</p>
|
||||
<h5>Main Process</h5>
|
||||
<pre><code class="csharp">Electron.IpcMain.On("put-in-tray", (args) => {
|
||||
|
||||
if (Electron.Tray.Items.Count == 0)
|
||||
{
|
||||
var menu = new MenuItem
|
||||
{
|
||||
Label = "Remove",
|
||||
Click = () => Electron.Tray.Destroy()
|
||||
};
|
||||
|
||||
Electron.Tray.Show("/Assets/electron_32x32.png", menu);
|
||||
Electron.Tray.SetToolTip("Electron Demo in the tray.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Electron.Tray.Destroy();
|
||||
}
|
||||
|
||||
});</code></pre>
|
||||
<h5>Renderer Process</h5>
|
||||
<pre><code class="javascript">const { ipcRenderer } = require("electron");
|
||||
|
||||
let trayOn = false;
|
||||
document.getElementById("put-in-tray").addEventListener("click", () => {
|
||||
ipcRenderer.send("put-in-tray");
|
||||
|
||||
let message = '';
|
||||
|
||||
if(trayOn) {
|
||||
trayOn = false;
|
||||
} else {
|
||||
trayOn = true;
|
||||
message = 'Click demo again to remove.'
|
||||
}
|
||||
|
||||
document.getElementById('tray-countdown').innerHTML = message;</code></pre>
|
||||
|
||||
<div class="demo-protip">
|
||||
<h2>ProTip</h2>
|
||||
<strong>Tray support in Linux.</strong>
|
||||
<p>On Linux distributions that only have app indicator support, users will need to install <code>libappindicator1</code> to make the tray icon work. See the <a href="http://electron.atom.io/docs/api/tray">full API documentation<span class="u-visible-to-screen-reader">(opens in new window)</span></a> for more details about using Tray on Linux.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
let trayOn = false;
|
||||
document.getElementById("put-in-tray").addEventListener("click", () => {
|
||||
ipcRenderer.send("put-in-tray");
|
||||
|
||||
let message = '';
|
||||
|
||||
if(trayOn) {
|
||||
trayOn = false;
|
||||
} else {
|
||||
trayOn = true;
|
||||
message = 'Click demo again to remove.'
|
||||
}
|
||||
|
||||
document.getElementById('tray-countdown').innerHTML = message;
|
||||
});
|
||||
}());
|
||||
</script>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -156,44 +156,45 @@ await Electron.WindowManager.CreateWindowAsync(options);</code></pre>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const { ipcRenderer } = require("electron");
|
||||
(function(){
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
document.getElementById("new-window").addEventListener("click", () => {
|
||||
ipcRenderer.send("new-window");
|
||||
});
|
||||
|
||||
document.getElementById("new-window").addEventListener("click", () => {
|
||||
ipcRenderer.send("new-window");
|
||||
});
|
||||
document.getElementById("manage-window").addEventListener("click", () => {
|
||||
ipcRenderer.send("manage-window");
|
||||
});
|
||||
|
||||
document.getElementById("manage-window").addEventListener("click", () => {
|
||||
ipcRenderer.send("manage-window");
|
||||
});
|
||||
ipcRenderer.on("manage-window-reply", (sender, data) => {
|
||||
document.getElementById("manage-window-reply").innerText = data;
|
||||
});
|
||||
|
||||
document.getElementById("listen-to-window").addEventListener("click", () => {
|
||||
ipcRenderer.send("listen-to-window");
|
||||
});
|
||||
|
||||
ipcRenderer.on("manage-window-reply", (sender, data) => {
|
||||
document.getElementById("manage-window-reply").innerText = data;
|
||||
});
|
||||
|
||||
document.getElementById("listen-to-window").addEventListener("click", () => {
|
||||
ipcRenderer.send("listen-to-window");
|
||||
});
|
||||
document.getElementById('focus-on-modal-window').addEventListener("click", () => {
|
||||
ipcRenderer.send("listen-to-window-set-focus");
|
||||
});
|
||||
|
||||
document.getElementById('focus-on-modal-window').addEventListener("click", () => {
|
||||
ipcRenderer.send("listen-to-window-set-focus");
|
||||
});
|
||||
ipcRenderer.on("listen-to-window-focus", (sender, data) => {
|
||||
const focusModalBtn = document.getElementById('focus-on-modal-window');
|
||||
focusModalBtn.classList.add('disappear');
|
||||
focusModalBtn.classList.remove('smooth-appear');
|
||||
});
|
||||
|
||||
ipcRenderer.on("listen-to-window-focus", (sender, data) => {
|
||||
const focusModalBtn = document.getElementById('focus-on-modal-window');
|
||||
focusModalBtn.classList.add('disappear');
|
||||
focusModalBtn.classList.remove('smooth-appear');
|
||||
});
|
||||
|
||||
ipcRenderer.on("listen-to-window-blur", (sender, data) => {
|
||||
const focusModalBtn = document.getElementById('focus-on-modal-window');
|
||||
focusModalBtn.classList.add('smooth-appear');
|
||||
focusModalBtn.classList.remove('disappear');
|
||||
});
|
||||
|
||||
document.getElementById('frameless-window').addEventListener("click", () => {
|
||||
ipcRenderer.send("frameless-window");
|
||||
});
|
||||
ipcRenderer.on("listen-to-window-blur", (sender, data) => {
|
||||
const focusModalBtn = document.getElementById('focus-on-modal-window');
|
||||
focusModalBtn.classList.add('smooth-appear');
|
||||
focusModalBtn.classList.remove('disappear');
|
||||
});
|
||||
|
||||
document.getElementById('frameless-window').addEventListener("click", () => {
|
||||
ipcRenderer.send("frameless-window");
|
||||
});
|
||||
}());
|
||||
</script>
|
||||
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user