// 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.Text.RegularExpressions;
using System.Threading.Tasks;
namespace CefSharp.Example
{
///
/// Methods whose functionaity is mostly implemented by evaluating or
/// executing scripts in the browser.
///
public static class ScriptedMethods
{
///
/// Determine if the active element in a frame accepts text input.
///
/// Test the active element in this frame.
/// True if the active element accepts text input.
public static async Task ActiveElementAcceptsTextInput(this IFrame frame)
{
if (frame == null)
{
throw new ArgumentException("An IFrame instance is required.", "frame");
}
// Scripts should be minified for production builds. The script
// could also be read from a file...
const string script =
@"(function ()
{
var isText = false;
var activeElement = document.activeElement;
if (activeElement) {
if (activeElement.tagName.toLowerCase() === 'textarea') {
isText = true;
} else {
if (activeElement.tagName.toLowerCase() === 'input') {
if (activeElement.hasAttribute('type')) {
var inputType = activeElement.getAttribute('type').toLowerCase();
if (inputType === 'text' || inputType === 'email' || inputType === 'password' || inputType === 'tel' || inputType === 'number' || inputType === 'range' || inputType === 'search' || inputType === 'url') {
isText = true;
}
}
}
}
}
return isText;
})();";
var response = await frame.EvaluateScriptAsync(script);
if (!response.Success)
{
throw new Exception(response.Message);
}
return (bool)response.Result;
}
///
/// Determine if the frame contains an element with the specified id.
///
/// Test the elements in this frame.
/// The id to find.
/// True if an element with the specified id exists in the frame.
public static async Task ElementWithIdExists(this IFrame frame, string id)
{
if (frame == null)
{
throw new ArgumentException("An IFrame instance is required.", "frame");
}
var script =
@"(function () {
var n = document.getElementById('##ID##');
return n !== null && typeof n !== 'undefined';
})();";
// For simple inline scripts you could use String.Format() but
// beware of braces in the javascript code. If reading from a file
// it's probably safer to include tokens that can be replaced via
// regex.
script = Regex.Replace(script, "##ID##", id);
var response = await frame.EvaluateScriptAsync(script);
if (!response.Success)
{
throw new Exception(response.Message);
}
return (bool)response.Result;
}
///
/// Set an event listener on the element with the provided id. When the
/// event listener callback is invoked an attempt will be made to pass
/// event information to a .Net class bound to the browser. See
/// ScriptedMethodsBoundObject.
///
/// The element is in this frame.
/// The id of an element that exists in the frame.
/// Subscribe to this event. For example 'click'.
public static void ListenForEvent(this IFrame frame, string id, string eventName)
{
if (frame == null)
{
throw new ArgumentException("An IFrame instance is required.", "frame");
}
// Adds a click event listener to a DOM element with the provided
// ID. When the element is clicked the ScriptedMethodsBoundObject's
// RaiseEvent function is invoked. This is one way to get
// asynchronous events from the web page. Typically though the web
// page would be aware of window.boundEvent.RaiseEvent and would
// simply raise it as needed.
//
// Scripts should be minified for production builds. The script
// could also be read from a file...
var script =
@"(async function ()
{
await CefSharp.BindObjectAsync('boundEvent');
var counter = 0;
var elem = document.getElementById('##ID##');
elem.removeAttribute('disabled');
elem.addEventListener('##EVENT##', function(e){
if (!window.boundEvent){
console.log('window.boundEvent does not exist.');
return;
}
counter++;
//NOTE RaiseEvent was converted to raiseEvent in JS (this is configurable when registering the object)
window.boundEvent.raiseEvent('##EVENT##', {count: counter, id: e.target.id, tagName: e.target.tagName});
});
console.log(`Added ##EVENT## listener to ${elem.id}.`);
})();";
// For simple inline scripts you could use String.Format() but
// beware of braces in the javascript code. If reading from a file
// it's probably safer to include tokens that can be replaced via
// regex.
script = Regex.Replace(script, "##ID##", id);
script = Regex.Replace(script, "##EVENT##", eventName);
frame.ExecuteJavaScriptAsync(script);
}
}
}