Skip to end of metadata
Go to start of metadata

Let's use the MarkMail gadget developed in the previous tutorial to set the mailing list as a user preference, so that we can use the same gadget, to display graphs for various lists.

For this, we can add a simple option where the user can set the URL of the list . We can pick that user set option and fetch data accordingly.

<UserPref name="MailingList"
     display_name="Mailing List"
     default_value="http://markmail.org/browse/org.wso2.carbon-commits">
</UserPref>

The user preference allows the user to set the URL of the mailing list. In the gadget's logic, we can use the value of the preference set rather than the hard-coded URL value. For that we need to first initialize the preferences within the gadget.

var prefs =new gadgets.Prefs();

And then, use the prefs object to pick the value set for MailingList:

var url = prefs.getString("MailingList"); gadgets.io.makeRequest(url, processResponse, parameters);

That's it! The rest of the logic is the same as we discussed in previous tutorials of this series. Note that, by default, the type of the preference is treated as a string. Therefore, we use the getString API, to retrieve the value of the user preference.

There are several data types supported by Google gadget API for the user preference section as described here: http://code.google.com/apis/gadgets/docs/fundamentals.html#Datatypes. In addition to that, the gadgets.Prefs class API provides means to get and set user preferences programmatically using JavaScript as described here: http://code.google.com/apis/gadgets/docs/reference/#gadgets.Prefs.

Now the user can use the settings menu icon on gadget’s title bar and set a mailing list address. The gadget will reload with new data.

Using enum Data Type as an Options List

Allowing users to set any URL using a string preference can lead to errors, and even usability concerns if the users do not know where to find the right URLs. Therefore, it is useful to provide a list of URLs as options. Also, based on the URL selected, we need to change some setting in the gadget presentation; for example the caption of the table. Therefore, we need something more than a simple string box to pick the URL.

Let’s say we want this gadget to support visualizing data for all main WSO2 mailing lists. We can allow users to pick a mailing list with an instance of the gadget. The enum type user preference can be used to implement this.

<UserPref name="MailingList" display_name="Mailing List"
    datatype="enum" default_value="3">
    <EnumValue value="0"
        display_value="WSO2 Architecture List - http://markmail.org/browse/org.wso2.architecture" />
    <EnumValue value="1"
        display_value="WSO2 Carbon Dev List - http://markmail.org/browse/org.wso2.carbon-dev" />
    <EnumValue value="2"
        display_value="WSO2 Stratos Dev List - http://markmail.org/browse/org.wso2.stratos-dev" />
    <EnumValue value="3"
        display_value="WSO2 SVN Commits - http://markmail.org/browse/org.wso2.carbon-commits" />
    <EnumValue value="4"
        display_value="WSO2 Carbon Jira Activity - http://markmail.org/browse/org.wso2.carbon-jira" />
    <EnumValue value="5"
        display_value="WSO2 Stratos Jira Activity - http://markmail.org/browse/org.wso2.stratos-jira" />
</UserPref>

In this enum user preference, we have used values 0 to 5 and a descriptive text for each as display value. Then we can pick the user selection using:

var listID = prefs.getString("MailingList");

We can use JavaScript to pick other variables such as column names, caption and the mailing list URL, based on the value of listID. For e.g. we can pick the table title and column title for the graph using a combination of JavaScript arrays and selected list ID value:

var titles = new Array("WSO2 Architecture List Discussions",
                       "WSO2 Carbon Dev List Discussions",
                       "WSO2 Stratos Dev List Duscussions",
                       "WSO2 Carbon and Stratos SVN Commits",
                       "WSO2 Carbon Jira Activity",
                       "WSO2 Stratos Jira Activity");
 
var columns = new Array("Discussions", "Discussions", "Discussions",
                        "Commits", "Activity", "Activity");
 
var listID = prefs.getString("MailingList");
 
document.getElementById('contentDiv').innerHTML = "<table id='data'><caption>" +
                                                    titles[listID] +
                                                    "</caption><thead><tr><th></th><th scope='col'>" +
                                                    columns[listID] +
                                                    "</th></tr></thead>" +
                                                    document.getElementById('browse').getElementsByTagName('table')[0].innerHTML +
                                                    "</table>";

Note that the selected value of enum can be accessed by using both getString and getInt, given that the value field contains a number. But, if it contains non-digit characters, using getInt will result in an error.

Using Boolean Data Type

In the gadget, we display only the graph. But we also have the data as a HTML table. If the user wishes, we can allow the user to see the table instead of the graph. This allows the user to duplicate the same gadget and see the data and the graph side by side.

This can be achieved with a simple Boolean type user preference.

<UserPref name="ShowGraph" display_name="Show Graph"
    datatype="bool" default_value="true">
</UserPref>

JavaScript code that deals with it is:

if (prefs.getBool("ShowGraph") == true) {
    drawGraph();
    document.getElementById('contentDiv').style.display = "none";
    document.getElementById('graphDiv').style.display = "block";
} else {
    document.getElementById('graphDiv').style.display = "none";
    document.getElementById('contentDiv').style.display = "block";
}

Note that we can use the getBool API call to access boolean type user options.

Integer Settings with String Data Type

The user preference documentation here (http://code.google.com/apis/gadgets/docs/fundamentals.html#Datatypes), has no integer data type. But the API supports getInt as mentioned here (http://code.google.com/apis/gadgets/docs/reference/#gadgets.Prefs).
What this means is that, if you want to deal with integer type user option, such as the height and width of the graph, you can use a string type user preference and access the value using getInt.

<UserPref name="GraphWidth" display_name="Graph Width"
    default_value="600">
</UserPref>
<UserPref name="GraphHeight" display_name="Graph Height"
    default_value="625">
</UserPref>

The JavaScript code that deals with it is as follows:

var g = new Bluff.SideBar('graph', prefs.getInt("GraphWidth") + 'x' + prefs.getInt("GraphHeight"));

Setting Preferences from Within the Gadget

User preference functionality is built into the gadget framework, and the API is easy to use. You just define the user preferences in the gadget, and the preferences will be generated with a form inside the action area of the gadget.
This is useful for most of the options which are usually one off. Once set, they will be hidden away from users without appearing in the visual area.

But some user preferences need to be changed more frequently. For example, as opposed to the mailing list URL, the theme of the graphs are more frequently changed. An admin can lay out the number of instances of the gadget and the mailing list but the graph theme might be a user-specific choice.

For such frequently changed options, having only the default user preference form could be a productivity-killer. This is because, the user has to go through 4 clicks each time a change is required, as shown in the following diagram.

For more frequently used options, we can facilitate one click instead of four. For this, we need to do three things, in addition to the usual user preference settings.

First, set "setprefs" inside <ModulePrefs> element as follows:

<ModulePrefs title="WSO2 Open Source Development Data from MarkMail">&nbsp;
&nbsp; <Require feature="dynamic-height" />&nbsp;
&nbsp; <Require feature="setprefs"/>
</ModulePrefs>

Second, provide an on-screen, within gadget HTML element to allow the user settings. In this example we use a select element for the user to pick the theme.

Grapth Theme: <select id="graphThemeSelect" onchange="if (this.selectedIndex >=0 ) updateTheme(this);"> 
                 <option value="0">Keynote</option> 
                 <option value="1">37signals</option>  
                 <option value="2">Rails Keynote</option> 
                 <option value="3">Odeo</option> 
                 <option value="4">Pastel</option> 
                 <option value="5">Greyscale</option> 
             </select>

The final step is to implement the updateTheme JavaScript fuction, triggered by onchange event of select element.

function updateTheme(theme) { 
   prefs.set("GraphTheme", theme.value); 
   drawGraph();
}

Note that inside the udateTheme fuction, we use the prefs.set API call to set the preference value. This means that the preference value will be persisted, and when the user views the gadget next time, the theme set last will be used as opposed to the default theme.

If we used just JavaScript without the gadget API, this persistence will not take place - a noteworthy advantage that makes Google gadgets more useful over just HTML.

Infor:
You can find more information on the use of setprefs feature and saving sate, on Google gadgets documentation here: http://code.google.com/apis/gadgets/docs/fundamentals.html#SetPrefs

Dealing with Views

There is a "view" attribute that is available with <Content> element. Multiple <Content> elements can be defined to make the gadget look different and fit for various views. However, defining multiple <Content> elements can lead to gadget logic duplication, especially for one as sophisticated as the MarkMail gadget that we developed from tutorial 1 of this series. Good news is that the Google gadget API has provisioning to deal with views programmatically as described here: http://code.google.com/apis/gadgets/docs/ui.html#curr_view.

For our example MarkMail gadget, we can choose to display both the table and the graphs side by side on the same gadget, when the gadget is in "canvas" view. Canvas view is the view you get when the gadget is maximized. In the maximized view, we have enough real state to show both the table and the graph on the same gadget.

For view API to be used, we need views feature.

<ModulePrefs title="WSO2 Open Source Development Data from MarkMail">
    <Require feature="dynamic-height" />
    <Require feature="setprefs"/>
    <Require feature="views" />
</ModulePrefs>

If we are in canvas view, we show both content div and graph div.

if (gadgets.views.getCurrentView().getName() == "canvas" ) {
    drawGraph();
    document.getElementById('contentDiv').style.display = "block";
    document.getElementById('graphDiv').style.display = "block";
}

Here is the maximized view of the gadget.

Versatility of Google Gadgets as a Presentation Instrument

In the past three tutorials of this series, we developed a gadget incrementally to fetch HTML from a URL, extract data and present those in an appealing manner. Let's have a look at a dashboard built using this gadget. The following is a screen shot of such a dashboard, created using the WSO2 Gadget Server.

As you can see, the gadget is duplicated six times and data presented on six different mailing lists. Moreover we have six themes used for the six graphs so that the mapping of the visual elements on the dashboard is natural. Furthermore, we have the architecture list, developer lists, code commit message list and issue reporting lists all presented side by side on the same dashboard. This offers the user a better view. For example, the user can easily spot the release efforts in sync with the peaks in svn commits and issue related activities.

This illustrates how a carefully designed gadget can help present and visualize information better. A gadget is worth a thousand pages!

In conclusion, let's look at some tips and tricks to keep in mind when developing gadgets in tutorial : Tips and Tricks in Developing Gadgets

  • No labels