Skip to content

Commit a619b6e

Browse files
Implemented BrowserView API #371
1 parent 3ba3fa6 commit a619b6e

18 files changed

+476
-7
lines changed

ElectronNET.API/BrowserView.cs

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
using ElectronNET.API.Entities;
2+
using Newtonsoft.Json;
3+
using Newtonsoft.Json.Linq;
4+
using Newtonsoft.Json.Serialization;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace ElectronNET.API
11+
{
12+
/// <summary>
13+
/// A BrowserView can be used to embed additional web content into a BrowserWindow.
14+
/// It is like a child window, except that it is positioned relative to its owning window.
15+
/// It is meant to be an alternative to the webview tag.
16+
/// </summary>
17+
public class BrowserView
18+
{
19+
/// <summary>
20+
/// Gets the identifier.
21+
/// </summary>
22+
/// <value>
23+
/// The identifier.
24+
/// </value>
25+
public int Id { get; internal set; }
26+
27+
/// <summary>
28+
/// Render and control web pages.
29+
/// </summary>
30+
public WebContents WebContents { get; internal set; }
31+
32+
/// <summary>
33+
/// Whether the view is destroyed.
34+
/// </summary>
35+
public Task<bool> IsDestroyedAsync
36+
{
37+
get
38+
{
39+
return Task.Run<bool>(() =>
40+
{
41+
var taskCompletionSource = new TaskCompletionSource<bool>();
42+
43+
BridgeConnector.Socket.On("browserView-isDestroyed-reply", (result) =>
44+
{
45+
BridgeConnector.Socket.Off("browserView-isDestroyed-reply");
46+
taskCompletionSource.SetResult((bool)result);
47+
});
48+
49+
BridgeConnector.Socket.Emit("browserView-isDestroyed", Id);
50+
51+
return taskCompletionSource.Task;
52+
});
53+
}
54+
}
55+
56+
/// <summary>
57+
/// Resizes and moves the view to the supplied bounds relative to the window.
58+
///
59+
/// (experimental)
60+
/// </summary>
61+
public Rectangle Bounds
62+
{
63+
get
64+
{
65+
return Task.Run<Rectangle>(() =>
66+
{
67+
var taskCompletionSource = new TaskCompletionSource<Rectangle>();
68+
69+
BridgeConnector.Socket.On("browserView-getBounds-reply", (result) =>
70+
{
71+
BridgeConnector.Socket.Off("browserView-getBounds-reply");
72+
taskCompletionSource.SetResult((Rectangle)result);
73+
});
74+
75+
BridgeConnector.Socket.Emit("browserView-getBounds", Id);
76+
77+
return taskCompletionSource.Task;
78+
}).Result;
79+
}
80+
set
81+
{
82+
BridgeConnector.Socket.Emit("browserView-setBounds", Id, JObject.FromObject(value, _jsonSerializer));
83+
}
84+
}
85+
86+
internal Action<BrowserView> Destroyed;
87+
88+
/// <summary>
89+
/// BrowserView
90+
/// </summary>
91+
internal BrowserView(int id)
92+
{
93+
Id = id;
94+
95+
// Workaround: increase the Id so as not to conflict with BrowserWindow id
96+
// the backend detect about the value an BrowserView
97+
WebContents = new WebContents(id + 1000);
98+
}
99+
100+
/// <summary>
101+
/// Force closing the view, the `unload` and `beforeunload` events won't be emitted
102+
/// for the web page.After you're done with a view, call this function in order to
103+
/// free memory and other resources as soon as possible.
104+
/// </summary>
105+
public void Destroy()
106+
{
107+
BridgeConnector.Socket.Emit("browserView-destroy", Id);
108+
109+
Destroyed?.Invoke(this);
110+
}
111+
112+
/// <summary>
113+
/// (experimental)
114+
/// </summary>
115+
/// <param name="options"></param>
116+
public void SetAutoResize(AutoResizeOptions options)
117+
{
118+
BridgeConnector.Socket.Emit("browserView-setAutoResize", Id, JObject.FromObject(options, _jsonSerializer));
119+
}
120+
121+
/// <summary>
122+
/// Color in #aarrggbb or #argb form. The alpha channel is optional.
123+
///
124+
/// (experimental)
125+
/// </summary>
126+
/// <param name="color">Color in #aarrggbb or #argb form. The alpha channel is optional.</param>
127+
public void SetBackgroundColor(string color)
128+
{
129+
BridgeConnector.Socket.Emit("browserView-setBackgroundColor", Id, color);
130+
}
131+
132+
private JsonSerializer _jsonSerializer = new JsonSerializer()
133+
{
134+
ContractResolver = new CamelCasePropertyNamesContractResolver(),
135+
NullValueHandling = NullValueHandling.Ignore
136+
};
137+
}
138+
}

ElectronNET.API/BrowserWindow.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2305,6 +2305,17 @@ public void SetVibrancy(Vibrancy type)
23052305
/// </summary>
23062306
public WebContents WebContents { get; internal set; }
23072307

2308+
/// <summary>
2309+
/// A BrowserView can be used to embed additional web content into a BrowserWindow.
2310+
/// It is like a child window, except that it is positioned relative to its owning window.
2311+
/// It is meant to be an alternative to the webview tag.
2312+
/// </summary>
2313+
/// <param name="browserView"></param>
2314+
public void SetBrowserView(BrowserView browserView)
2315+
{
2316+
BridgeConnector.Socket.Emit("browserWindow-setBrowserView", Id, browserView.Id);
2317+
}
2318+
23082319
private JsonSerializer _jsonSerializer = new JsonSerializer()
23092320
{
23102321
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System.ComponentModel;
2+
3+
namespace ElectronNET.API.Entities
4+
{
5+
/// <summary>
6+
///
7+
/// </summary>
8+
public class AutoResizeOptions
9+
{
10+
/// <summary>
11+
/// If `true`, the view's width will grow and shrink together with the window.
12+
/// `false` by default.
13+
/// </summary>
14+
[DefaultValue(false)]
15+
public bool Width { get; set; } = false;
16+
17+
/// <summary>
18+
/// If `true`, the view's height will grow and shrink together with the window.
19+
/// `false` by default.
20+
/// </summary>
21+
[DefaultValue(false)]
22+
public bool Height { get; set; } = false;
23+
24+
/// <summary>
25+
/// If `true`, the view's x position and width will grow and shrink proportionally
26+
/// with the window. `false` by default.
27+
/// </summary>
28+
[DefaultValue(false)]
29+
public bool Horizontal { get; set; } = false;
30+
31+
/// <summary>
32+
/// If `true`, the view's y position and height will grow and shrink proportionally
33+
/// with the window. `false` by default.
34+
/// </summary>
35+
[DefaultValue(false)]
36+
public bool Vertical { get; set; } = false;
37+
}
38+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace ElectronNET.API.Entities
2+
{
3+
/// <summary>
4+
///
5+
/// </summary>
6+
public class BrowserViewConstructorOptions
7+
{
8+
/// <summary>
9+
/// See BrowserWindow.
10+
/// </summary>
11+
public WebPreferences WebPreferences { get; set; }
12+
}
13+
}

ElectronNET.API/WebContents.cs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,59 @@ public Task<string> GetUrl()
205205

206206
return taskCompletionSource.Task;
207207
}
208-
208+
209+
/// <summary>
210+
/// The async method will resolve when the page has finished loading,
211+
/// and rejects if the page fails to load.
212+
///
213+
/// A noop rejection handler is already attached, which avoids unhandled rejection
214+
/// errors.
215+
///
216+
/// Loads the `url` in the window. The `url` must contain the protocol prefix, e.g.
217+
/// the `http://` or `file://`. If the load should bypass http cache then use the
218+
/// `pragma` header to achieve it.
219+
/// </summary>
220+
/// <param name="url"></param>
221+
public Task LoadURLAsync(string url)
222+
{
223+
return LoadURLAsync(url, new LoadURLOptions());
224+
}
225+
226+
/// <summary>
227+
/// The async method will resolve when the page has finished loading,
228+
/// and rejects if the page fails to load.
229+
///
230+
/// A noop rejection handler is already attached, which avoids unhandled rejection
231+
/// errors.
232+
///
233+
/// Loads the `url` in the window. The `url` must contain the protocol prefix, e.g.
234+
/// the `http://` or `file://`. If the load should bypass http cache then use the
235+
/// `pragma` header to achieve it.
236+
/// </summary>
237+
/// <param name="url"></param>
238+
/// <param name="options"></param>
239+
public Task LoadURLAsync(string url, LoadURLOptions options)
240+
{
241+
var taskCompletionSource = new TaskCompletionSource<object>();
242+
243+
BridgeConnector.Socket.On("webContents-loadURL-complete" + Id, () =>
244+
{
245+
BridgeConnector.Socket.Off("webContents-loadURL-complete" + Id);
246+
BridgeConnector.Socket.Off("webContents-loadURL-error" + Id);
247+
taskCompletionSource.SetResult(null);
248+
});
249+
250+
BridgeConnector.Socket.On("webContents-loadURL-error" + Id, (error) =>
251+
{
252+
BridgeConnector.Socket.Off("webContents-loadURL-error" + Id);
253+
taskCompletionSource.SetException(new InvalidOperationException(error.ToString()));
254+
});
255+
256+
BridgeConnector.Socket.Emit("webContents-loadURL", Id, url, JObject.FromObject(options, _jsonSerializer));
257+
258+
return taskCompletionSource.Task;
259+
}
260+
209261
private JsonSerializer _jsonSerializer = new JsonSerializer()
210262
{
211263
ContractResolver = new CamelCasePropertyNamesContractResolver(),

ElectronNET.API/WindowManager.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ public bool IsQuitOnWindowAllClosed
6565
public IReadOnlyCollection<BrowserWindow> BrowserWindows { get { return _browserWindows.AsReadOnly(); } }
6666
private List<BrowserWindow> _browserWindows = new List<BrowserWindow>();
6767

68+
/// <summary>
69+
/// Gets the browser views.
70+
/// </summary>
71+
/// <value>
72+
/// The browser view.
73+
/// </value>
74+
public IReadOnlyCollection<BrowserView> BrowserViews { get { return _browserViews.AsReadOnly(); } }
75+
private List<BrowserView> _browserViews = new List<BrowserView>();
76+
6877
/// <summary>
6978
/// Creates the window asynchronous.
7079
/// </summary>
@@ -155,6 +164,51 @@ private bool isWindows10()
155164
return RuntimeInformation.OSDescription.Contains("Windows 10");
156165
}
157166

167+
/// <summary>
168+
/// A BrowserView can be used to embed additional web content into a BrowserWindow.
169+
/// It is like a child window, except that it is positioned relative to its owning window.
170+
/// It is meant to be an alternative to the webview tag.
171+
/// </summary>
172+
/// <returns></returns>
173+
public Task<BrowserView> CreateBrowserViewAsync()
174+
{
175+
return CreateBrowserViewAsync(new BrowserViewConstructorOptions());
176+
}
177+
178+
/// <summary>
179+
/// A BrowserView can be used to embed additional web content into a BrowserWindow.
180+
/// It is like a child window, except that it is positioned relative to its owning window.
181+
/// It is meant to be an alternative to the webview tag.
182+
/// </summary>
183+
/// <param name="options"></param>
184+
/// <returns></returns>
185+
public Task<BrowserView> CreateBrowserViewAsync(BrowserViewConstructorOptions options)
186+
{
187+
var taskCompletionSource = new TaskCompletionSource<BrowserView>();
188+
189+
BridgeConnector.Socket.On("BrowserViewCreated", (id) =>
190+
{
191+
BridgeConnector.Socket.Off("BrowserViewCreated");
192+
193+
string browserViewId = id.ToString();
194+
BrowserView browserView = new BrowserView(int.Parse(browserViewId));
195+
browserView.Destroyed += (b) => _browserViews.Remove(b);
196+
197+
_browserViews.Add(browserView);
198+
199+
taskCompletionSource.SetResult(browserView);
200+
});
201+
202+
var ownjsonSerializer = new JsonSerializer()
203+
{
204+
ContractResolver = new CamelCasePropertyNamesContractResolver(),
205+
NullValueHandling = NullValueHandling.Ignore
206+
};
207+
BridgeConnector.Socket.Emit("createBrowserView", JObject.FromObject(options, ownjsonSerializer));
208+
209+
return taskCompletionSource.Task;
210+
}
211+
158212
private JsonSerializer _jsonSerializer = new JsonSerializer()
159213
{
160214
ContractResolver = new CamelCasePropertyNamesContractResolver(),

ElectronNET.CLI/Commands/Actions/DeployEmbeddedElectronFiles.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public static void Do(string tempPath)
2929
EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "screen.js", "api.");
3030
EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "clipboard.js", "api.");
3131
EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "autoUpdater.js", "api.");
32+
EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "browserView.js", "api.");
3233

3334
string splashscreenFolder = Path.Combine(tempPath, "splashscreen");
3435
if (Directory.Exists(splashscreenFolder) == false)

ElectronNET.CLI/ElectronNET.CLI.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
<EmbeddedResource Include="..\ElectronNET.Host\api\webContents.js" Link="ElectronHost\api\webContents.js" />
6666
<EmbeddedResource Include="..\ElectronNET.Host\api\clipboard.js" Link="ElectronHost\api\clipboard.js" />
6767
<EmbeddedResource Include="..\ElectronNET.Host\api\autoUpdater.js" Link="ElectronHost\api\autoUpdater.js" />
68+
<EmbeddedResource Include="..\ElectronNET.Host\api\browserView.js" Link="ElectronHost\api\browserView.js" />
6869
</ItemGroup>
6970

7071
<ItemGroup>

0 commit comments

Comments
 (0)