Note
The full code for this sample is available at https://github.com/jcleblanc/programming-social-applications/tree/master/chapter_4/countdown_feature.
In Chapter 3, we discussed the process of installing Shindig to run your own OpenSocial container to host applications. Thus far, this chapter has outlined the “out of the box” JavaScript components that are available to you in a Shindig container, but what if you want to create your own JavaScript libraries and features to extend those native offerings?
As with the default feature libraries, adding new JavaScript libraries and features to Shindig in order to make them available to your gadget is a simple, multistep process. Let’s look at a practical example to showcase how to do this. We’ll add a new JavaScript library feature to create a countdown clock that’s displayed in a gadget.
First, from the root of your Shindig installation directory, go to the JavaScript features directory:
cd features/src/main/javascript/features
This is where the JavaScript features we’ve explored thus far are housed, and where we’ll create a new one. Create a new directory called “countdown” and then move into it:
mkdir countdown cd countdown
Now we need to create the files that will define our JavaScript library feature. Create a new file called countdown_base.js. This file will house the JavaScript that will run our countdown clock. Within the JavaScript file, add the following code:
gadgets['countdown'] = (function(){ var time_left = 10; //number of seconds for countdown var output_element_id = 'countdown'; //node to output time to var keep_counting = 1; //whether to keep counting var no_time_left_message = "Time's Up!!!"; //message to display when time's up //decrement time left and check whether time has expired function countdown() { if(time_left < 2) { keep_counting = 0; } time_left = time_left - 1; } //add leading 0's on single digit numbers function add_leading_zero(n) { if(n.toString().length < 2) { return '0' + n; } else { return n; } } //format countdown output string function format_output() { var hours, minutes, seconds; seconds = Math.floor(time_left % 60); minutes = Math.floor(time_left / 60) % 60; hours = Math.floor(time_left / 3600); seconds = add_leading_zero( seconds ); minutes = add_leading_zero( minutes ); hours = add_leading_zero( hours ); return hours + ':' + minutes + ':' + seconds; } //display time left function show_time_left() { document.getElementById(output_element_id).innerHTML = format_output(); } //display time expired message function no_time_left() { document.getElementById(output_element_id).innerHTML = no_time_left_message; } return { //countdown function count: function () { countdown(); show_time_left(); }, //control timer timer: function () { this.count(); if(keep_counting) { setTimeout("gadgets.countdown.timer();", 1000); } else { no_time_left(); } }, //counter initialization init: function (t, element_id) { time_left = t; output_element_id = element_id; this.timer(); } }; })();
The first thing that we need to do to define our core JavaScript is
to assign the functionality to a custom gadgets object, gadgets['countdown']
. We then include any
JavaScript functionality that is necessary to run the feature but is not
accessible by calling directly into the JavaScript feature. Next, we issue
a series of functions in the return object. These are the functions that
we will make requests to in order to initialize the JavaScript feature;
for example, we’ll make a request to the init(...)
function to create the countdown
feature.
Since we assigned the return functionality to a gadgets
object, returning these functions allows
us to initialize the countdown by calling gadgets.countdown.init(...)
.
Now we need to create a new file, taming.js, which will allow us to make certain methods available to a gadget if Caja is being employed:
var tamings___ = tamings___ || []; tamings___.push(function(imports){ ___.grantRead(gadgets.countdown, 'init'); ___.grantRead(gadgets.countdown, 'timer'); ___.grantRead(gadgets.countdown, 'count'); });
We specify that we want to make our three return functions available when Caja is being employed.
Our last file, feature.xml, names the feature and specifies the files that provide the code (namely, our JavaScript) needed to run that feature:
<feature> <name>countdown</name> <dependency>globals</dependency> <gadget> <script src="countdown_base.js"/> <script src="taming.js"/> </gadget> <container> <script src="countdown_base.js"/> <script src="taming.js"/> </container> </feature>
We name the feature “countdown” and state that countdown_base.js and taming.js should be used for the container and gadget.
Now we just need to add our new feature to the list of features to be loaded by the container. Go to the features directory and open the features.txt file:
cd features/src/main/javascript/features vim features.txt
Add the following line to the file:
features/countdown/feature.xml
If you don’t want to manually edit the file, you can run the following command from the features directory:
ls -R1a **/*.xml > features.txt
At this point, we are ready to start using our new feature in our
gadget. To integrate our countdown feature into one of our existing
gadgets, we simply need to add the Require
node with the
appropriate feature name:
<Require feature="countdown"></Require>
When we expand this out into a full-fledged sample gadget, we see how the feature is used:
<?xml version="1.0" encoding="UTF-8"?> <Module> <ModulePrefs title="Countdown Application"> <Require feature="countdown"/> </ModulePrefs> <Content type="html"> <![CDATA[ <div id="countdown">...</div> <script type="text/javascript"> //calculate time left from current to future time var currentTime = new Date(); var futureTime = new Date("September 26, 2011 17:55:00"); var timeLeft = (futureTime - currentTime) / 1000; //initialize counter gadgets.countdown.init(timeLeft, 'countdown'); </script> ]]> </Content> </Module>
In the ModulePrefs
node, we have
included our Require
statement. The
countdown feature functionality is loaded within the Content
node. We include the div
node where we want to render the counter.
Next, in the script
block, we calculate
the time between the current time and some date in the future. We can then
initialize the feature by calling the gadgets.countdown.init(...)
method, passing in
the time remaining and a string representing the ID of the node in which
the countdown should be rendered.
Using this method, you can create and use custom JavaScript library features.
Get Programming Social Applications now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.