
This section assumes you have already read and understood the Time example.
The Simple Image widget finds images on or referenced by the page and displays them all together in its visualization frame. If the user clicks on one of these images then it will bring up a bubble describing the item that the image was from.
If you have Mash Maker installed then you can try out the Simple Image widget on Google News.
The Simple Image Widget makes use of the Patterns Library. The Patterns Library contains standard functions that simplify the creation of widgets that fit into one of a number of common patterns. Simple Image fits into what the Patterns Library calls the itemsByProp pattern. This means that it wants to be given all items that have a particular property (in this case an image). While we could have implemented Simple Image directly using the full Widget API, using the patterns library makes things simpler.
If you are interested in understanding how the Patterns Library is implemented in terms of the Widget API then you can have a look at the source for the patterns library:
http://mashmaker.intel.com/v13/mashmaker_patterns.js.
The configuration file for Simple Image is only slightly more complex than that for Time.
<widget title="Simple Image"
description="Show an image or images"
icon="http://mashmaker.intel.com/icons/image.png"
version="12">
<feature name="incremental"/>
<settings href="http://mashmaker.intel.com/newwidgets/simpleimage_settings.html"/>
<content scroll="yes" href="http://mashmaker.intel.com/newwidgets/simpleimage.html"/>
</widget>
The widget includes URLs for both a content pane and a settings panel. It turns on the incremental feature to indicate that it wishes to be told when new images appear or dissapear.
The Simple Image settings panel allows one to choose which elements on the page to take images from, and which item property to use as the image URL. The "target items" drop-down menu is automatically populated with the path to every kind of item on the page that has properties, and the "image" drop-down menu is automatically populated with all the properties that are available for the items selected by "target items".
The settings panel is created using the Patterns Library, using the following simple code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript" src="http://mashmaker.intel.com/v13/mashmaker_api.js"></script>
<script type="text/javascript" src="http://mashmaker.intel.com/v13/mashmaker_settings.js"></script>
<script type="text/javascript" src="http://mashmaker.intel.com/v13/mashmaker_patterns.js"></script>
<link rel="stylesheet" href="http://mashmaker.intel.com/style/settingstyle.css"/>
<script type="text/javascript" defer="true">
//<![CDATA[
function init(){
var opts = {
path:true,
slots:["image"]
}
mashmaker_patterns.itemsByProp.settings("table",opts);
}
// ]]>
</script>
<body onload="init()">
<table class="mm-table" id="table" />
</body>
</html>
If we ignore the standard boilerplate code for starting an HTML file and including the standard javascript libraries, we see that the entire settings panel boils down to the following:
function init(){
var opts = {
path:true,
slots:["image"]
}
mashmaker_patterns.itemsByProp.settings("table",opts);
}
When the page is loaded, it calls the init function. This function uses itemsByProp from the Patterns Library to create a standard settings panel that has an item path ("target items") and asks a path to an "image" property. These fields are added to the table with the id of "table".
Here is the entire source code for the main widget frame:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" href="http://mashmaker.intel.com/mashprops.css"/>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="http://mashmaker.intel.com/v13/mashmaker_api.js"></script>
<script type="text/javascript" src="http://mashmaker.intel.com/v13/mashmaker_util.js"></script>
<script type="text/javascript" src="http://mashmaker.intel.com/v13/mashmaker_settings.js"></script>
<script type="text/javascript" src="http://mashmaker.intel.com/v13/mashmaker_patterns.js"></script>
<script type="text/javascript">
//<![CDATA[
function init(){
var opts = {
path : true,
slots : ["image"],
addRemoveItems : add_remove_items // called when a single item is added
};
mashmaker_patterns.itemsByProp.widget(opts);
}
function add_remove_items(additems,removeids){
var i;
var loadcount = 0;
var imgcount = 0;
for(i in removeids){
var image = document.getElementById("img-"+removeids[i]);
image.parentNode.removeChild(image);
}
for(i in additems){
var span = document.createElement("span");
span.setAttribute("id","img-"+additems[i].id);
span.style.cursor = "pointer";
var urls = additems[i].slots.image;
for(var j in urls){
var image = document.createElement("img");
imgcount++;
image.addEventListener("load",function(){
loadcount++;
if(loadcount == imgcount){
mashmaker.setHeight(document.body.offsetHeight);
}
},false);
image.setAttribute("src", urls[j]);
span.appendChild(image);
}
document.body.appendChild(span);
click_select(span,additems[i].id);
}
mashmaker.done();
}
function click_select(node,id){
node.addEventListener("click",function(ev){
mashmaker.select(id);
mashmaker.showBubble(id,{x:ev.pageX, y:ev.pageY});
},false);
}
// ]]>
</script>
</head>
<body onload="init()" style="margin:0px; padding:0px;" style="overflow:auto">
</body>
</html>
Let's walk through this code step-by-step.
function init(){
var opts = {
path : true,
slots : ["image"],
addRemoveItems : add_remove_items // called when a single item is added
};
mashmaker_patterns.itemsByProp.widget(opts);
}
Like the settings panel, the main panel calls an init function when the page loads. This function calls into the Patterns Library and asks it to set up the widget basics. The first two parts of the opts structure are the same as for the settings. We say that this widget has an item path and expects an image property. The final field is a pointer to a function that the Patterns Library should call when items with the desired property are added or removed from the pgage. In this case, we provide a function called add_remove_items.
The add_remove_items function is the core of the Simple Image widget.
| additems | A list of items, with the desired path and property that have been added to the page. Each item has an identifying id and a slots array, mapping each requested property to a list of strings giving values for it. |
| removeitems | a list of ids for items that we previously added but which have now gone away |
When the widget is first added to the page this function will called with all matching items on the page in the additems array. Further calls will happen if other widgets manipulate the page data using addProp and removeProp.
function add_remove_items(additems,removeids){
var i;
var loadcount = 0;
var imgcount = 0;
for(i in removeids){
var image = document.getElementById("img-"+removeids[i]);
image.parentNode.removeChild(image);
}
for(i in additems){
var span = document.createElement("span");
span.setAttribute("id","img-"+additems[i].id);
span.style.cursor = "pointer";
var urls = additems[i].slots.image;
for(var j in urls){
var image = document.createElement("img");
imgcount++;
image.addEventListener("load",function(){
loadcount++;
if(loadcount == imgcount){
mashmaker.setHeight(document.body.offsetHeight);
}
},false);
image.setAttribute("src", urls[j]);
span.appendChild(image);
}
document.body.appendChild(span);
click_select(span,additems[i].id);
}
mashmaker.done();
}
The actual code for adding and removing items is pretty simple. To add an item, it walks through the list of images associated with the item and creates an image tag for each one. When creating a span for an item we include the id of the item in its name so we can easily delete it if the item is removed.
The add_remove_items function calls click_select to register a click event handler for the images.
function click_select(node,id){
node.addEventListener("click",function(ev){
mashmaker.select(id);
mashmaker.showBubble(id,{x:ev.pageX, y:ev.pageY});
},false);
}
When the user clicks on one of the images we do two things:
- Ask all other widgets to select the same item in their visualizations, if applicable. This is done by calling select.
- Ask Mash Maker to display a popup bubble giving more information about this item. This is done using showBubble.

