Introduction to Javascript / C++ Integration
Using Awesomium's API, you can create global Javascript objects and manipulate them directly from C++, call Javascript functions with native C++ variables, and evaluate arbitrary strings of Javascript.
Global Javascript Objects
The best way to integrate your application with a web-page is by using Global Javascript Objects. These objects are linked to the lifetime of the WebView so this feature is quite useful for specifying persistent data for each WebView.
Creating, manipulating, and accessing these objects is very
simple in our C++ API. To create an object, simply call
WebView::createObject with the name that you want the
object to appear as in Javascript.
For example:
myWebView->createObject(L"MyObject");
The above would create a global Javascript object that you can
access as MyObject from any web page loaded into your
WebView.
Of course, creating objects alone isn’t very
useful–- to give the object some properties, you can use
WebView::setObjectProperty:
myWebView->setObjectProperty(L"MyObject", L"name", "foobar");
myWebView->setObjectProperty(L"MyObject", L"color", "Blue");
myWebView->setObjectProperty(L"MyObject", L"level", 25);
You can set as many properties as you want, setting a property
more than once will replace the previous value. Notice that the
last parameter to setObjectProperty accepts a JSValue
(more on that later).
Another nifty feature of these global Javascript objects is that you can bind C++ callbacks to them and invoke events from Javascript. For example:
myWebView->setObjectCallback(L"MyObject", L"myCallback");
The above code would add a new method, myCallback,
to MyObject that, when called from any page via
Javascript, will invoke WebViewListener::onCallback
with the name of the object, the name of the callback, and the
arguments passed, if any.
For example, say you made a button that calls “myCallback” with a single string argument (”hello!”) when clicked:
<input type="button" value="Click Me!"
onclick="MyObject.myCallback('hello!')" />
You could then intercept this callback in
WebViewListener::onCallback (you’ll need to
register your WebViewListener first via
WebView::setListener):
void MyListener::onCallback(const std::wstring& objectName, const
std::wstring& callbackName, const Awesomium::JSArguments& args)
{
if(objectName == L"MyObject" && callbackName == L"myCallback")
std::wstring value = args[0].toString(); // value is 'hello!'
}
JSValue Class
The JSValue class is used as an intermediary to translate C++ types into Javascript variables and vice-versa. To get a better understanding of how this relationship works, here’s how types are mapped between Javascript and C++ using JSValue:
| Javascript | C++ |
|---|---|
| Number | double or int |
| Boolean | bool |
| String | std::wstring or std::string |
| Object | std::map<std::wstring, JSValue> |
| Array | std::vector<JSValue> |
| Null or Undefined | JSValue with null type |
JSValue Type: Strings
You can get the string representation of any JSValue via
JSValue::toString. It is safe to call this on a
JSValue of any type.
JSValue Type: Objects
Objects in Javascript are sort of like a "map" or "dictionary". Every key has a "string" type and every value can be any number of types.
As specified in the table above, these Objects are modeled in C++ as a std::map with a string key and a JSValue for a value (typedef’d as JSValue::Object).
For example, say you had an object ‘Person’ in Javascript:
var Person = {
name: 'Bob',
age: 22,
};
You could then retrieve a copy of this object in C++:
JSValue myValue = myWebView->executeJavascriptWithResult("Person").get();
if(myValue.isObject())
{
JSValue::Object person = myValue.getObject();
std::wstring name = person[L"name"].toString(); // value is 'Bob'
int age = person[L"age"].toInteger(); // value is '22'
}
JSValue Type: Arrays
On the C++ side, Arrays are modeled as a std::vector of JSValues (typedef’d as JSValue::Array).
So, for example, if you had the following array in Javascript:
var myArray = [1, 2, "three", 4, "five"];
You could access it in C++ like so:
JSValue myValue = myWebView->executeJavascriptWithResult("myArray").get();
if(myValue.isArray())
{
JSValue::Array myArray = myValue.getArray();
int first = myArray[0].toInteger(); // value is '1'
int second = myArray[1].toInteger(); // value is '2'
std::wstring third = myArray[2].toString(); // value is 'three'
}
Compositions of JSValues
It is also worthy to note that JSValue is flexible enough to
accommodate compositions of arrays, objects, and other types. It
supports arrays of arrays, arrays of objects, objects with array
values, and all other nested permutations along this line.
For example, say you wanted to create a JSValue that is
functionally equivalent to the following Javascript Object:
var Player = {
name: 'Rex',
HP: 1000,
items: ['Armor', 'Sword', 'Gauntlets'],
stats: {
strength: 57,
defense: 90,
dexterity: 24
}
};
You could model this Object in C++ as so:
JSValue::Object player;
player[L"name"] = "Rex";
player[L"HP"] = 1000;
JSValue::Array items;
items.push_back("Armor");
items.push_back("Sword");
items.push_back("Gauntlets");
player[L"items"] = items;
JSValue::Object stats;
stats[L"strength"] = 57;
stats[L"defense"] = 90;
stats[L"dexterity"] = 24;
player[L"stats"] = stats;
Direct Calling of Javascript Functions
You can call a Javascript function directly with JSValues as parameters.
Say you had the following function in Javascript:
function addChatMessage(nickname, message) {
chat = document.getElementById('chat');
chat.innerText = nickname + ": " + message;
}
You can call it directly from C++ like so:
JSArguments args;
args.push_back("Bob");
args.push_back("Hello world!");
myWebView->callJavascriptFunction(L"", L"addChatMessage", args);
Calling Functions Contained Within An Object
As you may have noticed above, I’ve specified an empty
wide string (L”") as the first parameter of
WebView::callJavascriptFunction. This is because the
first parameter allows you to specify the Object that contains the
function. In the above example, I’ve specified an empty
string to indicate that this function is in the global scope (and
thus is not contained within any object).
Here’s an example of how to call a function contained within an Object; say you had the following defined in Javascript:
var MusicBox = {
currentTrack: '',
isPlaying: false,
play: function(track) {
this.isPlaying = true;
this.currentTrack = track;
displayMsg = document.getElementById('display');
displayMsg.innerText = "Now playing: " + this.currentTrack;
}
};
You could call this function from C++ by the following:
JSArguments args;
args.push_back("Moonlight Sonata");
myWebView->callJavascriptFunction(L"MusicBox", L"play", args);
Conclusion
It is super easy to pass data between Javascript and C++ using Awesomium. The “Global Javascript Objects” feature simplifies the task of exposing data in your application to Javascript, JSValue’s support for Array and Object types makes it a snap to share complex structures, and direct calling of Javascript functions with JSValue parameters provides a fast path to code on a web-page.