Bubbletop Foundry

Bubbletop Foundry: Bubbletop Developer’s Documentation

Overview

Benefit the community by building widgets around your own ideas and innovations. Extend the reach of your existing website or online app by enabling your users to use it from within the Bubbletop environment.

Introduction – what you need

In order to build a widget you will need the following:

Workflow

In order to build a successful widget we suggest the following workflow:

  1. Design out your widget in a graphics package or even on paper. You only have a small area to play with, so making sure that your widget is clear and easy to use is crucial. Keep things simple and try to build your widget to around width of 300px.
  2. Work out what you need to build your widget before you start coding – if you’re going to mashup a number of APIs and services make sure you know how each one works. If you don’t know which API to use, Programableweb.com is a great resource for finding them.
  3. Build your widget in regular HTML page. You might find it useful to build your code within a div set to width:300px, as this is the usual width of a widget:

    <div id="widgetWidthConstrainer" style="width:300px">
    ...
    </div>

  4. Once you have your widget successfully working in HTML, it’s time to wrap it into the XML file used by Bubbletop. The specification of the XML is discussed below.
  5. Upload your XML file to your server so that you have a url for your XML File. Then access the Widget Preview service on the Bubbletop Foundry.
  6. Point the Widget Preview to your XML file. The Widget Preview will load the XML file into the preview window for you to check that we’re able to successfully process and display your widget. For convenience your source code will also be displayed, allowing you to make and preview last-minute alterations to your code. Don’t forget to save your final XML source back to your XML file on your server!
  7. Submit the widget to Bubbletop via the form provided on this site (make sure all your contact information is correctly listed in your widget XML!)
  8. We will review your widget and let you know when we add it to the Bubbletop system. If we are unable to add your widget we’ll let you know why via email – we’ll do our best to try to help you fix any problems. If you’re coming to the Orange C0ding C4mp on August 4th, we’ll give you feedback there and then!
  9. Once your widget is in Bubbletop you can add it to your tab.

Widget XML file

Here is a sample ‘blank’ XML file:


Sample code

hide

<?xml version="1.0" encoding="UTF-8"?>
<widget>
  <widget-prefs
    title="This is your title"
    description="This is your description"
    author="Your name/nick"
    author_email="your@emailaddress.com"
    author_location="Town/City, Country"
    restricted="true|false"
    height="100"
    scaling="true|false"
    scrolling="true|false"
    singleton="true|false"
    accept_data_type="string"
     >
  </widget-prefs>
  <user-pref name="name" display_name="name" default_value="default"></user-pref>
 
  <content type="html">
    <![CDATA[
      <style type="text/css">
      </style>
      
      <script type="text/javascript">
      </script>
      
      <!-- widget html here -->
    ]]>
  </content>
 
</widget>

This node helps us know how to display your widget and how to get in contact with you.

* denotes mandatory attribute

The tags define how you collect user-specific information and settings from the widget user. Using the preferences panel is not mandatory, however it is the preferred way to collecting such data as it provides a consistent and familiar user-experience within Bubbletop.

Example panel

We also provide easy to use convenience javascript methods to set and get user properties within your widget.

As an example, here are the set of tags used to render the weather preference window shown above:

<user-pref name="days" display-name="days" default-value="5"/>
 
<user-pref name="location" display-name="location" default-value="USCA0987"/>
 
<user-pref name="address" display-name="address" default-value="San Francisco,CA"/>
 
<user-pref name="icon" datatype="hidden"/>
 
<user-pref name="unit" datatype="enum" default-value="F" display-name="unit">
  <enum-value value="F" display-value="F"/>
  <enum-value value="C" display-value="C"/>
</user-pref>

When processed, these tags are parsed into the following HTML:

<span class="editBlockLabel">days: </span><select name="days"><option value="1">1</option>
<option value="2">2</option>
<option value="3" selected="selected">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select><br><input name="location" value="USCA0987" type="hidden"><span class="editBlockLabel">address: </span><input name="address" value="San Francisco,CA" type="text"><br><input name="oldaddress" value="San Francisco,CA" type="hidden"><input name="icon" value="" type="hidden"><span class="editBlockLabel">unit: </span><select name="unit"><option value="F" selected="selected">F</option>
<option value="C">C</option>
</select>

As you can see each tag has a series of attributes:

* denotes mandatory attribute

Each may have its datatype defined, although by default (i.e. if no datatype is set) this is set to string. The datatypes available are:

Enum’s (short for enumerator’s) will iterate over child tags nested inside them, creating a dropdown. The attributes for an tag are value and display_name. If the default_value set in the parent matches a value in a child then that item will be shown as the default item in the dropdown list.

See the above code example to see an enum datatype and its child tags.

Event handling is not implemented for V1.0. However very soon we intend to allow you to ‘bind’ your own custom javascript functions to Bubbletop events that occur around your widget - such as OnLoad and OnDragEnd (i.e. when the user finishes moving your widget around their personalized page.

We would very much welcome the community’s thoughts and feedback about this – foundry@bubbletop.com

The HTML contents of your widget should be placed within the tag. The correct syntax is as follows:

<content type="html">
  <![CDATA[
    <style type="text/css">
    </style>
    
    <script type="text/javascript">
    </script>
    
    <!-- html here -->
  ]]>
</content>

As you can see, we include a type attribute within the tag to ensure that it is very clear that the contents are HTML. We also wrap the HTML with a ![CDATA[ definition.

Another way to wrap your service into a widget is to use url type content.


Sample code

A widget directly link to Google Mail PDA version

hide


<?xml version="1.0" encoding="UTF-8"?>
<widget version="0">
  <widget-prefs
    title="gmail"
    description="Gmail"
    author=""
    author_email=""
    author_location="France"
    restricted="true"
    height="400"
    scaling="false"
    scrolling="true"
    singleton="false"
     >
  </widget-prefs>
 
  <content  type="url" href="https://m.gmail.com">
  </content>
 
</widget>
 

There is no need to include outer tags as the type is already defined in the parent tag. Further more and tags are unnecessary too.

Javascript API

dimsuPref.getProperty(propertyname)

Returns the value assigned the key ‘propertyname’ for that user - either through the edit panel or through the setProperty() method.

dimsuPref.setProperty(propertyname,value,ifSave)

Saves a variable as a key/value pair. Setting ifSave=TRUE stores the key/value back on the server for future retrievale for that user, otherwise the variable is stored for this session only

dimsuPref.savepreference()

Saves all current set preferences for this session to the server


Sample code

This is a working notepad widget that use Bubbletop platform to store text from user input

hide


<?xml version="1.0" encoding="UTF-8"?>
<widget>
  <widget-prefs
    title="Notepad"
    description="Note Pad"
    author=""
    author_email=""
    author_location="San Francisco, CA"
    restricted="false"
    height="400"
    scaling="false"
    scrolling="true"
    singleton="false"
    accept_data_type="string"
     >
  </widget-prefs>
  <user-pref name="content" datatype="hidden" display-name="content" default-value=""/>
  
    <events>
        <on-load>loadContent</on-load>
    </events>
  <content  type="html">
 
  <![CDATA[
 
    <style type="text/css">
      body {margin:0px;}
    </style>
 
    <script type="text/javascript">
      var defaulecontent = "write some text here and it will be saved";
      function loadContent(){
        if(dimsuPref.getProperty('content')!=undefined)
           document.getElementById('pad').value = dimsuPref.getProperty('content');
      }
    </script>
  
    <textarea id="pad" onchange="dimsuPref.setProperty('content',this.value);dimsuPref.savepreference();"
    style="margin:0px;width:100%;border-width:0px;height:90%;overflow:auto;"
    onblur="if(this.value==''){this.value=defaulecontent;}"
    onfocus="if(this.value==defaulecontent){this.value='';}">write some text here and it will be saved</textarea>
  ]]>
  </content>
 
</widget>
 

dimsuLib.FetchXMLContent(url,callbackfn)

Passes function ‘callbackfn’ a DOM object of the xml document located at the url specified

dimsuLib.FetchJsonContent(url,callbackfn)

Passes function ‘callbackfn’ a javascript object of the JSON payload located at the url specified

dimsuLib.FetchContent(url,callbackfn)

Passes function ‘callbackfn’ a javascript object of the plain text payload located at the url specified

dimsuLib.FetchContentByPost(url,cmd,myCallbackFunction,myErrorCallbackfunction,myAttachedJSObject)

Makes POST call to a url and send response text to the callback function. Note that you can also register a function to handle errors and even a Javascript object to attach some value to the request object and will be send back to the call back function.


Sample code

This widget code shows how to make Fetch content POST calls

hide


<?xml version="1.0" encoding="UTF-8"?>
<widget>
  <widget-prefs
    title="TEST-FetchByPost"
    description=""
    author=""
    author_email=""
    author_location="San Francisco, CA"
    restricted="false"
    height="200"
    scaling="false"
    scrolling="true"
    singleton="false"
    accept_data_type="string">
  </widget-prefs>
  <user-pref name="content" datatype="hidden" display-name="content" default-value=""/>
<events>
        <on-load>start</on-load>
    </events>
  <content  type="html">
  <![CDATA[
 
    <script type="text/javascript">
 
  var cf = function(xDoc,props) {
    alert("success: xDoc = " + xDoc + ", props = "+ props);
    for (var key in props) {
      alert(key + " = " + props[key]);
    }
  }
 
  var ef = function(e,p) {
    alert("ef: e="+e+", p="+p);
  }
var start = function(){
var cmd= 'my post data';
var url='http://my.server';
dimsuLib.FetchContentByPost(url,cmd,cf,ef,{ "hello": "world" });
}
    </script>
  ]]>
  </content>
</widget>

dimsuSys.setWidgetTitle(title)

Sets the title of the Bubblet dynamically. Supercedes the title defined in the widget spec file - can be used for dynamic title changes

dimsuSys.setWidgetIcon(url)

Sets the icon for the Bubblet to be the image at the url given. Image should be 16px x 16px, can be a favicon.

dimsuSys.getLocale()

Returns the current locale as described at http://java.sun.com/j2se/1.4.2/docs/api/java/util/Locale.html, for example en_US, fr_FR.

Example 1 – Hello World

Here is an example of a ‘hello world’ widget:


Sample code

This example does nothing – it just displays “Hello World”:

hide

<?xml version="1.0" encoding="UTF-8"?>
<widget>
<widget-prefs
    title="Hello World"
    description="This is my first widget"
    author="Bubbletop Team"
    author_email="foundry@bubbletop.com"
    author_location="San Francisco, USA"
    restricted="false"
>
</widget-prefs>
<content type="html">
<![CDATA[
<style type="text/css">
</style>
 
<script type="text/javascript">
</script>
 
<h1>Hello World!</h1>
]]>
</content>
 
</widget>
 

Example 2 – Simple example of get/set preferences


Sample code

The following code demonstrate getProperty and setProperty methods

hide

<?xml version="1.0" encoding="UTF-8"?>
<widget>
  <widget-prefs
    title="Get/Set Properties Example"
    description="Demonstrates getting and setting properties in Bubbletop"
    author="Bubbletop Team"
    author_email="foundry@bubbletop.com"
    author_location="San Francisco, USA"
    restricted="false"
    >
  </widget-prefs>
 
<user-pref name="name" display-name="Your Name:" default-value="Ben"/>
<user-pref name="age" display-name="Your Age:" default-value="25"/>
<user-pref name="gender" datatype="enum" default-value="m" display-name="Your Gender:">
<enum-value value="f" display-value="Female"/>
<enum-value value="m" display-value="Male"/>
</user-pref>
 
<content type="html">
    <![CDATA[
      <style type="text/css">
      </style>
      
      <script type="text/javascript">
      function printProperty(property) {
          document.write(dimsuPref.getProperty(property)); //print out the property being passed in
      }
      
      function getLastLogin() {
          var d = new Date(); //get Date object for this example
          
          if ((dimsuPref.getProperty('lastlogin') != null) || (dimsuPref.getProperty('lastlogin') != undefined)) {
            document.write(dimsuPref.getProperty('lastlogin')); //if previously set, return 'lastlogin' property
          }
          else {
            document.write('never before!') //if never set, display alternative
          }
          
          dimsuPref.setProperty('lastlogin',d.toLocaleString()); //update property for next time!
      
      }
 
  
      </script>
      
      <h1>Hello <script>printProperty('name');</script>!</h1>
      <div>I understand you are <script>printProperty('gender');</script> and <script>printProperty('age');</script> years old.</div>
       <div>You last accessed this widget: <script>printProperty('lastlogin');</script></div>
    ]]>
  </content>
 
</widget>

Example 3 - Youtube tag search


Sample code

This widget shows how to set/get user preference and make remote call to apis.

hide


 
<?xml version="1.0" encoding="UTF-8"?>
<widget>
  <widget-prefs
    title="demo"
    description="This is your description"
    author="John Doe"
    author_email="your@emailaddress.com"
    author_location="town/city, country"
    restricted="false"
    height="200"
     >
  </widget-prefs>
  <user-pref name="tag" display-name="tag" default-value="music"></user-pref>
  <events>
    <on-load>startmyapp</on-load>
  </events>
  <content type="html">
 
    <![CDATA[
      <style type="text/css">
      </style>
      
      
      <script type="text/javascript">
      
      var mycallback = function(xmldoc){
        var thepanel = document.getElementById('panel');
      
        var items = xmldoc.getElementsByTagName('video');
        var item,des,id,content='';
        for(var i=0;i<items.length;i++){
          item = items[i];
          id = item.getElementsByTagName('id')[0].firstChild.nodeValue;
          content += ('<div style="float:right;margin:1px"><a href="http://www.youtube.com/?v='+id+'" target="_blank"><img style="border-width:0px" src="http://img.youtube.com/vi/'+id+'/default.jpg"></a></div>');
 
        
        }
        
        thepanel.innerHTML = content;
      }
      
      var startmyapp = function(){
      var url = 'http://www.youtube.com/api2_rest?method=youtube.videos.list_by_tag&dev_id=Z35TyR4rYQE&tag='+dimsuPref.getProperty('tag')+'&per_page=20&page=1';
      
        dimsuLib.FetchXMLContent(url,mycallback);
      }
      </script>
      
      <div id="panel" style="width:100%;height:100%">
        
      </div>
    ]]>
  </content>
 
</widget>