using System; using System.Threading.Tasks; using ElectronNET.API.Entities; using ElectronNET.Common; // ReSharper disable InconsistentNaming namespace ElectronNET.API; /// /// Render and control web pages. /// public class WebContents : ApiBase { protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst; protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst; protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.CamelCase; /// /// Gets the identifier. /// /// /// The identifier. /// public override int Id { get; protected set; } /// /// Manage browser sessions, cookies, cache, proxy settings, etc. /// public Session Session { get; internal set; } /// /// Emitted when the renderer process crashes or is killed. /// public event Action OnCrashed { add => AddEvent(value, Id); remove => RemoveEvent(value, Id); } /// /// Emitted when the navigation is done, i.e. the spinner of the tab has /// stopped spinning, and the onload event was dispatched. /// public event Action OnDidFinishLoad { add => AddEvent(value, Id); remove => RemoveEvent(value, Id); } /// /// Emitted when any frame (including main) starts navigating. /// public event Action OnDidStartNavigation { add => AddEvent(value, Id); remove => RemoveEvent(value, Id); } /// /// Emitted when a main frame navigation is done. /// This event is not emitted for in-page navigations, such as clicking anchor links or updating the window.location.hash. Use did-navigate-in-page event for this purpose. /// public event Action OnDidNavigate { add => AddEvent(value, Id); remove => RemoveEvent(value, Id); } /// /// Emitted when a server side redirect occurs during navigation. For example a 302 redirect. /// This event will be emitted after OnDidStartNavigation and always before the OnDidRedirectNavigation event for the same navigation. /// public event Action OnWillRedirect { add => AddEvent(value, Id); remove => RemoveEvent(value, Id); } /// /// Emitted after a server side redirect occurs during navigation. For example a 302 redirect. /// public event Action OnDidRedirectNavigation { add => AddEvent(value, Id); remove => RemoveEvent(value, Id); } /// /// This event is like OnDidFinishLoad but emitted when the load failed. /// public event Action OnDidFailLoad { add => AddEvent(value, Id); remove => RemoveEvent(value, Id); } /// /// Emitted when an input event is sent to the WebContents. /// public event Action InputEvent { add => AddEvent(value, Id); remove => RemoveEvent(value, Id); } /// /// Emitted when the document in the top-level frame is loaded. /// public event Action OnDomReady { add => AddEvent(value, Id); remove => RemoveEvent(value, Id); } internal WebContents(int id) { Id = id; Session = new Session(id); } /// /// Opens the devtools. /// public void OpenDevTools() { BridgeConnector.Socket.Emit("webContents-openDevTools", Id); } /// /// Opens the devtools. /// /// public void OpenDevTools(OpenDevToolsOptions openDevToolsOptions) { BridgeConnector.Socket.Emit("webContents-openDevTools", Id, openDevToolsOptions); } /// /// Toggles the devtools. /// public void ToggleDevTools() { BridgeConnector.Socket.Emit("webContents-toggleDevTools", Id); } /// /// Closes the devtools. /// public void CloseDevTools() { BridgeConnector.Socket.Emit("webContents-closeDevTools", Id); } /// /// Returns boolean - Whether the devtools is opened. /// /// public bool IsDevToolsOpened() { return Task.Run(() => InvokeAsync()).Result; } /// /// Returns boolean - Whether the devtools view is focused. /// /// public bool IsDevToolsFocused() { return Task.Run(() => InvokeAsync()).Result; } /// /// Get system printers. /// /// printers public Task GetPrintersAsync() => this.InvokeAsyncWithTimeout(8.seconds()); /// /// Prints window's web page. /// /// /// success public Task PrintAsync(PrintOptions options) => this.InvokeAsync(options); /// /// Prints window's web page. /// /// success public Task PrintAsync() => this.InvokeAsync(string.Empty); /// /// Prints window's web page as PDF with Chromium's preview printing custom /// settings.The landscape will be ignored if @page CSS at-rule is used in the web page. /// By default, an empty options will be regarded as: Use page-break-before: always; /// CSS style to force to print to a new page. /// /// /// /// success public Task PrintToPDFAsync(string path, PrintToPDFOptions options = null) { var tcs = new TaskCompletionSource(); BridgeConnector.Socket.Once("webContents-printToPDF-completed", tcs.SetResult); if (options == null) { BridgeConnector.Socket.Emit("webContents-printToPDF", Id, "", path); } else { BridgeConnector.Socket.Emit("webContents-printToPDF", Id, options, path); } return tcs.Task; } /// /// Evaluates script code in page. /// /// The code to execute. /// if set to true simulate a user gesture. /// The result of the executed code. /// /// /// In the browser window some HTML APIs like `requestFullScreen` can only be /// invoked by a gesture from the user. Setting `userGesture` to `true` will remove /// this limitation. /// /// /// Code execution will be suspended until web page stop loading. /// /// public Task ExecuteJavaScriptAsync(string code, bool userGesture = false) { var tcs = new TaskCompletionSource(); BridgeConnector.Socket.Once("webContents-executeJavaScript-completed", tcs.SetResult); BridgeConnector.Socket.Emit("webContents-executeJavaScript", Id, code, userGesture); return tcs.Task; } /// /// Is used to get the Url of the loaded page. /// It's usefull if a web-server redirects you and you need to know where it redirects. For instance, It's useful in case of Implicit Authorization. /// /// URL of the loaded page public Task GetUrl() { var tcs = new TaskCompletionSource(); BridgeConnector.Socket.Once("webContents-getUrl" + Id, tcs.SetResult); BridgeConnector.Socket.Emit("webContents-getUrl", Id); return tcs.Task; } /// /// The async method will resolve when the page has finished loading, /// and rejects if the page fails to load. /// /// A noop rejection handler is already attached, which avoids unhandled rejection /// errors. /// /// Loads the `url` in the window. The `url` must contain the protocol prefix, e.g. /// the `http://` or `file://`. If the load should bypass http cache then use the /// `pragma` header to achieve it. /// /// public Task LoadURLAsync(string url) { return LoadURLAsync(url, new LoadURLOptions()); } /// /// The async method will resolve when the page has finished loading, /// and rejects if the page fails to load. /// /// A noop rejection handler is already attached, which avoids unhandled rejection /// errors. /// /// Loads the `url` in the window. The `url` must contain the protocol prefix, e.g. /// the `http://` or `file://`. If the load should bypass http cache then use the /// `pragma` header to achieve it. /// /// /// public Task LoadURLAsync(string url, LoadURLOptions options) { var tcs = new TaskCompletionSource(); BridgeConnector.Socket.Once("webContents-loadURL-complete" + Id, () => { BridgeConnector.Socket.Off("webContents-loadURL-error" + Id); tcs.SetResult(); }); BridgeConnector.Socket.Once("webContents-loadURL-error" + Id, (error) => { tcs.SetException(new InvalidOperationException(error)); }); BridgeConnector.Socket.Emit("webContents-loadURL", Id, url, options); return tcs.Task; } /// /// Inserts CSS into the web page. /// See: https://www.electronjs.org/docs/api/web-contents#contentsinsertcsscss-options /// Works for both BrowserWindows and BrowserViews. /// /// Whether the webContents belong to a BrowserWindow or not (the other option is a BrowserView) /// Absolute path to the CSS file location public void InsertCSS(bool isBrowserWindow, string path) { BridgeConnector.Socket.Emit("webContents-insertCSS", Id, isBrowserWindow, path); } /// /// Returns number - The current zoom factor. /// /// public Task GetZoomFactorAsync() => InvokeAsync(); /// /// Changes the zoom factor to the specified factor. /// Zoom factor is zoom percent divided by 100, so 300% = 3.0. /// The factor must be greater than 0.0. /// /// public void SetZoomFactor(double factor) { BridgeConnector.Socket.Emit("webContents-setZoomFactor", Id, factor); } /// /// Returns number - The current zoom level. /// /// public Task GetZoomLevelAsync() => InvokeAsync(); /// /// Changes the zoom level to the specified level. /// The original size is 0 and each increment above or below represents zooming 20% larger or smaller to default limits of 300% and 50% of original size, respectively. /// /// public void SetZoomLevel(int level) { BridgeConnector.Socket.Emit("webContents-setZoomLevel", Id, level); } /// /// Sets the maximum and minimum pinch-to-zoom level. /// /// /// public Task SetVisualZoomLevelLimitsAsync(int minimumLevel, int maximumLevel) { var tcs = new TaskCompletionSource(); BridgeConnector.Socket.Once("webContents-setVisualZoomLevelLimits-completed", tcs.SetResult); BridgeConnector.Socket.Emit("webContents-setVisualZoomLevelLimits", Id, minimumLevel, maximumLevel); return tcs.Task; } /// /// Returns boolean - Whether this page has been muted. /// /// public Task IsAudioMutedAsync() => InvokeAsync(); /// /// Returns boolean - Whether audio is currently playing. /// /// public Task IsCurrentlyAudibleAsync() => InvokeAsync(); /// /// Mute the audio on the current web page. /// /// public void SetAudioMuted(bool muted) { BridgeConnector.Socket.Emit("webContents-setAudioMuted", Id, muted); } /// /// Returns string - The user agent for this web page. /// /// public Task GetUserAgentAsync() => InvokeAsyncWithTimeout(3.seconds()); /// /// Overrides the user agent for this web page. /// /// public void SetUserAgent(string userAgent) { BridgeConnector.Socket.Emit("webContents-setUserAgent", Id, userAgent); } }