// Copyright © 2015 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. using System; using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Text; using System.Threading.Tasks; using CefSharp.Internals; using CefSharp.Web; namespace CefSharp { /// /// WebBrowser extensions - These methods make performing common tasks easier. /// public static class WebBrowserExtensions { internal const string BrowserNotInitializedExceptionErrorMessage = "The ChromiumWebBrowser instance creates the underlying Chromium Embedded Framework (CEF) browser instance in an async fashion. " + "The undelying CefBrowser instance is not yet initialized. Use the IsBrowserInitializedChanged event and check " + "the IsBrowserInitialized property to determine when the browser has been initialized."; #region Legacy Javascript Binding /// /// Registers a Javascript object in this specific browser instance. /// /// The browser to perform the registering on. /// The name of the object. (e.g. "foo", if you want the object to be accessible as window.foo). /// The object to be made accessible to Javascript. /// (Optional) binding options - camelCaseJavascriptNames default to true. /// Browser is already initialized. RegisterJsObject must be + /// called before the underlying CEF browser is created. [Obsolete("This method has been removed, see https://github.com/cefsharp/CefSharp/issues/2990 for details on migrating your code.")] public static void RegisterJsObject(this IWebBrowser webBrowser, string name, object objectToBind, BindingOptions options = null) { throw new NotImplementedException("This method has been removed, see https://github.com/cefsharp/CefSharp/issues/2990 for details on migrating your code."); } /// /// Asynchronously registers a Javascript object in this specific browser instance. /// Only methods of the object will be availabe. /// /// The browser to perform the registering on /// The name of the object. (e.g. "foo", if you want the object to be accessible as window.foo). /// The object to be made accessible to Javascript. /// binding options - camelCaseJavascriptNames default to true /// Browser is already initialized. RegisterJsObject must be + /// called before the underlying CEF browser is created. /// The registered methods can only be called in an async way, they will all return immeditaly and the resulting /// object will be a standard javascript Promise object which is usable to wait for completion or failure. [Obsolete("This method has been removed, see https://github.com/cefsharp/CefSharp/issues/2990 for details on migrating your code.")] public static void RegisterAsyncJsObject(this IWebBrowser webBrowser, string name, object objectToBind, BindingOptions options = null) { throw new NotImplementedException("This method has been removed, see https://github.com/cefsharp/CefSharp/issues/2990 for details on migrating your code."); } #endregion /// /// Returns the main (top-level) frame for the browser window. /// /// the ChromiumWebBrowser instance. /// the main frame. public static IFrame GetMainFrame(this IWebBrowser browser) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); return cefBrowser.MainFrame; } /// /// Returns the focused frame for the browser window. /// /// the ChromiumWebBrowser instance. /// the focused frame. public static IFrame GetFocusedFrame(this IWebBrowser browser) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); return cefBrowser.FocusedFrame; } /// /// Execute Undo on the focused frame. /// /// The ChromiumWebBrowser instance this method extends. public static void Undo(this IWebBrowser browser) { using (var frame = browser.GetFocusedFrame()) { ThrowExceptionIfFrameNull(frame); frame.Undo(); } } /// /// Execute Redo on the focused frame. /// /// The ChromiumWebBrowser instance this method extends. public static void Redo(this IWebBrowser browser) { using (var frame = browser.GetFocusedFrame()) { ThrowExceptionIfFrameNull(frame); frame.Redo(); } } /// /// Execute Cut on the focused frame. /// /// The ChromiumWebBrowser instance this method extends. public static void Cut(this IWebBrowser browser) { using (var frame = browser.GetFocusedFrame()) { ThrowExceptionIfFrameNull(frame); frame.Cut(); } } /// /// Execute Copy on the focused frame. /// /// The ChromiumWebBrowser instance this method extends. public static void Copy(this IWebBrowser browser) { using (var frame = browser.GetFocusedFrame()) { ThrowExceptionIfFrameNull(frame); frame.Copy(); } } /// /// Execute Paste on the focused frame. /// /// The ChromiumWebBrowser instance this method extends. public static void Paste(this IWebBrowser browser) { using (var frame = browser.GetFocusedFrame()) { ThrowExceptionIfFrameNull(frame); frame.Paste(); } } /// /// Execute Delete on the focused frame. /// /// The ChromiumWebBrowser instance this method extends. public static void Delete(this IWebBrowser browser) { using (var frame = browser.GetFocusedFrame()) { ThrowExceptionIfFrameNull(frame); frame.Delete(); } } /// /// Execute SelectAll on the focused frame. /// /// The ChromiumWebBrowser instance this method extends. public static void SelectAll(this IWebBrowser browser) { using (var frame = browser.GetFocusedFrame()) { ThrowExceptionIfFrameNull(frame); frame.SelectAll(); } } /// /// Opens up a new program window (using the default text editor) where the source code of the currently displayed web page is /// shown. /// /// The ChromiumWebBrowser instance this method extends. public static void ViewSource(this IWebBrowser browser) { using (var frame = browser.GetMainFrame()) { ThrowExceptionIfFrameNull(frame); frame.ViewSource(); } } /// /// Retrieve the main frame's HTML source using a . /// /// The ChromiumWebBrowser instance this method extends. /// /// that when executed returns the main frame source as a string. /// public static Task GetSourceAsync(this IWebBrowser browser) { using (var frame = browser.GetMainFrame()) { ThrowExceptionIfFrameNull(frame); return frame.GetSourceAsync(); } } /// /// Retrieve the main frame's display text using a . /// /// The ChromiumWebBrowser instance this method extends. /// /// that when executed returns the main frame display text as a string. /// public static Task GetTextAsync(this IWebBrowser browser) { using (var frame = browser.GetMainFrame()) { ThrowExceptionIfFrameNull(frame); return frame.GetTextAsync(); } } /// /// Execute some Javascript code in the context of this WebBrowser. As the method name implies, the script will be executed /// asynchronously, and the method therefore returns before the script has actually been executed. This simple helper extension /// will encapsulate params in single quotes (unless int, uint, etc) /// /// The ChromiumWebBrowser instance this method extends. /// The javascript method name to execute. /// the arguments to be passed as params to the method. Args are encoded using /// , you can provide a custom implementation if you require a custom implementation. public static void ExecuteScriptAsync(this IWebBrowser browser, string methodName, params object[] args) { var script = GetScriptForJavascriptMethodWithArgs(methodName, args); browser.ExecuteScriptAsync(script); } /// /// Execute some Javascript code in the context of this WebBrowser. As the method name implies, the script will be executed /// asynchronously, and the method therefore returns before the script has actually been executed. /// /// The ChromiumWebBrowser instance this method extends. /// The Javascript code that should be executed. public static void ExecuteScriptAsync(this IWebBrowser browser, string script) { if (browser.CanExecuteJavascriptInMainFrame == false) { ThrowExceptionIfCanExecuteJavascriptInMainFrameFalse(); } using (var frame = browser.GetMainFrame()) { ThrowExceptionIfFrameNull(frame); frame.ExecuteJavaScriptAsync(script); } } /// /// Execute Javascript code in the context of this WebBrowser. This extension method uses the LoadingStateChanged event. As the /// method name implies, the script will be executed asynchronously, and the method therefore returns before the script has /// actually been executed. /// /// /// Best effort is made to make sure the script is executed, there are likely a few edge cases where the script won't be executed, /// if you suspect your script isn't being executed, then try executing in the LoadingStateChanged event handler to confirm that /// it does indeed get executed. /// /// The ChromiumWebBrowser instance this method extends. /// The Javascript code that should be executed. /// (Optional) The script will only be executed on first page load, subsiquent page loads will be ignored. public static void ExecuteScriptAsyncWhenPageLoaded(this IWebBrowser webBrowser, string script, bool oneTime = true) { var useLoadingStateChangedEventHandler = webBrowser.IsBrowserInitialized == false || oneTime == false; //Browser has been initialized, we check if there is a valid document and we're not loading if (webBrowser.IsBrowserInitialized) { //CefBrowser wrapper var browser = webBrowser.GetBrowser(); if (browser.HasDocument && browser.IsLoading == false) { webBrowser.ExecuteScriptAsync(script); } else { useLoadingStateChangedEventHandler = true; } } //If the browser hasn't been initialized we can just wire up the LoadingStateChanged event //If the script has already been executed and oneTime is false will be hooked up next page load. if (useLoadingStateChangedEventHandler) { EventHandler handler = null; handler = (sender, args) => { //Wait for while page to finish loading not just the first frame if (!args.IsLoading) { if (oneTime) { webBrowser.LoadingStateChanged -= handler; } webBrowser.ExecuteScriptAsync(script); } }; webBrowser.LoadingStateChanged += handler; } } /// /// Creates a new instance of IRequest with the specified Url and Method = POST and then calls /// . /// can only be used if a renderer process already exists. /// In newer versions initially loading about:blank no longer creates a renderer process. You can load a Data Uri initially then /// call this method. https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs. /// /// browser this method extends /// url to load /// post data as byte array /// (Optional) if set the Content-Type header will be set [Obsolete("This method will be removed in version 75 as it has become unreliable see https://github.com/cefsharp/CefSharp/issues/2705 for details.")] public static void LoadUrlWithPostData(this IWebBrowser browser, string url, byte[] postDataBytes, string contentType = null) { using (var frame = browser.GetMainFrame()) { ThrowExceptionIfFrameNull(frame); //Initialize Request with PostData var request = frame.CreateRequest(initializePostData: true); request.Url = url; request.Method = "POST"; //Add AllowStoredCredentials as per suggestion linked in //https://github.com/cefsharp/CefSharp/issues/2705#issuecomment-476819788 request.Flags = UrlRequestFlags.AllowStoredCredentials; request.PostData.AddData(postDataBytes); if (!string.IsNullOrEmpty(contentType)) { var headers = new NameValueCollection(); headers.Add("Content-Type", contentType); request.Headers = headers; } frame.LoadRequest(request); } } /// /// Registers and loads a that represents the HTML content. /// /// /// `Cef` Native `LoadHtml` is unpredictable and only works sometimes, this method wraps the provided HTML in a /// and loads the provided url using the method. Defaults to using /// for character encoding The url must start with a valid schema, other uri's such as about:blank /// are invalid A valid example looks like http://test/page. /// /// The ChromiumWebBrowser instance this method extends. /// The HTML content. /// The URL that will be treated as the address of the content. /// /// returns false if the Url was not successfully parsed into a Uri. /// public static bool LoadHtml(this IWebBrowser browser, string html, string url) { return browser.LoadHtml(html, url, Encoding.UTF8); } /// /// Loads html as Data Uri See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs for details If /// base64Encode is false then html will be Uri encoded. /// /// The ChromiumWebBrowser instance this method extends. /// Html to load as data uri. /// (Optional) if true the html string will be base64 encoded using UTF8 encoding. public static void LoadHtml(this IWebBrowser browser, string html, bool base64Encode = false) { var htmlString = new HtmlString(html, base64Encode); browser.Load(htmlString.ToDataUriString()); } /// /// Loads html as Data Uri See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs for details If /// base64Encode is false then html will be Uri encoded. /// /// The instance this method extends. /// Html to load as data uri. /// (Optional) if true the html string will be base64 encoded using UTF8 encoding. public static void LoadHtml(this IFrame frame, string html, bool base64Encode = false) { var htmlString = new HtmlString(html, base64Encode); frame.LoadUrl(htmlString.ToDataUriString()); } /// /// Registers and loads a that represents the HTML content. /// /// /// `Cef` Native `LoadHtml` is unpredictable and only works sometimes, this method wraps the provided HTML in a /// and loads the provided url using the method. /// /// Thrown when an exception error condition occurs. /// The ChromiumWebBrowser instance this method extends. /// The HTML content. /// The URL that will be treated as the address of the content. /// Character Encoding. /// (Optional) Whether or not the handler should be used once (true) or until manually unregistered /// (false) /// /// returns false if the Url was not successfully parsed into a Uri. /// public static bool LoadHtml(this IWebBrowser browser, string html, string url, Encoding encoding, bool oneTimeUse = false) { if (browser.ResourceRequestHandlerFactory == null) { browser.ResourceRequestHandlerFactory = new ResourceRequestHandlerFactory(); } var handler = browser.ResourceRequestHandlerFactory as ResourceRequestHandlerFactory; if (handler == null) { throw new Exception("LoadHtml can only be used with the default IResourceRequestHandlerFactory(DefaultResourceRequestHandlerFactory) implementation"); } if (handler.RegisterHandler(url, ResourceHandler.GetByteArray(html, encoding, true), ResourceHandler.DefaultMimeType, oneTimeUse)) { browser.Load(url); return true; } return false; } /// /// Register a ResourceHandler. Can only be used when browser.ResourceHandlerFactory is an instance of /// DefaultResourceHandlerFactory. /// /// Thrown when an exception error condition occurs. /// The ChromiumWebBrowser instance this method extends. /// the url of the resource to unregister. /// Stream to be registered, the stream should not be shared with any other instances of /// DefaultResourceHandlerFactory. /// (Optional) the mimeType. /// (Optional) Whether or not the handler should be used once (true) or until manually unregistered /// (false). If true the Stream will be Diposed of when finished. public static void RegisterResourceHandler(this IWebBrowser browser, string url, Stream stream, string mimeType = ResourceHandler.DefaultMimeType, bool oneTimeUse = false) { if (browser.ResourceRequestHandlerFactory == null) { browser.ResourceRequestHandlerFactory = new ResourceRequestHandlerFactory(); } var handler = browser.ResourceRequestHandlerFactory as ResourceRequestHandlerFactory; if (handler == null) { throw new Exception("RegisterResourceHandler can only be used with the default IResourceRequestHandlerFactory(DefaultResourceRequestHandlerFactory) implementation"); } using (var ms = new MemoryStream()) { stream.CopyTo(ms); handler.RegisterHandler(url, ms.ToArray(), mimeType, oneTimeUse); } } /// /// Unregister a ResourceHandler. Can only be used when browser.ResourceHandlerFactory is an instance of /// DefaultResourceHandlerFactory. /// /// Thrown when an exception error condition occurs. /// The ChromiumWebBrowser instance this method extends. /// the url of the resource to unregister. public static void UnRegisterResourceHandler(this IWebBrowser browser, string url) { var handler = browser.ResourceRequestHandlerFactory as ResourceRequestHandlerFactory; if (handler == null) { throw new Exception("UnRegisterResourceHandler can only be used with the default IResourceRequestHandlerFactory(DefaultResourceRequestHandlerFactory) implementation"); } handler.UnregisterHandler(url); } /// /// Stops loading the current page. /// /// The ChromiumWebBrowser instance this method extends. public static void Stop(this IWebBrowser browser) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.StopLoad(); } /// /// Navigates back, must check before calling this method. /// /// The ChromiumWebBrowser instance this method extends. public static void Back(this IWebBrowser browser) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.GoBack(); } /// /// Navigates forward, must check before calling this method. /// /// The ChromiumWebBrowser instance this method extends. public static void Forward(this IWebBrowser browser) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.GoForward(); } /// /// Reloads the page being displayed. This method will use data from the browser's cache, if available. /// /// The ChromiumWebBrowser instance this method extends. public static void Reload(this IWebBrowser browser) { browser.Reload(false); } /// /// Reloads the page being displayed, optionally ignoring the cache (which means the whole page including all .css, .js etc. /// resources will be re-fetched). /// /// The ChromiumWebBrowser instance this method extends. /// true A reload is performed ignoring browser cache; false A reload is performed using /// files from the browser cache, if available. public static void Reload(this IWebBrowser browser, bool ignoreCache) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.Reload(ignoreCache); } /// /// Gets the default cookie manager associated with the IWebBrowser. /// /// Thrown when an exception error condition occurs. /// The ChromiumWebBrowser instance this method extends. /// (Optional) If not null it will be executed asnychronously on the CEF IO thread after the manager's /// storage has been initialized. /// /// Cookie Manager. /// public static ICookieManager GetCookieManager(this IWebBrowser browser, ICompletionCallback callback = null) { var host = browser.GetBrowserHost(); ThrowExceptionIfBrowserHostNull(host); var requestContext = host.RequestContext; if (requestContext == null) { throw new Exception("RequestContext is null, unable to obtain cookie manager"); } return requestContext.GetCookieManager(callback); } /// /// Asynchronously gets the current Zoom Level. /// /// The ChromiumWebBrowser instance this method extends. /// /// An asynchronous result that yields the zoom level. /// public static Task GetZoomLevelAsync(this IBrowser cefBrowser) { var host = cefBrowser.GetHost(); ThrowExceptionIfBrowserHostNull(host); return host.GetZoomLevelAsync(); } /// /// Asynchronously gets the current Zoom Level. /// /// the ChromiumWebBrowser instance. /// /// An asynchronous result that yields the zoom level. /// public static Task GetZoomLevelAsync(this IWebBrowser browser) { var cefBrowser = browser.GetBrowser(); return cefBrowser.GetZoomLevelAsync(); } /// /// Change the ZoomLevel to the specified value. Can be set to 0.0 to clear the zoom level. /// /// /// If called on the CEF UI thread the change will be applied immediately. Otherwise, the change will be applied asynchronously /// on the CEF UI thread. The CEF UI thread is different to the WPF/WinForms UI Thread. /// /// The ChromiumWebBrowser instance this method extends. /// zoom level. public static void SetZoomLevel(this IBrowser cefBrowser, double zoomLevel) { cefBrowser.ThrowExceptionIfBrowserNull(); var host = cefBrowser.GetHost(); ThrowExceptionIfBrowserHostNull(host); host.SetZoomLevel(zoomLevel); } /// /// Change the ZoomLevel to the specified value. Can be set to 0.0 to clear the zoom level. /// /// /// If called on the CEF UI thread the change will be applied immediately. Otherwise, the change will be applied asynchronously /// on the CEF UI thread. The CEF UI thread is different to the WPF/WinForms UI Thread. /// /// The ChromiumWebBrowser instance this method extends. /// zoom level. public static void SetZoomLevel(this IWebBrowser browser, double zoomLevel) { var cefBrowser = browser.GetBrowser(); cefBrowser.SetZoomLevel(zoomLevel); } /// /// Search for text within the current page. /// /// The ChromiumWebBrowser instance this method extends. /// Can be used in can conjunction with searchText to have multiple searches running simultaneously. /// search text. /// indicates whether to search forward or backward within the page. /// indicates whether the search should be case-sensitive. /// indicates whether this is the first request or a follow-up. public static void Find(this IBrowser cefBrowser, int identifier, string searchText, bool forward, bool matchCase, bool findNext) { var host = cefBrowser.GetHost(); ThrowExceptionIfBrowserHostNull(host); host.Find(identifier, searchText, forward, matchCase, findNext); } /// /// Search for text within the current page. /// /// The ChromiumWebBrowser instance this method extends. /// Can be used in can conjunction with searchText to have multiple searches running simultaneously. /// search text. /// indicates whether to search forward or backward within the page. /// indicates whether the search should be case-sensitive. /// indicates whether this is the first request or a follow-up. public static void Find(this IWebBrowser browser, int identifier, string searchText, bool forward, bool matchCase, bool findNext) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.Find(identifier, searchText, forward, matchCase, findNext); } /// /// Cancel all searches that are currently going on. /// /// The ChromiumWebBrowser instance this method extends. /// clear the current search selection. public static void StopFinding(this IBrowser cefBrowser, bool clearSelection) { cefBrowser.ThrowExceptionIfBrowserNull(); var host = cefBrowser.GetHost(); ThrowExceptionIfBrowserHostNull(host); host.StopFinding(clearSelection); } /// /// Cancel all searches that are currently going on. /// /// The ChromiumWebBrowser instance this method extends. /// clear the current search selection. public static void StopFinding(this IWebBrowser browser, bool clearSelection) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.StopFinding(clearSelection); } /// /// Opens a Print Dialog which if used (can be user cancelled) will print the browser contents. /// /// The ChromiumWebBrowser instance this method extends. public static void Print(this IBrowser cefBrowser) { var host = cefBrowser.GetHost(); ThrowExceptionIfBrowserHostNull(host); host.Print(); } /// /// Asynchronously prints the current browser contents to the PDF file specified. The caller is responsible for deleting the file /// when done. /// /// The object this method extends. /// Output file location. /// (Optional) Print Settings. /// /// A task that represents the asynchronous print operation. The result is true on success or false on failure to generate the /// Pdf. /// public static Task PrintToPdfAsync(this IBrowser cefBrowser, string path, PdfPrintSettings settings = null) { var host = cefBrowser.GetHost(); ThrowExceptionIfBrowserHostNull(host); var callback = new TaskPrintToPdfCallback(); host.PrintToPdf(path, settings, callback); return callback.Task; } /// /// Opens a Print Dialog which if used (can be user cancelled) will print the browser contents. /// /// The ChromiumWebBrowser instance this method extends. public static void Print(this IWebBrowser browser) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.Print(); } /// /// Asynchronously prints the current browser contents to the PDF file specified. The caller is responsible for deleting the file /// when done. /// /// The ChromiumWebBrowser instance this method extends. /// Output file location. /// (Optional) Print Settings. /// /// A task that represents the asynchronous print operation. The result is true on success or false on failure to generate the /// Pdf. /// public static Task PrintToPdfAsync(this IWebBrowser browser, string path, PdfPrintSettings settings = null) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); return cefBrowser.PrintToPdfAsync(path, settings); } /// /// Open developer tools in its own window. /// /// The ChromiumWebBrowser instance this method extends. /// (Optional) window info used for showing dev tools. /// (Optional) x coordinate (used for inspectElement) /// (Optional) y coordinate (used for inspectElement) public static void ShowDevTools(this IBrowser cefBrowser, IWindowInfo windowInfo = null, int inspectElementAtX = 0, int inspectElementAtY = 0) { var host = cefBrowser.GetHost(); ThrowExceptionIfBrowserHostNull(host); host.ShowDevTools(windowInfo, inspectElementAtX, inspectElementAtY); } /// /// Open developer tools in its own window. /// /// The ChromiumWebBrowser instance this method extends. /// (Optional) window info used for showing dev tools. /// (Optional) x coordinate (used for inspectElement) /// (Optional) y coordinate (used for inspectElement) public static void ShowDevTools(this IWebBrowser browser, IWindowInfo windowInfo = null, int inspectElementAtX = 0, int inspectElementAtY = 0) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.ShowDevTools(windowInfo, inspectElementAtX, inspectElementAtY); } /// /// Explicitly close the developer tools window if one exists for this browser instance. /// /// The ChromiumWebBrowser instance this method extends. public static void CloseDevTools(this IBrowser cefBrowser) { var host = cefBrowser.GetHost(); ThrowExceptionIfBrowserHostNull(host); host.CloseDevTools(); } /// /// Explicitly close the developer tools window if one exists for this browser instance. /// /// The ChromiumWebBrowser instance this method extends. public static void CloseDevTools(this IWebBrowser browser) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.CloseDevTools(); } /// /// If a misspelled word is currently selected in an editable node calling this method will replace it with the specified word. /// /// The ChromiumWebBrowser instance this method extends. /// The new word that will replace the currently selected word. public static void ReplaceMisspelling(this IBrowser cefBrowser, string word) { var host = cefBrowser.GetHost(); ThrowExceptionIfBrowserHostNull(host); host.ReplaceMisspelling(word); } /// /// If a misspelled word is currently selected in an editable node calling this method will replace it with the specified word. /// /// The ChromiumWebBrowser instance this method extends. /// The new word that will replace the currently selected word. public static void ReplaceMisspelling(this IWebBrowser browser, string word) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.ReplaceMisspelling(word); } /// /// Add the specified word to the spelling dictionary. /// /// The ChromiumWebBrowser instance this method extends. /// The new word that will be added to the dictionary. public static void AddWordToDictionary(this IBrowser cefBrowser, string word) { var host = cefBrowser.GetHost(); ThrowExceptionIfBrowserHostNull(host); host.AddWordToDictionary(word); } /// /// Shortcut method to get the browser IBrowserHost. /// /// The ChromiumWebBrowser instance this method extends. /// /// browserHost or null. /// public static IBrowserHost GetBrowserHost(this IWebBrowser browser) { var cefBrowser = browser.GetBrowser(); return cefBrowser == null ? null : cefBrowser.GetHost(); } /// /// Add the specified word to the spelling dictionary. /// /// The ChromiumWebBrowser instance this method extends. /// The new word that will be added to the dictionary. public static void AddWordToDictionary(this IWebBrowser browser, string word) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.AddWordToDictionary(word); } /// /// Send a mouse wheel event to the browser. /// /// The ChromiumWebBrowser instance this method extends. /// The x coordinate relative to upper-left corner of view. /// The y coordinate relative to upper-left corner of view. /// The delta x coordinate. /// The delta y coordinate. /// The modifiers. public static void SendMouseWheelEvent(this IWebBrowser browser, int x, int y, int deltaX, int deltaY, CefEventFlags modifiers) { var cefBrowser = browser.GetBrowser(); cefBrowser.ThrowExceptionIfBrowserNull(); cefBrowser.SendMouseWheelEvent(x, y, deltaX, deltaY, modifiers); } /// /// Send a mouse wheel event to the browser. /// /// The ChromiumWebBrowser instance this method extends. /// The x coordinate relative to upper-left corner of view. /// The y coordinate relative to upper-left corner of view. /// The delta x coordinate. /// The delta y coordinate. /// The modifiers. public static void SendMouseWheelEvent(this IBrowser browser, int x, int y, int deltaX, int deltaY, CefEventFlags modifiers) { browser.ThrowExceptionIfBrowserNull(); var host = browser.GetHost(); ThrowExceptionIfBrowserHostNull(host); host.SendMouseWheelEvent(new MouseEvent(x, y, modifiers), deltaX, deltaY); } /// /// Send a mouse wheel event to the browser. /// /// browserHost. /// The x coordinate relative to upper-left corner of view. /// The y coordinate relative to upper-left corner of view. /// The delta x coordinate. /// The delta y coordinate. /// The modifiers. public static void SendMouseWheelEvent(this IBrowserHost host, int x, int y, int deltaX, int deltaY, CefEventFlags modifiers) { ThrowExceptionIfBrowserHostNull(host); host.SendMouseWheelEvent(new MouseEvent(x, y, modifiers), deltaX, deltaY); } /// /// Send a mouse click event to the browser. /// /// browserHost. /// The x coordinate relative to upper-left corner of view. /// The y coordinate relative to upper-left corner of view. /// Type of the mouse button. /// True to mouse up. /// Number of clicks. /// The modifiers. public static void SendMouseClickEvent(this IBrowserHost host, int x, int y, MouseButtonType mouseButtonType, bool mouseUp, int clickCount, CefEventFlags modifiers) { ThrowExceptionIfBrowserHostNull(host); host.SendMouseClickEvent(new MouseEvent(x, y, modifiers), mouseButtonType, mouseUp, clickCount); } /// /// Send a mouse move event to the browser. /// /// browserHost. /// The x coordinate relative to upper-left corner of view. /// The y coordinate relative to upper-left corner of view. /// mouse leave. /// The modifiers. public static void SendMouseMoveEvent(this IBrowserHost host, int x, int y, bool mouseLeave, CefEventFlags modifiers) { ThrowExceptionIfBrowserHostNull(host); host.SendMouseMoveEvent(new MouseEvent(x, y, modifiers), mouseLeave); } /// /// Evaluate some Javascript code in the context of the MainFrame of the ChromiumWebBrowser. The script will be executed /// asynchronously and the method returns a Task encapsulating the response from the Javascript This simple helper extension will /// encapsulate params in single quotes (unless int, uint, etc) /// /// Thrown when one or more arguments are outside the required range. /// The ChromiumWebBrowser instance this method extends. /// The Javascript code that should be executed. /// (Optional) The timeout after which the Javascript code execution should be aborted. /// /// that can be awaited to perform the script execution. /// public static Task EvaluateScriptAsync(this IWebBrowser browser, string script, TimeSpan? timeout = null) { if (timeout.HasValue && timeout.Value.TotalMilliseconds > UInt32.MaxValue) { throw new ArgumentOutOfRangeException("timeout", "Timeout greater than Maximum allowable value of " + UInt32.MaxValue); } if (browser.CanExecuteJavascriptInMainFrame == false) { ThrowExceptionIfCanExecuteJavascriptInMainFrameFalse(); } using (var frame = browser.GetMainFrame()) { ThrowExceptionIfFrameNull(frame); return frame.EvaluateScriptAsync(script, timeout: timeout); } } /// /// Evaluate some Javascript code in the context of this WebBrowser. The script will be executed asynchronously and the method /// returns a Task encapsulating the response from the Javascript This simple helper extension will encapsulate params in single /// quotes (unless int, uint, etc) /// /// The ChromiumWebBrowser instance this method extends. /// The javascript method name to execute. /// the arguments to be passed as params to the method. /// /// that can be awaited to perform the script execution. /// public static Task EvaluateScriptAsync(this IWebBrowser browser, string methodName, params object[] args) { return browser.EvaluateScriptAsync(null, methodName, args); } /// /// Evaluate some Javascript code in the context of this WebBrowser using the specified timeout. The script will be executed /// asynchronously and the method returns a Task encapsulating the response from the Javascript This simple helper extension will /// encapsulate params in single quotes (unless int, uint, etc). /// /// The ChromiumWebBrowser instance this method extends. /// The timeout after which the Javascript code execution should be aborted. /// The javascript method name to execute. /// the arguments to be passed as params to the method. Args are encoded using /// , you can provide a custom implementation if you require a custom implementation. /// /// that can be awaited to perform the script execution. /// public static Task EvaluateScriptAsync(this IWebBrowser browser, TimeSpan? timeout, string methodName, params object[] args) { var script = GetScriptForJavascriptMethodWithArgs(methodName, args); return browser.EvaluateScriptAsync(script, timeout); } /// /// An IWebBrowser extension method that sets the /// property used when passing a ChromiumWebBrowser instance to /// /// The ChromiumWebBrowser instance this method extends. public static void SetAsPopup(this IWebBrowser browser) { var internalBrowser = (IWebBrowserInternal)browser; internalBrowser.HasParent = true; } /// /// Function used to encode the params passed to , /// and /// /// Provide your own custom function to perform custom encoding. You can use your choice of JSON encoder here if you should so /// choose. /// /// /// A function delegate that yields a string. /// public static Func EncodeScriptParam { get; set; } = (str) => { return str.Replace("\\", "\\\\") .Replace("'", "\\'") .Replace("\t", "\\t") .Replace("\r", "\\r") .Replace("\n", "\\n"); }; /// /// Checks if the given object is a numerical object. /// /// The object to check. /// /// True if numeric, otherwise false. /// private static bool IsNumeric(this object value) { return value is sbyte || value is byte || value is short || value is ushort || value is int || value is uint || value is long || value is ulong || value is float || value is double || value is decimal; } /// /// Transforms the methodName and arguments into valid Javascript code. Will encapsulate params in single quotes (unless int, /// uint, etc) /// /// The javascript method name to execute. /// the arguments to be passed as params to the method. /// /// The Javascript code. /// public static string GetScriptForJavascriptMethodWithArgs(string methodName, object[] args) { var stringBuilder = new StringBuilder(); stringBuilder.Append(methodName); stringBuilder.Append("("); if (args.Length > 0) { for (int i = 0; i < args.Length; i++) { var obj = args[i]; if (obj == null) { stringBuilder.Append("null"); } else if (obj.IsNumeric()) { stringBuilder.Append(Convert.ToString(args[i], CultureInfo.InvariantCulture)); } else if (obj is bool) { stringBuilder.Append(args[i].ToString().ToLowerInvariant()); } else { stringBuilder.Append("'"); stringBuilder.Append(EncodeScriptParam(obj.ToString())); stringBuilder.Append("'"); } stringBuilder.Append(", "); } //Remove the trailing comma stringBuilder.Remove(stringBuilder.Length - 2, 2); } stringBuilder.Append(");"); return stringBuilder.ToString(); } /// /// An IWebBrowser extension method that throw exception if browser not initialized. /// /// /// Not used in WPF as IsBrowserInitialized is a dependency property and can only be checked on the UI thread(throws /// InvalidOperationException if called on another Thread). /// /// Thrown when an exception error condition occurs. /// The ChromiumWebBrowser instance this method extends. internal static void ThrowExceptionIfBrowserNotInitialized(this IWebBrowser browser) { if (!browser.IsBrowserInitialized) { throw new Exception(BrowserNotInitializedExceptionErrorMessage); } } /// /// An IWebBrowser extension method that throw exception if disposed. /// /// Thrown when a supplied object has been disposed. /// The ChromiumWebBrowser instance this method extends. internal static void ThrowExceptionIfDisposed(this IWebBrowser browser) { if (browser.IsDisposed) { throw new ObjectDisposedException("browser", "Browser has been disposed"); } } /// /// Throw exception if frame null. /// /// Thrown when an exception error condition occurs. /// The instance this method extends. private static void ThrowExceptionIfFrameNull(IFrame frame) { if (frame == null) { throw new Exception("IFrame instance is null. Browser has likely not finished initializing or is in the process of disposing."); } } /// /// An IBrowser extension method that throw exception if browser null. /// /// Thrown when an exception error condition occurs. /// The ChromiumWebBrowser instance this method extends. private static void ThrowExceptionIfBrowserNull(this IBrowser browser) { if (browser == null) { throw new Exception("IBrowser instance is null. Browser has likely not finished initializing or is in the process of disposing."); } } /// /// Throw exception if browser host null. /// /// Thrown when an exception error condition occurs. /// The browser host. private static void ThrowExceptionIfBrowserHostNull(IBrowserHost browserHost) { if (browserHost == null) { throw new Exception("IBrowserHost instance is null. Browser has likely not finished initializing or is in the process of disposing."); } } /// /// Throw exception if can execute javascript in main frame false. /// /// Thrown when an exception error condition occurs. private static void ThrowExceptionIfCanExecuteJavascriptInMainFrameFalse() { throw new Exception("Unable to execute javascript at this time, scripts can only be executed within a V8Context. " + "Use the IWebBrowser.CanExecuteJavascriptInMainFrame property to guard against this exception. " + "See https://github.com/cefsharp/CefSharp/wiki/General-Usage#when-can-i-start-executing-javascript " + "for more details on when you can execute javascript. For frames that do not contain Javascript then no " + "V8Context will be created. Executing a script once the frame has loaded it's possible to create a V8Context. " + "You can use browser.GetMainFrame().ExecuteJavaScriptAsync(script) or browser.GetMainFrame().EvaluateScriptAsync " + "to bypass these checks (advanced users only)."); } } }