ShowTable of Contents
Previous | Next
This section covers the development of a basic widget for deployment in the IBM Connections Home page. It discusses the file structure for a widget that is deployed as a web application, includes a tutorial about how to write a simple "Hello World" widget, and shows how to make the widget more interactive.
The IBM Connections Home page widgets are based on the iWidget specification and implement custom libraries that are specific to the Home page. These libraries are subject to change between releases and are there to facilitate the basic widgets that are already available.
To proceed with this section, it is important to have a good understanding of the various technologies used (for example, JavaScript, XML, HTML, and CSS) and preferably some experiences in creating custom Dojo 1.x widgets because these are essential to understanding the development of widgets for the IBM Connections Home page.
This section does not discuss how to deploy widgets because this information is found in section 3.3 Adding and removing widgets in the IBM Connections Home page. Creating a basic iWidget
An iWidget is the basic building block for adding new features to the IBM Connection Home page. In the simplest terms, an iWidget consists of a single XML file descriptor. The descriptor file begins with the name of the iWidget and is following by several possible iWidget attributes.
The simplest place to start for a basic iWidget is to develop a "Hello World" widget. In this basic example, only the iw:content attribute is used and contains an HTML template for the iWidget itself. This template is copied by the framework and inserted into the Document Object Model (DOM) of the page where the iWidget is deployed. This widget does nothing more than display some text in the iWidget container that says "Hello World!".
To create the widget, create a text file with the following code:
<iw:iwidget name="helloWorld" xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget">
<iw:content mode="view">
<![CDATA[
<div>
<div id="helloWorld">Hello World!</div>
</div>
]]>
</iw:content>
</iw:iwidget>
This file must be placed on a HTTP server such as an IBM HTTP Server (IHS) or an Apache web server because the IBM Connections Home page uses the HTTP or HTTPS protocol to load the descriptor file.
This example was very basic. You can use the XML descriptor file to import JavaScript libraries and to pass parameters to the framework. The content section of an iWidget descriptor can include more complex templates that include in-line JavaScript and CSS for styling the HTML. It is important to note that any HTML in this content section ultimately is subject to the existing CSS styles in the page on which the iWidget is rendered. This inheritance of styling is useful in that an iWidget deployed on a page in an application can inherit the look and feel of the parent application. The same iWidget could look differently when deployed in another application.
Importing a JavaScript resource file for a basic iWidget
The iWidget in the previous example is very basic. That sample iWidget provides a static iWidget that displayed a simple text message and provides an HTML form that posted to another page. However, an iWidget can be made more interactive by using extensive JavaScript or by importing a JavaScript library. Placing JavaScript in the HTML template using script tags will work, but references to an external file of JavaScript functions is also possible.
The iWidget descriptor can define a resource that the framework imports into the page and that makes it available to the iWidget. This framework allows the separation of the template from the functional code. The iw:resource takes a URI parameter that contains a URI of the file to import. It is important to note that this URI should be absolute, which helps the iWidget find the file regardless of which application the iWidget is imported into. The URI must be contactable from only the client browser because it is imported on the client-side when the page is rendered. In the following example the iWidget has been modified to include the iw:resource section:
<iw:iwidget name="helloWorld" xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget">
<iw:resource uri="<servername>/helloWorldFunctions.js" />
<iw:content mode="view">
<![CDATA[
<div
<div id="helloWorld">Hello World!</div>
<a href="javascript:void(0);" onClick="showMessage();" >
Click me!
</a>
</div>
]]>
</iw:content>
</iw:iwidget>
This iw:resource section points to the URI /helloworldfunctions.js. This JavaScript file is included in the page, and its function is accessible in the HTML template in the content section. In the template, the anchor element calls a function that is defined in the included JavaScript resource file. The function that is defined in the resource file is exactly the same as a JavaScript function that is defined in an HTML document using a script tag.
// JavaScript function to show a message
function showMessage() {
a message string
var msg = "Hello again, world!";
alert(msg);
}
Any of the functions in the file can be accessed in this manner. So a library can be built of functions to complete the tasks for which the iWidget is designed. The iWidget is only limited by the limits of JavaScript itself at this point.
Using the iWidget iScope and iContext
The iWidget specification provides more functionality for developers who want to do more than just the basic template presentation. This functionality is provided through the iWidget iContext. The details on these functions are available in the online iWidget 1.0 specification . While not everything the specification describes is available in the 3.0.1 release of IBM Connections Home page, necessary functions are available to provide the developer with useful tools.
The following example shows the iScope option that can be included in the iWidget XML descriptor.
<iw:iwidget name="helloWorld" xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget" iScope="helloWorld">
<iw:resource uri="/helloworldfunctions.js" />
<iw:content mode="view">
<![CDATA[
<div>
<div id="helloWorld" Hello World!></div>
<a href="javascript:void(0);" onClick="helloWorld.showMessage();">Click me!></a>
</div>
]]>
</iw:content>
</iw:iwidget>
This code sample is from the original example above with only the addition of the iScope property in the first line of the descriptor. The iScope property is placed in the iw:iwidget section, and its value should be that of a JavaScript object or class. This is the class that will be initialized when the iWidget is placed on a page or rendered in a page. The class must be defined somewhere for it to be initialized or its definition can be found in the resource file that we included. When the class that the iScope references initializes, it gets a property added to it called an iContext. This is an object that provides all of the iWidget functionality that the framework has to offer.
The following is a sample object:
var helloWorld = {
msg1: "Hello World Class Loaded",
msg2: "Hello World, again",
onLoad: function() {
alert(this.msg1);
},
showMessage:function() {
alert(this.msg2);
}
};
This sample object has the same name as the iScope parameter in the iWidget descriptor. The object is created and its onLoad method is called. While this method is not strictly the constructor for the class, it can be treated as such. In this method, place any type of initialization code that the widget needs to do such as alert the user that the object was created. The class defines two messages that are scoped to the class. The first message alerts the user that the class has loaded, and the second message displays when the user clicks the link. The function that the link called in the previous example is now a method of the class and so must be called using 'helloWorld.showMessage()'.
As stated earlier, the iScope class that is instantiated on the page also has an attribute set that is a reference to the iContext object that provides some extra iWidget functionality to our iScope class. The first feature of this to note is the function iContext.getElementById(elemId). As the iContext object is technically a member of the iScope class, the object can be referenced anywhere using this.iContext. The functioniContext.getElementById(elemId) returns a reference to a DOM node from inside the template in the iWidget descriptor. In the descriptor file we have been using, there is a div with an ID of 'helloWorld'. The method below, when added to our class, allows us to alter the text that is in that DOM node with ease.
alterText:function() {
var helloDiv = this.iContext.getElementById('helloWorld');
helloDiv.innerHTML="Hello New World!";
}
By adding this function to the class, the function is available when the class is loaded. Notice in the class definition below, the call after the alert tells the user the class is loaded. While this message is on the screen, the user can see that the widget has the original text from the template in it. After the message is dismissed, it should change.
var helloWorld = {
msg1: "Hello World Class Loaded",
msg2: "Hello World, again",
onLoad: function() {
alert(this.msg1);
alter our text
this.alterText();
},
showMessage:function() {
alert(this.msg2);
},
alterText:function() {
var helloDiv = this.iContext.getElementById('helloWorld');
helloDiv.innerHTML="Hello New World!";
}
};
Using this method of coding is a more favorable method for constructing a widget rather than creating a file loaded with functions. For example, two custom widgets developed by different developers can be placed on a page that define a function with the same name, but with a very different functionality. Using the methods described in this article help to keep the functions that are needed to a specified namespace thus preventing function conflicts.
Using Dojo widget inside an iWidget
With the ability to import JavaScript resource files and reference DOM nodes in the iWidget template, it is possible to import widgets from the Dojo framework as well. While it is beyond the scope of this topic to discuss how to create Dojo widgets, it is relevant enough to show how to create one so that any custom iWidget can benefit from the rich Dojo framework. This section covers briefly how to create a Dojo widget that has its own template and how to wrap it in the iWidget framework.
We first begin with a basic XML descriptor in the following example:
<iw:iwidget name="helloWorld" xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget">
<iw:resource uri="/helloWorldFunctions.js" />
<iw:content mode="view">
<![CDATA[
<div
<div id="helloWorld"></div>
</div>
]]>
</iw:content>
</iw:iwidget>
Because the example custom Dojo widget contains its own HTML template, there is no reason to have more than just an empty div tag to contain the Dojo widgets template. To inject the Dojo widget code must be added to only the iw:content section. Use the iContext.getElementById to reference this div tag and insert the Dojo widgets domNode into it as shown in the following example:
dojo.registerModulePath('DojoHello','servername/DojoHello');
dojo.require('DojoHello.helloWorld');
var helloWorld = {
dhw: null,
onLoad: function() {
var container = this.iContext.getElementById('helloWorld');
this.dhw=new DojoHello.helloWorld({iContext:this.iCOntext});
container.appendChild(this.dhw.domNode);
}
};
The class that the iScope creates has the most alterations. In this resource file, a location was added where the Dojo widget's files will reside (using Dojo.registerModulePath). This instructs Dojo to look in the location that is specified for anything in the namespace that is registered. For more information about this function and other Dojo functions, refer to the Dojo documentation on the Dojo website. Also a function was added that tells Dojo to load the required widget into the iWidget template in the iWidget XML descriptor. When the onLoad method is called, it instantiates a new Dojo widget called DojoHello.helloWorld. The Dojo widget has a domNode attribute that can be appended to the iWidget templates div.
The next task is to create the Dojo widget that we require for this iWidget. This widget must be stored in a file named helloWorld.js in the location pointed to by the namespace. Also, it must be accessible from the client browser similar to the other files. We declare the Dojo widget exactly as one normally would. By inheriting the dijit._Templated class and the dijit._Widget class, we can specify an HTML template string. It is also useful to pass to this widget the iContext so the Dojo widget has access to the useful functions provided by the iWidget framework. In the above example we simply have a template string that contains a link that attaches the method pressMe to its onClick event. We do nothing with the iContext, but it is available to us if we need it later on in development. The code in this example produces a link in the iWidget that executes a function from our Dojo widget. The function prompts the user with a message.
dojo.provide('DojoHello.helloWorld');
// Declaration of our dojo widget
dojo.declare("DojoHello.helloWorld", [dijit._Widget,dijit._Templated], {
// Holder for the passed in iContext object
iContext: null,
// String for our HTML template
templateString: "<a href=\"javascript:void(0);\" dojoAttachEvent=\"onclick:pressMe\">Press me!</a>",
// Constructor for the Dojo widget
postCreate: function() {
// Nothing necessary to do on startup
},
pressMe: function() {
alert("Hello from Dojo!");
}
});
Using Dojo and iWidget iContext to request data
Most widgets require the ability to request data from other applications. The Dojo framework provides utility functions for both requesting and transforming data. While these functions can be implemented with standard JavaScript methods, the best practice is to use a framework such as Dojo and avoid browser capability issues.
The following code shows a basic XML descriptor:
Note that the sample code has a minor change with the addition of the iw:itemSet section. This section provides the ability to pass name-value pairs to the iContext object when it is created. Wherever we have access to the iContext object, we can use it to get the values from the iWidget XML descriptor file. Inside each iw:itemSet, there is an iw:item with an ID (name) and a value. An iWidget descriptor file can have multiple iw:itemSets, and each iw:itemSet can have multiple iw:items. To refer to a particular iw:itemSet through the iContext object, we use iContext.getItemSet(id). This method returns a reference to the particular item set with the ID that is passed in. To get the value of an iw:item in the iw:itemSet, use the getItemValue(id) method on the object containing the reference returned from the iContext.getItemSet(id). In the previous example, we used the iw:itemSet to hold various URLs from which we want to fetch data. Each iw:item is a URL that provides a feed of information.
Due to the security model imposed by browsers, it is not possible to request data from a server other than where the widget was loaded. This security risk is called a cross site scripting (XSS) attach and is considered a huge security vulnerability. If a JavaScript function tries to request data from a domain that it was not loaded from, then that request is stopped. To solve this issue, the iWidget framework provides a function that rewrites a URI to go through an intermediate proxy if needed. If the framework is part of an application that provides or allows data request to be proxied, then this function rewrites the URI to something that allows the request to happen. In the case of IBM Connections, there is a configurable secure proxy that allows for external data requests. The administrator has control over the domains from which the data can be requested in order to increase security. To rewrite the URI from which you want to request data, pass it to the iContext.io.rewriteURI(uri) method.
The following code example shows an iw:itemSet that is accessed to get a list of URLs from which to request data.
dojo.provide('DojoHello.helloWorld');
// Declaration of the Dojo widget
dojo.declare("DojoHello.helloWorld", [dijit._Widget,dijit._Templated], {
// Holder for the passed in iContext object
iContext: null,
// String for the HTML template
templateString: "",
// Constructor for the Dojo widget
postCreate: function() {
// Get a uri from the itemsets
var items = this.iContext.getItemSet('urls');
var location = items.getItemValue('url1');
// Transform the location
var nLocation = iContext.io.rewriteURI(location);
// Create Dojo xhr request object
var bindArgs = { handleAs:text,
url:nLocation,
timeout:5000
};
// Create a GET request for the data
var req = dojo.xhrGet(bindArgs);
// Add a callback function to handle the returned data
req.addCallback(this,"result");
},
// This method handles the data returned by the GET request
result: function(data,evt) {
// Append data to the dom
this.resultContainer.innerHTML=data;
}
});
In this example, one URL is transformed from the original value stored in the iw:item to an accessible URI using the iContext.io.rewriteURI(uri) method. The text that is returned by the request is appended to the DOM in the template of the Dojo widget itself. We use the Dojo.xhrGet method to request the data in this example because of the simplicity of making xmlHTTPRequests compared to using pure JavaScript.
Usually the data returned by a request would be transformed or interpreted into something more meaningful such as a visual representation in the case of graph data. In addition, the data can be used to create HTML that is inserted into the widget template itself. With the ability to request data from an external web-based data source, the possible uses for an iWidget is greatly increased.
Parent topic: 3.0 Customizing the Home page
|
|
|
|
| Version 1 |
November 21, 2011 |
11:11:52 AM |
by Amanda J Bauman  |
|
|