Skip to content

Instantly share code, notes, and snippets.

@AlexP11223
Last active March 21, 2017 19:35
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save AlexP11223/8286153 to your computer and use it in GitHub Desktop.
Save AlexP11223/8286153 to your computer and use it in GitHub Desktop.
using System;
using Awesomium.Core;
namespace WebViewHelpers
{
public static class WebViewExtensions
{
/// <summary>
/// Simulates mouse movement to the specified coordinates and click.
/// As I remember it requires coordinates relative to the currently displayed area, and also will not work if specified coordinates are out of that area.
/// </summary>
public static void Click(this IWebView webView, int x, int y)
{
webView.InjectMouseMove(x, y);
webView.InjectMouseDown(MouseButton.Left);
webView.InjectMouseUp(MouseButton.Left);
}
/// <summary>
/// Simulates mouse movement to the specified coordinates and click.
/// As I remember it requires coordinates relative to the currently displayed area, and also will not work if specified coordinates are out of that area.
/// </summary>
public static void Click(this IWebView webView, Point p)
{
webView.Click(p.X, p.Y);
}
/// <summary>
/// Fires specified event on element specified by any Javascript query for getting a single element.
/// </summary>
/// <param name="getElementQuery">
/// <para>Any Javascript query to get an element.</para>
/// <para>Examples:</para>
/// <para>"document.getElementById('id')"</para>
/// <para>"document.getElementsByClassName('name')[0]"</para>
/// <para>"document.evaluate(\"//a[contains(@href, 'something')]\", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue" (XPath)</para>
/// </param>
/// <param name="eventName">Event name such as "click", "mouseup"</param>
public static void JsFireEvent(this IWebView webView, string getElementQuery, string eventName)
{
webView.ExecuteJavascript(@"
function fireEvent(element,event) {
var evt = document.createEvent('HTMLEvents');
evt.initEvent(event, true, false ); // event type,bubbling,cancelable
element.dispatchEvent(evt);
}
" + String.Format("fireEvent({0}, '{1}');", getElementQuery, eventName));
}
/// <summary>
/// <para>(Mostly for backward-compatibility for code when JsFireEvent didn't exist.)</para>
/// <para>Some elements like &lt;a&gt; does not have click() method (although it works in Chrome), so this method works for them.</para>
/// </summary>
/// <param name="getElementQuery">
/// <para>Any Javascript query to get an element.</para>
/// <para>Examples:</para>
/// <para>"document.getElementById('id')"</para>
/// <para>"document.getElementsByClassName('name')[0]"</para>
/// <para>"document.evaluate(\"//a[contains(@href, 'something')]\", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue" (XPath)</para>
/// </param>
public static void ImprovedJsClick(this IWebView webView, string getElementQuery)
{
//webView.JsFireEvent(getElementQuery, "click"); // probably can replace to this
webView.ExecuteJavascript(@"
function clickEvent(obj){
var fireOnThis = obj;
var evObj = document.createEvent('MouseEvents');
evObj.initEvent( 'click', true, false );
fireOnThis.dispatchEvent(evObj);
}
" + String.Format("clickEvent({0});", getElementQuery));
}
/// <summary>
/// <para>Sends key/character to focused element.</para>
/// <para>Examples:</para>
/// <para>TypeKey(VirtualKey.A, "A"); // uppercase A</para>
/// <para>TypeKey(VirtualKey.B, "b"); // lowercase b</para>
/// <para>TypeKey(VirtualKey.DOWN, ""); // down arrow</para>
/// <para>TypeKey(VirtualKey.RETURN, "\r\n"); // Enter</para>
/// </summary>
public static void TypeKey(this IWebView webView, VirtualKey vk, string chr)
{
var keyEvent = new WebKeyboardEvent();
keyEvent.Type = WebKeyboardEventType.KeyDown;
keyEvent.VirtualKeyCode = vk;
webView.InjectKeyboardEvent(keyEvent);
keyEvent.Type = WebKeyboardEventType.Char;
keyEvent.Text = chr;
webView.InjectKeyboardEvent(keyEvent);
keyEvent.Type = WebKeyboardEventType.KeyUp;
keyEvent.VirtualKeyCode = vk;
webView.InjectKeyboardEvent(keyEvent);
}
/// <summary>
/// Returns HTML code string of the page
/// </summary>
public static string GetHtml(this IWebView webView)
{
return webView.ExecuteJavascriptWithResult("document.getElementsByTagName('html')[0].innerHTML");
}
/// <summary>
/// Finds and returns element (JSObject) by id using document.getElementById
/// </summary>
public static dynamic GetElementById(this IWebView webView, string id)
{
dynamic element = (JSObject)webView.ExecuteJavascriptWithResult(String.Format("document.getElementById('{0}')", id));
return element;
}
/// <summary>
/// Finds and returns elements (JSObject array) by name using document.getElementsByName
/// </summary>
public static dynamic GetElementsByName(this IWebView webView, string name)
{
dynamic elements = (JSObject)webView.ExecuteJavascriptWithResult(String.Format("document.getElementsByName('{0}')", name));
return elements;
}
/// <summary>
/// Finds and returns elements (JSObject array) by tag using document.getElementsByTagName
/// </summary>
public static dynamic GetElementsByTagName(this IWebView webView, string tag)
{
dynamic elements = (JSObject)webView.ExecuteJavascriptWithResult(String.Format("document.getElementsByTagName('{0}')", tag));
return elements;
}
/// <summary>
/// Finds and returns elements (JSObject array) by class using document.getElementsByClassName
/// </summary>
public static dynamic GetElementsByClassName(this IWebView webView, string className)
{
dynamic elements = (JSObject)webView.ExecuteJavascriptWithResult(String.Format("document.getElementsByClassName('{0}')", className));
return elements;
}
/// <summary>
/// Fills the textbox with the specified text
/// </summary>
public static void FillTextbox(IWebView webView, dynamic textbox, string value)
{
textbox.focus();
textbox.value = value;
}
/// <summary>
/// Finds textbox by id (using GetElementById) and fills with the specified text
/// </summary>
public static void FillTextboxById(this IWebView webView, string id, string value)
{
using (dynamic textbox = webView.GetElementById(id))
{
if (textbox == null)
throw new Exception("Element " + id + " was not found.");
FillTextbox(webView, textbox, value);
}
}
/// <summary>
/// Finds textbox by name (using GetElementsByName, the first one if more than one exist) and fills with the specified text
/// </summary>
public static void FillTextboxByName(this IWebView webView, string name, string value)
{
using (dynamic elements = webView.GetElementsByName(name))
{
if (elements == null || elements.length == 0)
throw new Exception("No elements with name " + name + " were found.");
using (dynamic textbox = elements[0])
{
FillTextbox(webView, textbox, value);
}
}
}
/// <summary>
/// Finds and clicks button by id (using GetElementById)
/// </summary>
public static void ClickButtonById(this IWebView webView, string id)
{
using (dynamic button = webView.GetElementById(id))
{
if (button == null)
throw new Exception("Element " + id + " was not found.");
button.click();
}
}
/// <summary>
/// Finds and clicks button by name (using GetElementsByName, the first one if more than one exist)
/// </summary>
public static void ClickButtonByName(this IWebView webView, string name)
{
using (dynamic buttons = webView.GetElementsByName(name))
{
if (buttons == null || buttons.length == 0)
throw new Exception("No elements with name " + name + " were found.");
using (dynamic btn = buttons[0])
{
btn.click();
}
}
}
/// <summary>
/// Finds and clicks button by tag + value (the first one if more than one exist)
/// <para>Could be slow if there are many elements with this tag on the page, use XPath instead</para>
/// </summary>
public static void ClickButtonByValue(this IWebView webView, string value, string tag = "input")
{
using (dynamic elements = webView.GetElementsByTagName(tag))
{
if (elements == null || elements.length == 0)
throw new Exception("Failed to get page input elements.");
int len = elements.length;
for (int i = 0; i < len; i++)
{
using (var button = elements[i])
{
if (button.value == value)
{
button.click();
return;
}
}
}
}
throw new Exception("Element " + value + " was not found.");
}
/// <summary>
/// Finds checkbox by id (using GetElementById) and sets it to isChecked
/// </summary>
public static void CheckCheckboxById(this IWebView webView, string id, bool isChecked = true)
{
using (dynamic checkbox = webView.GetElementById(id))
{
if (checkbox == null)
throw new Exception("Element " + id + " was not found.");
checkbox.@checked = isChecked;
}
}
/// <summary>
/// Finds select ("listbox") by id (using GetElementById) and sets selectedIndex
/// </summary>
public static void SetSelectIndexById(this IWebView webView, string id, int selectedIndex)
{
using (dynamic select = webView.GetElementById(id))
{
if (select == null)
throw new Exception("Element " + id + " was not found.");
select.selectedIndex = selectedIndex;
}
}
/// <summary>
/// Finds select ("listbox") by id (using GetElementsByName, chooses by index if more than one exist) and sets selectedIndex
/// </summary>
public static void SetSelectIndexByName(this IWebView webView, string name, int selectedIndex, int index = 0)
{
using (dynamic elements = webView.GetElementsByName(name))
{
if (elements == null || elements.length == 0)
throw new Exception("No elements with name " + name + " were found.");
if (elements.length < index + 1)
throw new Exception(string.Format("Array of elements with name {0} does not have {1} elements.", name, index + 1));
using (dynamic select = elements[index])
{
select.selectedIndex = selectedIndex;
}
}
}
/// <summary>
/// Finds element by id (using GetElementById) and returns its coordinates of top-left corner relative to the page
/// </summary>
public static Point GetElementPositionById(this IWebView webView, string id)
{
using (dynamic element = webView.GetElementById(id))
{
if (element == null)
throw new Exception("Element " + id + " was not found.");
return WebViewHelper.GetElementPosition(element);
}
}
/// <summary>
/// Finds element by id (using GetElementsByName, chooses by index if more than one exist) and returns its coordinates of top-left corner relative to the page
/// </summary>
public static Point GetElementPositionByName(this IWebView webView, string name, int index = 0)
{
using (dynamic elements = webView.GetElementsByName(name))
{
if (elements == null || elements.length == 0)
throw new Exception("No elements with name " + name + " were found.");
if (elements.length < index + 1)
throw new Exception(string.Format("Array of elements with name {0} does not have {1} elements.", name, index + 1));
using (dynamic element = elements[index])
{
return WebViewHelper.GetElementPosition(element);
}
}
}
/// <summary>
/// Finds element by class (using GetElementsByClassName, chooses by index if more than one exist) and returns its coordinates of top-left corner relative to the page
/// </summary>
public static Point GetElementPositionByClassName(this IWebView webView, string className, int index = 0)
{
using (dynamic elements = webView.GetElementsByClassName(className))
{
if (elements == null || elements.length == 0)
throw new Exception("No elements with class name " + className + " were found.");
if (elements.length < index + 1)
throw new Exception(string.Format("Array of elements with class name {0} does not have {1} elements.", className, index + 1));
using (dynamic element = elements[index])
{
return WebViewHelper.GetElementPosition(element);
}
}
}
/// <summary>
/// Returns Base64 string of image content. Without redownloading image. If it is not on the same domain, WebSecurity must be set to false.
/// </summary>
/// <param name="getElementQuery">
/// <para>Any Javascript query to get an element.</para>
/// <para>Examples:</para>
/// <para>"document.getElementById('id')"</para>
/// <para>"document.getElementsByClassName('name')[0]"</para>
/// <para>"document.evaluate(\"//a[contains(@href, 'something')]\", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue" (XPath)</para>
/// </param>
/// <param name="leaveOnlyBase64Data">if true, removes "data:image/type;base64," from the beginning of the string</param>
/// <returns>Base64 string or empty string in case of error</returns>
public static string JsGetImgBase64String(this IWebView webView, string getElementQuery,
bool leaveOnlyBase64Data = true)
{
string data = webView.ExecuteJavascriptWithResult(@"
function getImgBase64String(img)
{
var cnv = document.createElement('CANVAS');
var ctx = cnv.getContext('2d');
ctx.drawImage(img, 0, 0);
return cnv.toDataURL();
}
" + String.Format("getImgBase64String({0});", getElementQuery));
if (data == "undefined")
return string.Empty;
if (leaveOnlyBase64Data && data.Contains(","))
{
data = data.Substring(data.IndexOf(",") + 1);
}
return data;
}
}
public struct Point
{
public int X, Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
}
}
using System;
namespace WebViewHelpers
{
public static class WebViewHelper
{
/// <summary>
/// Returns JavaScript XPath query string for getting a single element
/// </summary>
/// <param name="xpath">Any valid XPath string, for example "//input[@id='myid']"</param>
/// <returns>JS code to perform the XPath query (document.evaluate(...)</returns>
public static string GetJsSingleXpathString(string xpath)
{
return
String.Format(
"document.evaluate(\"{0}\", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue", xpath);
}
/// <summary>
/// Returns JavaScript XPath query string for getting a collection of elements
/// </summary>
/// <param name="xpath">Any valid XPath string, for example "//input[@id='myid']"</param>
/// <returns>JS code to perform the XPath query (document.evaluate(...)</returns>
public static string GetJsXpathString(string xpath)
{
return
String.Format(
"document.evaluate(\"{0}\", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null)", xpath);
}
/// <summary>
/// Returns coordinates of top-left corner of the element (probably relative to the page)
/// </summary>
public static Point GetElementPosition(dynamic element)
{
dynamic rect = element.getBoundingClientRect();
using (rect)
{
return new Point(rect.left, rect.top);
}
}
}
}
@radiaku
Copy link

radiaku commented Apr 25, 2015

is this work for awesomium 1.7.4? (I just downgraded from 1.7.5) and is this work for code like background-image(url:) ?

thanks :)

@AlexP11223
Copy link
Author

Yes, I used this in 1.7.4. But I think most (or all) of this should work in 1.7.5 too.
Not sure about background-image, never tried

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment