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.