// 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).");
}
}
}