Caja allows you to run plain JavaScript as well as Web content. For example, you may want to run guest JavaScript without a UI to add third-party numerical formulas, skinnable UIs with custom behaviors, and other application plug-ins that do not fit into the mold of a "virtualized HTML page". Here, we show you how.
Create guest code
Assume you define some guest JavaScript as follows (also available here):
return function f(x) { return Math.cos(5 * x); };
The return value of the code (i.e., the
result you would get if you were to pass the code to new Function
and call the result)
is a function taking a single numerical variable x
and
returning a single numerical result.
Create host page
Now create your host page as follows (also available here):
<html> <head> <title>Caja host page</title> <script type="text/javascript" src="//www.google.com/jsapi"></script> <script type="text/javascript" src="//caja.appspot.com/caja.js"></script> <style type="text/css"> #graph { width: 600px; height: 400px; margin: 10px; border: 1px solid grey; } </style> </head> <body> <h1>Caja host page</h1> <p> <!-- (1) --> Formula URL: <input id="formulaUrl" value="https://developers.google.com/caja/demos/runningjavascript/cosine.js" size="100"> <button id="set">Set</button> </p> <div id="graph"></div> <script type="text/javascript"> var graphDiv = document.getElementById('graph'); google.load('visualization', '1', {packages: ['corechart']}); // (2) caja.initialize({ cajaServer: 'https://caja.appspot.com/', debug: true }); function series(f, xMin, xMax, npts, data) { // (3) var xStep = (xMax - xMin) / (npts - 1); for (var i = 0; i < npts; i++) { var x = xMin + (xStep * i); var y = f(x); data.addRow([x, y]); } } function draw(f) { // (4) var data = new google.visualization.DataTable(); data.addColumn('number', 'x'); data.addColumn('number', 'y'); series(f, -2, 2, 100, data); var chart = new google.visualization.ScatterChart(graphDiv); chart.draw(data, { width: 600, height: 400 }); } function setFormula(formulaUrl) { // (5) graphDiv.innerHTML = 'Loading ' + formulaUrl + ' ...'; caja.load(undefined, undefined, function(frame) { frame.code(formulaUrl, 'application/javascript') // (6) .run(function (guestF) { // (7) var f = frame.untame(guestF); // (8) graphDiv.innerHTML = ''; draw(function (x) { return +f(x); }); // (9) }); }); } google.setOnLoadCallback(function() { // (10) document.getElementById('set').onclick = function() { setFormula(document.getElementById('formulaUrl').value); }; }); </script> </body> </html>
(1) We define an HTML input area allowing the user to enter and submit the URL of some JavaScript code.
(2) We load the Google Charts API. We will get a callback at (9) when this API is ready.
(4) This function creates and populates a Google Charts
chart, again given some arbitrary numerical
function f
of one variable. It uses the
function series
at (3).
(5) Given a URL to some JavaScript code
representing a mathematical formula, this function loads it as a Caja
module, using the right MIME type at (6), and passes
it to the draw
function. Contrary to the way we have
called run
in previous examples, here we pass a callback
function to run
at (7). This callback
function receives the return value of the guest code --
which is, as described previously, a JavaScript function.
Because this function was constructed by the guest code and could
misbehave in various ways, we pass it to frame.untame
(the
opposite of the tame
operation used in the preceding
example Providing services to guest
code) at (8) to obtain a better-behaved wrapper
function (which, most significantly, will always frame.tame
its arguments before passing them into the underlying guest code).
However, we still must consider misbehavior such as, in this case of
graphing, returning a value that isn't a number or even a string.
Caja can't help us directly here since this is application-specific,
so we do it ourselves; at (9) we make our own wrapper
function which uses the unary +
operator to ensure that the
return value is a number before passing it to draw
. We
could also have put the +
inside of draw
.
(10) When the Chart Tools API is ready, we add
an onclick
handler to the HTML button.
The result of running this code is as follows:

Run it yourself
Review
- You used JavaScript guest code, rather than HTML; and
- You learned to obtain and use the return value from the guest code.