mirror of
https://github.com/ElectronNET/Electron.NET.git
synced 2026-09-21 06:25:20 +00:00
Added more missing APIs
This commit is contained in:
@@ -13,6 +13,10 @@
|
||||
- Fixed resolution of unrelated target (#1099) @epsnm
|
||||
- Fixed false alarm for `ELECTRON001` on a root `package-lock.json` (#946)
|
||||
- Added `WebContents.OnZoomChanged` event (#956)
|
||||
- Added `WebContents` page loading APIs `LoadFileAsync`, `IsLoadingAsync`, `IsLoadingMainFrameAsync`, `IsWaitingForResponseAsync`, `Reload`, `ReloadIgnoringCache` and `Stop` (#956)
|
||||
- Added `WebContents.InsertCSSAsync` and `WebContents.RemoveInsertedCSSAsync` for dynamic CSS (#956)
|
||||
- Added `WebContents` editing and selection APIs (undo, redo, cut, copy, paste, insert text, select, ...) (#956)
|
||||
- Added `WebContents.FindInPageAsync`, `WebContents.StopFindInPage` and the `OnFoundInPage` event (#956)
|
||||
- Added target framework customization (#1095) @epsnm
|
||||
- Added configurable Electron root directory for custom packaging layouts (#1106) @DYH1319
|
||||
- Added ability for `custom_main.js` to modify command line switches (#1029) @AeonSake
|
||||
|
||||
@@ -58,6 +58,23 @@ Works for both BrowserWindows and BrowserViews.
|
||||
- `isBrowserWindow` - Whether the webContents belong to a BrowserWindow or not (the other option is a BrowserView)
|
||||
- `path` - Absolute path to the CSS file location
|
||||
|
||||
#### 🧊 `Task<string> InsertCSSAsync(string css, string cssOrigin = null)`
|
||||
Injects CSS into the current web page and returns a unique key for the inserted style sheet.
|
||||
|
||||
**Parameters:**
|
||||
- `css` - The style sheet to inject
|
||||
- `cssOrigin` - Can be either `user` or `author`, defaults to `author`
|
||||
|
||||
**Returns:**
|
||||
|
||||
The key of the inserted style sheet, to be used with `RemoveInsertedCSSAsync`.
|
||||
|
||||
#### 🧊 `Task RemoveInsertedCSSAsync(string key)`
|
||||
Removes a previously inserted style sheet from the current web page.
|
||||
|
||||
**Parameters:**
|
||||
- `key` - The key returned by `InsertCSSAsync`
|
||||
|
||||
#### 🧊 `Task LoadURLAsync(string url)`
|
||||
Loads the url in the window. The url must contain the protocol prefix.
|
||||
|
||||
@@ -138,6 +155,66 @@ Sets the maximum and minimum pinch-to-zoom level.
|
||||
- `minimumLevel` - The minimum pinch-to-zoom level
|
||||
- `maximumLevel` - The maximum pinch-to-zoom level
|
||||
|
||||
#### 🧊 `Task LoadFileAsync(string filePath, LoadFileOptions options = null)`
|
||||
Loads the given HTML file, relative to the root of the application.
|
||||
|
||||
**Parameters:**
|
||||
- `filePath` - Path to the HTML file
|
||||
- `options` - Optional `Query`, `Search` and `Hash` parts of the resulting URL
|
||||
|
||||
#### 🧊 `Task<bool> IsLoadingAsync()`
|
||||
Whether the web page is still loading resources.
|
||||
|
||||
#### 🧊 `Task<bool> IsLoadingMainFrameAsync()`
|
||||
Whether the main frame (and not just iframes or frames within it) is still loading.
|
||||
|
||||
#### 🧊 `Task<bool> IsWaitingForResponseAsync()`
|
||||
Whether the web page is waiting for a first response from the main resource of the page.
|
||||
|
||||
#### 🧊 `void Reload()`
|
||||
Reloads the current web page.
|
||||
|
||||
#### 🧊 `void ReloadIgnoringCache()`
|
||||
Reloads the current web page and ignores the cache.
|
||||
|
||||
#### 🧊 `void Stop()`
|
||||
Stops any pending navigation.
|
||||
|
||||
#### 🧊 `void Undo()` / `void Redo()`
|
||||
Executes the `undo` / `redo` editing command in the web page.
|
||||
|
||||
#### 🧊 `void Cut()` / `void Copy()` / `void Paste()` / `void PasteAndMatchStyle()` / `void Delete()`
|
||||
Executes the corresponding editing command in the web page.
|
||||
|
||||
#### 🧊 `void CopyImageAt(int x, int y)`
|
||||
Copies the image at the given position to the clipboard.
|
||||
|
||||
#### 🧊 `void SelectAll()` / `void Unselect()` / `void CenterSelection()`
|
||||
Selects all content, clears the selection, or scrolls to the current selection.
|
||||
|
||||
#### 🧊 `void AdjustSelection(AdjustSelectionOptions options)`
|
||||
Adjusts the start and end points of the current text selection by the given amounts. Negative amounts move towards the beginning of the document.
|
||||
|
||||
#### 🧊 `Task InsertTextAsync(string text)`
|
||||
Inserts text into the focused element.
|
||||
|
||||
#### 🧊 `void Replace(string text)` / `void ReplaceMisspelling(string text)`
|
||||
Replaces the current selection, or the currently misspelled word, with the given text.
|
||||
|
||||
#### 🧊 `Task<int> FindInPageAsync(string text, FindInPageOptions options = null)`
|
||||
Starts a request to find all matches for the text in the web page. Results are reported via the `OnFoundInPage` event.
|
||||
|
||||
**Parameters:**
|
||||
- `text` - Content to be searched, must not be empty
|
||||
- `options` - Optional `Forward`, `FindNext` and `MatchCase` flags
|
||||
|
||||
**Returns:**
|
||||
|
||||
The request id of the find request.
|
||||
|
||||
#### 🧊 `void StopFindInPage(StopFindInPageAction action)`
|
||||
Stops any `FindInPageAsync` request with the given action (`ClearSelection`, `KeepSelection` or `ActivateSelection`).
|
||||
|
||||
## Events
|
||||
|
||||
#### ⚡ `InputEvent`
|
||||
@@ -170,6 +247,9 @@ Emitted when a server side redirect occurs during navigation.
|
||||
#### ⚡ `OnZoomChanged`
|
||||
Emitted when the user changes the zoom level using the mouse wheel or the keyboard. The handler receives the `ZoomDirection` (`In` or `Out`).
|
||||
|
||||
#### ⚡ `OnFoundInPage`
|
||||
Emitted when a result is available for a `FindInPageAsync` request. The handler receives a `FoundInPageResult`.
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Page Loading
|
||||
@@ -331,6 +411,41 @@ webContents.OnZoomChanged += (direction) =>
|
||||
|
||||
> **Note:** The zoom factor is shared by all windows using the same session partition. Assign a unique `WebPreferences.Partition` per window if each window should keep its own zoom.
|
||||
|
||||
### Dynamic CSS
|
||||
|
||||
```csharp
|
||||
var key = await webContents.InsertCSSAsync("body { background-color: #202020; }");
|
||||
|
||||
// ... later
|
||||
await webContents.RemoveInsertedCSSAsync(key);
|
||||
```
|
||||
|
||||
### Editing and Selection
|
||||
|
||||
```csharp
|
||||
await webContents.InsertTextAsync("Hello from .NET");
|
||||
|
||||
webContents.SelectAll();
|
||||
webContents.Copy();
|
||||
webContents.Unselect();
|
||||
```
|
||||
|
||||
### Find in Page
|
||||
|
||||
```csharp
|
||||
webContents.OnFoundInPage += (result) =>
|
||||
{
|
||||
Console.WriteLine($"{result.ActiveMatchOrdinal}/{result.Matches} matches");
|
||||
|
||||
if (result.FinalUpdate)
|
||||
{
|
||||
webContents.StopFindInPage(StopFindInPageAction.ClearSelection);
|
||||
}
|
||||
};
|
||||
|
||||
var requestId = await webContents.FindInPageAsync("electron", new FindInPageOptions { MatchCase = false });
|
||||
```
|
||||
|
||||
## Related APIs
|
||||
|
||||
- [Electron.WindowManager](WindowManager.md) - Windows containing web contents
|
||||
|
||||
18
src/ElectronNET.API/API/Entities/AdjustSelectionOptions.cs
Normal file
18
src/ElectronNET.API/API/Entities/AdjustSelectionOptions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for <see cref="WebContents.AdjustSelection"/>.
|
||||
/// </summary>
|
||||
public class AdjustSelectionOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Amount to shift the start index of the current selection.
|
||||
/// </summary>
|
||||
public int? Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Amount to shift the end index of the current selection.
|
||||
/// </summary>
|
||||
public int? End { get; set; }
|
||||
}
|
||||
}
|
||||
24
src/ElectronNET.API/API/Entities/FindInPageOptions.cs
Normal file
24
src/ElectronNET.API/API/Entities/FindInPageOptions.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for <see cref="WebContents.FindInPageAsync"/>.
|
||||
/// </summary>
|
||||
public class FindInPageOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether to search forward or backward, defaults to true.
|
||||
/// </summary>
|
||||
public bool? Forward { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to begin a new text finding session with this request. Should be true
|
||||
/// for initial requests, and false for subsequent requests. Defaults to false.
|
||||
/// </summary>
|
||||
public bool? FindNext { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether search should be case-sensitive, defaults to false.
|
||||
/// </summary>
|
||||
public bool? MatchCase { get; set; }
|
||||
}
|
||||
}
|
||||
33
src/ElectronNET.API/API/Entities/FoundInPageResult.cs
Normal file
33
src/ElectronNET.API/API/Entities/FoundInPageResult.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// The result of a text finding session, reported by the found-in-page event.
|
||||
/// </summary>
|
||||
public class FoundInPageResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The identifier of the request returned by FindInPageAsync.
|
||||
/// </summary>
|
||||
public int RequestId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Position of the active match.
|
||||
/// </summary>
|
||||
public int ActiveMatchOrdinal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of matches.
|
||||
/// </summary>
|
||||
public int Matches { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Coordinates of the first match region.
|
||||
/// </summary>
|
||||
public Rectangle SelectionArea { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether more responses are to follow.
|
||||
/// </summary>
|
||||
public bool FinalUpdate { get; set; }
|
||||
}
|
||||
}
|
||||
25
src/ElectronNET.API/API/Entities/LoadFileOptions.cs
Normal file
25
src/ElectronNET.API/API/Entities/LoadFileOptions.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for loading a local file into a web page.
|
||||
/// </summary>
|
||||
public class LoadFileOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Passed to url.format().
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Query { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Passed to url.format().
|
||||
/// </summary>
|
||||
public string Search { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Passed to url.format().
|
||||
/// </summary>
|
||||
public string Hash { get; set; }
|
||||
}
|
||||
}
|
||||
23
src/ElectronNET.API/API/Entities/StopFindInPageAction.cs
Normal file
23
src/ElectronNET.API/API/Entities/StopFindInPageAction.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace ElectronNET.API.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines what happens to the selection when a text finding session is stopped.
|
||||
/// </summary>
|
||||
public enum StopFindInPageAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Clear the selection.
|
||||
/// </summary>
|
||||
ClearSelection,
|
||||
|
||||
/// <summary>
|
||||
/// Translate the selection into a normal selection.
|
||||
/// </summary>
|
||||
KeepSelection,
|
||||
|
||||
/// <summary>
|
||||
/// Focus and click the selection node.
|
||||
/// </summary>
|
||||
ActivateSelection
|
||||
}
|
||||
}
|
||||
@@ -122,6 +122,15 @@ public class WebContents : ApiBase
|
||||
remove => RemoveEvent(value, Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emitted when a result is available for a <see cref="FindInPageAsync(string, FindInPageOptions)"/> request.
|
||||
/// </summary>
|
||||
public event Action<FoundInPageResult> OnFoundInPage
|
||||
{
|
||||
add => AddEvent(value, Id);
|
||||
remove => RemoveEvent(value, Id);
|
||||
}
|
||||
|
||||
internal WebContents(int id)
|
||||
{
|
||||
Id = id;
|
||||
@@ -313,6 +322,68 @@ public class WebContents : ApiBase
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the given file in the window. The file path must be a path to an HTML file
|
||||
/// relative to the root of your application.
|
||||
/// </summary>
|
||||
/// <param name="filePath">Path to the HTML file.</param>
|
||||
/// <param name="options">Optional query, search and hash parts of the resulting URL.</param>
|
||||
public Task LoadFileAsync(string filePath, LoadFileOptions options = null)
|
||||
{
|
||||
var tcs = new TaskCompletionSource();
|
||||
|
||||
BridgeConnector.Socket.Once("webContents-loadFile-complete" + Id, () =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("webContents-loadFile-error" + Id);
|
||||
tcs.SetResult();
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Once<string>("webContents-loadFile-error" + Id, (error) => { tcs.SetException(new InvalidOperationException(error)); });
|
||||
|
||||
BridgeConnector.Socket.Emit("webContents-loadFile", Id, filePath, options);
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns boolean - Whether web page is still loading resources.
|
||||
/// </summary>
|
||||
public Task<bool> IsLoadingAsync() => InvokeAsync<bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns boolean - Whether the main frame (and not just iframes or frames within it) is still loading.
|
||||
/// </summary>
|
||||
public Task<bool> IsLoadingMainFrameAsync() => InvokeAsync<bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns boolean - Whether the web page is waiting for a first-response from the main resource of the page.
|
||||
/// </summary>
|
||||
public Task<bool> IsWaitingForResponseAsync() => InvokeAsync<bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the current web page.
|
||||
/// </summary>
|
||||
public void Reload()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-reload", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the current page and ignores cache.
|
||||
/// </summary>
|
||||
public void ReloadIgnoringCache()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-reloadIgnoringCache", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops any pending navigation.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-stop", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts CSS into the web page.
|
||||
/// See: https://www.electronjs.org/docs/api/web-contents#contentsinsertcsscss-options
|
||||
@@ -325,6 +396,37 @@ public class WebContents : ApiBase
|
||||
BridgeConnector.Socket.Emit("webContents-insertCSS", Id, isBrowserWindow, path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Injects CSS into the current web page and returns a unique key for the inserted
|
||||
/// stylesheet, which can be used with <see cref="RemoveInsertedCSSAsync"/>.
|
||||
/// </summary>
|
||||
/// <param name="css">The style sheet to inject.</param>
|
||||
/// <param name="cssOrigin">Can be either 'user' or 'author'. Defaults to 'author'.</param>
|
||||
/// <returns>The key of the inserted style sheet.</returns>
|
||||
public Task<string> InsertCSSAsync(string css, string cssOrigin = null)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<string>();
|
||||
|
||||
BridgeConnector.Socket.Once<string>("webContents-insertCSSText-completed" + Id, tcs.SetResult);
|
||||
BridgeConnector.Socket.Emit("webContents-insertCSSText", Id, css, cssOrigin);
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the inserted CSS from the current web page.
|
||||
/// </summary>
|
||||
/// <param name="key">The key returned by <see cref="InsertCSSAsync"/>.</param>
|
||||
public Task RemoveInsertedCSSAsync(string key)
|
||||
{
|
||||
var tcs = new TaskCompletionSource();
|
||||
|
||||
BridgeConnector.Socket.Once("webContents-removeInsertedCSS-completed" + Id, tcs.SetResult);
|
||||
BridgeConnector.Socket.Emit("webContents-removeInsertedCSS", Id, key);
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns number - The current zoom factor.
|
||||
/// </summary>
|
||||
@@ -408,4 +510,162 @@ public class WebContents : ApiBase
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-setUserAgent", Id, userAgent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command undo in web page.
|
||||
/// </summary>
|
||||
public void Undo()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-undo", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command redo in web page.
|
||||
/// </summary>
|
||||
public void Redo()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-redo", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command cut in web page.
|
||||
/// </summary>
|
||||
public void Cut()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-cut", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command copy in web page.
|
||||
/// </summary>
|
||||
public void Copy()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-copy", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the image at the given position to the clipboard.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public void CopyImageAt(int x, int y)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-copyImageAt", Id, x, y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command paste in web page.
|
||||
/// </summary>
|
||||
public void Paste()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-paste", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command pasteAndMatchStyle in web page.
|
||||
/// </summary>
|
||||
public void PasteAndMatchStyle()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-pasteAndMatchStyle", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command delete in web page.
|
||||
/// </summary>
|
||||
public void Delete()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-delete", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command selectAll in web page.
|
||||
/// </summary>
|
||||
public void SelectAll()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-selectAll", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command unselect in web page.
|
||||
/// </summary>
|
||||
public void Unselect()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-unselect", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the current text selection starting and ending points by the given amounts.
|
||||
/// A negative amount moves the selection towards the beginning of the document.
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
public void AdjustSelection(AdjustSelectionOptions options)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-adjustSelection", Id, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls to the current text selection.
|
||||
/// </summary>
|
||||
public void CenterSelection()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-centerSelection", Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts text to the focused element.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to be inserted.</param>
|
||||
public Task InsertTextAsync(string text)
|
||||
{
|
||||
var tcs = new TaskCompletionSource();
|
||||
|
||||
BridgeConnector.Socket.Once("webContents-insertText-completed" + Id, tcs.SetResult);
|
||||
BridgeConnector.Socket.Emit("webContents-insertText", Id, text);
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command replace in web page.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void Replace(string text)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-replace", Id, text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the editing command replaceMisspelling in web page.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
public void ReplaceMisspelling(string text)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-replaceMisspelling", Id, text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a request to find all matches for the text in the web page.
|
||||
/// The result of the request can be obtained by subscribing to the <see cref="OnFoundInPage"/> event.
|
||||
/// </summary>
|
||||
/// <param name="text">Content to be searched, must not be empty.</param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns>The request id used for the request.</returns>
|
||||
public Task<int> FindInPageAsync(string text, FindInPageOptions options = null)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<int>();
|
||||
|
||||
BridgeConnector.Socket.Once<int>("webContents-findInPage-completed" + Id, tcs.SetResult);
|
||||
BridgeConnector.Socket.Emit("webContents-findInPage", Id, text, options);
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops any findInPage request for the web contents with the provided action.
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
public void StopFindInPage(StopFindInPageAction action)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("webContents-stopFindInPage", Id, action);
|
||||
}
|
||||
}
|
||||
@@ -118,6 +118,13 @@ module.exports = (socket) => {
|
||||
electronSocket.emit("webContents-zoomChanged" + id, zoomDirection);
|
||||
});
|
||||
});
|
||||
socket.on("register-webContents-foundInPage", (id) => {
|
||||
const browserWindow = getWindowById(id);
|
||||
browserWindow.webContents.removeAllListeners("found-in-page");
|
||||
browserWindow.webContents.on("found-in-page", (_, result) => {
|
||||
electronSocket.emit("webContents-foundInPage" + id, result);
|
||||
});
|
||||
});
|
||||
socket.on("webContents-openDevTools", (id, options) => {
|
||||
if (options) {
|
||||
getWindowById(id).webContents.openDevTools(options);
|
||||
@@ -315,6 +322,36 @@ module.exports = (socket) => {
|
||||
electronSocket.emit("webContents-loadURL-error" + id, error);
|
||||
});
|
||||
});
|
||||
socket.on("webContents-loadFile", (id, filePath, options) => {
|
||||
const browserWindow = getWindowById(id);
|
||||
browserWindow.webContents
|
||||
.loadFile(filePath, options ?? undefined)
|
||||
.then(() => {
|
||||
electronSocket.emit("webContents-loadFile-complete" + id);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
electronSocket.emit("webContents-loadFile-error" + id, error);
|
||||
});
|
||||
});
|
||||
socket.on("webContents-isLoading", (id) => {
|
||||
electronSocket.emit("webContents-isLoading-completed", getWindowById(id).webContents.isLoading());
|
||||
});
|
||||
socket.on("webContents-isLoadingMainFrame", (id) => {
|
||||
electronSocket.emit("webContents-isLoadingMainFrame-completed", getWindowById(id).webContents.isLoadingMainFrame());
|
||||
});
|
||||
socket.on("webContents-isWaitingForResponse", (id) => {
|
||||
electronSocket.emit("webContents-isWaitingForResponse-completed", getWindowById(id).webContents.isWaitingForResponse());
|
||||
});
|
||||
socket.on("webContents-reload", (id) => {
|
||||
getWindowById(id).webContents.reload();
|
||||
});
|
||||
socket.on("webContents-reloadIgnoringCache", (id) => {
|
||||
getWindowById(id).webContents.reloadIgnoringCache();
|
||||
});
|
||||
socket.on("webContents-stop", (id) => {
|
||||
getWindowById(id).webContents.stop();
|
||||
});
|
||||
socket.on("webContents-insertCSS", (id, isBrowserWindow, path) => {
|
||||
if (isBrowserWindow) {
|
||||
const browserWindow = getWindowById(id);
|
||||
@@ -337,6 +374,14 @@ module.exports = (socket) => {
|
||||
}
|
||||
}
|
||||
});
|
||||
socket.on("webContents-insertCSSText", async (id, css, cssOrigin) => {
|
||||
const key = await getWindowById(id).webContents.insertCSS(css, cssOrigin ? { cssOrigin } : undefined);
|
||||
electronSocket.emit("webContents-insertCSSText-completed" + id, key);
|
||||
});
|
||||
socket.on("webContents-removeInsertedCSS", async (id, key) => {
|
||||
await getWindowById(id).webContents.removeInsertedCSS(key);
|
||||
electronSocket.emit("webContents-removeInsertedCSS-completed" + id);
|
||||
});
|
||||
socket.on("webContents-session-getAllExtensions", (id) => {
|
||||
const browserWindow = getWindowById(id);
|
||||
const extensionsList = browserWindow.webContents.session.getAllExtensions();
|
||||
@@ -410,6 +455,59 @@ module.exports = (socket) => {
|
||||
socket.on("webContents-setUserAgent", (id, userAgent) => {
|
||||
getWindowById(id).webContents.setUserAgent(userAgent);
|
||||
});
|
||||
socket.on("webContents-undo", (id) => {
|
||||
getWindowById(id).webContents.undo();
|
||||
});
|
||||
socket.on("webContents-redo", (id) => {
|
||||
getWindowById(id).webContents.redo();
|
||||
});
|
||||
socket.on("webContents-cut", (id) => {
|
||||
getWindowById(id).webContents.cut();
|
||||
});
|
||||
socket.on("webContents-copy", (id) => {
|
||||
getWindowById(id).webContents.copy();
|
||||
});
|
||||
socket.on("webContents-copyImageAt", (id, x, y) => {
|
||||
getWindowById(id).webContents.copyImageAt(x, y);
|
||||
});
|
||||
socket.on("webContents-paste", (id) => {
|
||||
getWindowById(id).webContents.paste();
|
||||
});
|
||||
socket.on("webContents-pasteAndMatchStyle", (id) => {
|
||||
getWindowById(id).webContents.pasteAndMatchStyle();
|
||||
});
|
||||
socket.on("webContents-delete", (id) => {
|
||||
getWindowById(id).webContents.delete();
|
||||
});
|
||||
socket.on("webContents-selectAll", (id) => {
|
||||
getWindowById(id).webContents.selectAll();
|
||||
});
|
||||
socket.on("webContents-unselect", (id) => {
|
||||
getWindowById(id).webContents.unselect();
|
||||
});
|
||||
socket.on("webContents-adjustSelection", (id, options) => {
|
||||
getWindowById(id).webContents.adjustSelection(options ?? {});
|
||||
});
|
||||
socket.on("webContents-centerSelection", (id) => {
|
||||
getWindowById(id).webContents.centerSelection();
|
||||
});
|
||||
socket.on("webContents-insertText", async (id, text) => {
|
||||
await getWindowById(id).webContents.insertText(text);
|
||||
electronSocket.emit("webContents-insertText-completed" + id);
|
||||
});
|
||||
socket.on("webContents-replace", (id, text) => {
|
||||
getWindowById(id).webContents.replace(text);
|
||||
});
|
||||
socket.on("webContents-replaceMisspelling", (id, text) => {
|
||||
getWindowById(id).webContents.replaceMisspelling(text);
|
||||
});
|
||||
socket.on("webContents-findInPage", (id, text, options) => {
|
||||
const requestId = getWindowById(id).webContents.findInPage(text, options ?? undefined);
|
||||
electronSocket.emit("webContents-findInPage-completed" + id, requestId);
|
||||
});
|
||||
socket.on("webContents-stopFindInPage", (id, action) => {
|
||||
getWindowById(id).webContents.stopFindInPage(action);
|
||||
});
|
||||
function getWindowById(id) {
|
||||
if (id >= 1000) {
|
||||
return (0, browserView_1.browserViewMediateService)(id - 1000);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -112,6 +112,15 @@ export = (socket: Socket) => {
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("register-webContents-foundInPage", (id) => {
|
||||
const browserWindow = getWindowById(id);
|
||||
|
||||
browserWindow.webContents.removeAllListeners("found-in-page");
|
||||
browserWindow.webContents.on("found-in-page", (_, result) => {
|
||||
electronSocket.emit("webContents-foundInPage" + id, result);
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("webContents-openDevTools", (id, options) => {
|
||||
if (options) {
|
||||
getWindowById(id).webContents.openDevTools(options);
|
||||
@@ -418,6 +427,52 @@ export = (socket: Socket) => {
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("webContents-loadFile", (id, filePath, options) => {
|
||||
const browserWindow = getWindowById(id);
|
||||
browserWindow.webContents
|
||||
.loadFile(filePath, options ?? undefined)
|
||||
.then(() => {
|
||||
electronSocket.emit("webContents-loadFile-complete" + id);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
electronSocket.emit("webContents-loadFile-error" + id, error);
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("webContents-isLoading", (id) => {
|
||||
electronSocket.emit(
|
||||
"webContents-isLoading-completed",
|
||||
getWindowById(id).webContents.isLoading(),
|
||||
);
|
||||
});
|
||||
|
||||
socket.on("webContents-isLoadingMainFrame", (id) => {
|
||||
electronSocket.emit(
|
||||
"webContents-isLoadingMainFrame-completed",
|
||||
getWindowById(id).webContents.isLoadingMainFrame(),
|
||||
);
|
||||
});
|
||||
|
||||
socket.on("webContents-isWaitingForResponse", (id) => {
|
||||
electronSocket.emit(
|
||||
"webContents-isWaitingForResponse-completed",
|
||||
getWindowById(id).webContents.isWaitingForResponse(),
|
||||
);
|
||||
});
|
||||
|
||||
socket.on("webContents-reload", (id) => {
|
||||
getWindowById(id).webContents.reload();
|
||||
});
|
||||
|
||||
socket.on("webContents-reloadIgnoringCache", (id) => {
|
||||
getWindowById(id).webContents.reloadIgnoringCache();
|
||||
});
|
||||
|
||||
socket.on("webContents-stop", (id) => {
|
||||
getWindowById(id).webContents.stop();
|
||||
});
|
||||
|
||||
socket.on("webContents-insertCSS", (id, isBrowserWindow, path) => {
|
||||
if (isBrowserWindow) {
|
||||
const browserWindow = getWindowById(id);
|
||||
@@ -440,6 +495,19 @@ export = (socket: Socket) => {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("webContents-insertCSSText", async (id, css, cssOrigin) => {
|
||||
const key = await getWindowById(id).webContents.insertCSS(
|
||||
css,
|
||||
cssOrigin ? { cssOrigin } : undefined,
|
||||
);
|
||||
electronSocket.emit("webContents-insertCSSText-completed" + id, key);
|
||||
});
|
||||
|
||||
socket.on("webContents-removeInsertedCSS", async (id, key) => {
|
||||
await getWindowById(id).webContents.removeInsertedCSS(key);
|
||||
electronSocket.emit("webContents-removeInsertedCSS-completed" + id);
|
||||
});
|
||||
|
||||
socket.on("webContents-session-getAllExtensions", (id) => {
|
||||
const browserWindow = getWindowById(id);
|
||||
const extensionsList = browserWindow.webContents.session.getAllExtensions();
|
||||
@@ -566,6 +634,79 @@ export = (socket: Socket) => {
|
||||
getWindowById(id).webContents.setUserAgent(userAgent);
|
||||
});
|
||||
|
||||
socket.on("webContents-undo", (id) => {
|
||||
getWindowById(id).webContents.undo();
|
||||
});
|
||||
|
||||
socket.on("webContents-redo", (id) => {
|
||||
getWindowById(id).webContents.redo();
|
||||
});
|
||||
|
||||
socket.on("webContents-cut", (id) => {
|
||||
getWindowById(id).webContents.cut();
|
||||
});
|
||||
|
||||
socket.on("webContents-copy", (id) => {
|
||||
getWindowById(id).webContents.copy();
|
||||
});
|
||||
|
||||
socket.on("webContents-copyImageAt", (id, x, y) => {
|
||||
getWindowById(id).webContents.copyImageAt(x, y);
|
||||
});
|
||||
|
||||
socket.on("webContents-paste", (id) => {
|
||||
getWindowById(id).webContents.paste();
|
||||
});
|
||||
|
||||
socket.on("webContents-pasteAndMatchStyle", (id) => {
|
||||
getWindowById(id).webContents.pasteAndMatchStyle();
|
||||
});
|
||||
|
||||
socket.on("webContents-delete", (id) => {
|
||||
getWindowById(id).webContents.delete();
|
||||
});
|
||||
|
||||
socket.on("webContents-selectAll", (id) => {
|
||||
getWindowById(id).webContents.selectAll();
|
||||
});
|
||||
|
||||
socket.on("webContents-unselect", (id) => {
|
||||
getWindowById(id).webContents.unselect();
|
||||
});
|
||||
|
||||
socket.on("webContents-adjustSelection", (id, options) => {
|
||||
getWindowById(id).webContents.adjustSelection(options ?? {});
|
||||
});
|
||||
|
||||
socket.on("webContents-centerSelection", (id) => {
|
||||
getWindowById(id).webContents.centerSelection();
|
||||
});
|
||||
|
||||
socket.on("webContents-insertText", async (id, text) => {
|
||||
await getWindowById(id).webContents.insertText(text);
|
||||
electronSocket.emit("webContents-insertText-completed" + id);
|
||||
});
|
||||
|
||||
socket.on("webContents-replace", (id, text) => {
|
||||
getWindowById(id).webContents.replace(text);
|
||||
});
|
||||
|
||||
socket.on("webContents-replaceMisspelling", (id, text) => {
|
||||
getWindowById(id).webContents.replaceMisspelling(text);
|
||||
});
|
||||
|
||||
socket.on("webContents-findInPage", (id, text, options) => {
|
||||
const requestId = getWindowById(id).webContents.findInPage(
|
||||
text,
|
||||
options ?? undefined,
|
||||
);
|
||||
electronSocket.emit("webContents-findInPage-completed" + id, requestId);
|
||||
});
|
||||
|
||||
socket.on("webContents-stopFindInPage", (id, action) => {
|
||||
getWindowById(id).webContents.stopFindInPage(action);
|
||||
});
|
||||
|
||||
function getWindowById(
|
||||
id: number,
|
||||
): Electron.BrowserWindow | Electron.BrowserView {
|
||||
|
||||
@@ -199,5 +199,94 @@ namespace ElectronNET.IntegrationTests.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[IntegrationFact]
|
||||
public async Task InsertAndRemoveCSS_check()
|
||||
{
|
||||
var wc = this.MainWindow.WebContents;
|
||||
await wc.LoadURLAsync("data:text/html,<html><body><p>CSS Test</p></body></html>");
|
||||
|
||||
var key = await wc.InsertCSSAsync("body { background-color: rgb(255, 0, 0); }");
|
||||
key.Should().NotBeNullOrEmpty();
|
||||
|
||||
var color = await wc.ExecuteJavaScriptAsync<string>("getComputedStyle(document.body).backgroundColor");
|
||||
color.Should().Be("rgb(255, 0, 0)");
|
||||
|
||||
await wc.RemoveInsertedCSSAsync(key);
|
||||
|
||||
color = await wc.ExecuteJavaScriptAsync<string>("getComputedStyle(document.body).backgroundColor");
|
||||
color.Should().NotBe("rgb(255, 0, 0)");
|
||||
}
|
||||
|
||||
[IntegrationFact]
|
||||
public async Task EditCommands_check()
|
||||
{
|
||||
var wc = this.MainWindow.WebContents;
|
||||
await wc.LoadURLAsync("data:text/html,<html><body><input id='in' autofocus /></body></html>");
|
||||
await Task.Delay(500.ms());
|
||||
|
||||
await wc.InsertTextAsync("Electron.NET");
|
||||
await Task.Delay(500.ms());
|
||||
|
||||
var value = await wc.ExecuteJavaScriptAsync<string>("document.getElementById('in').value");
|
||||
value.Should().Be("Electron.NET");
|
||||
|
||||
wc.SelectAll();
|
||||
wc.Delete();
|
||||
await Task.Delay(500.ms());
|
||||
|
||||
value = await wc.ExecuteJavaScriptAsync<string>("document.getElementById('in').value");
|
||||
value.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[IntegrationFact]
|
||||
public async Task FindInPage_check()
|
||||
{
|
||||
var wc = this.MainWindow.WebContents;
|
||||
await wc.LoadURLAsync("data:text/html,<html><body><p>needle in a haystack</p></body></html>");
|
||||
await Task.Delay(500.ms());
|
||||
|
||||
var tcs = new TaskCompletionSource<FoundInPageResult>();
|
||||
|
||||
void OnFound(FoundInPageResult result) => tcs.TrySetResult(result);
|
||||
|
||||
wc.OnFoundInPage += OnFound;
|
||||
|
||||
try
|
||||
{
|
||||
var requestId = await wc.FindInPageAsync("needle");
|
||||
requestId.Should().BeGreaterThan(0);
|
||||
|
||||
var completed = await Task.WhenAny(tcs.Task, Task.Delay(5.seconds()));
|
||||
completed.Should().Be(tcs.Task);
|
||||
|
||||
var result = await tcs.Task;
|
||||
result.RequestId.Should().Be(requestId);
|
||||
result.Matches.Should().BeGreaterThan(0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
wc.OnFoundInPage -= OnFound;
|
||||
wc.StopFindInPage(StopFindInPageAction.ClearSelection);
|
||||
}
|
||||
}
|
||||
|
||||
[IntegrationFact]
|
||||
public async Task Reload_and_loading_state_check()
|
||||
{
|
||||
var wc = this.MainWindow.WebContents;
|
||||
await wc.LoadURLAsync("data:text/html,<html><body><h1>Reload Test</h1></body></html>");
|
||||
await Task.Delay(500.ms());
|
||||
|
||||
(await wc.IsLoadingAsync()).Should().BeFalse();
|
||||
(await wc.IsLoadingMainFrameAsync()).Should().BeFalse();
|
||||
(await wc.IsWaitingForResponseAsync()).Should().BeFalse();
|
||||
|
||||
wc.Reload();
|
||||
await Task.Delay(1.seconds());
|
||||
|
||||
var title = await wc.ExecuteJavaScriptAsync<string>("document.querySelector('h1').textContent");
|
||||
title.Should().Be("Reload Test");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user