using the dojo toolkit with websphere...

39
Using the Dojo Toolkit with WebSphere Portal Adding sizzle to your portal application user interface Karl Bishop ([email protected] ), Senior Software Engineer, IBM Doug Phillips ([email protected] ), Advisory Software Engineer, IBM November, 2007 © Copyright International Business Machines Corporation 2007. All rights reserved. This article describes how to use and leverage the Dojo toolkit in portal applications. Dojo is a JavaScript™ based toolkit that you can use to enhance your portal with a rich set of widgets and dynamic interactivity that customers expect from today's modern Web applications. The article guides you through the installation and configuration of Dojo, and helps you use it with IBM® WebSphere® Portal. Then, it shows you how to take advantage of the features provided with Dojo. To get the most out of this article, you should have a good understanding of JavaScript programming, portal administration and development, and have the desire to make your portal applications sizzle! 1

Upload: others

Post on 17-Oct-2020

18 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Using the Dojo Toolkit with WebSphere PortalAdding sizzle to your portal application user interface

Karl Bishop ([email protected]), Senior Software Engineer, IBMDoug Phillips ([email protected]), Advisory Software Engineer, IBM

November, 2007

© Copyright International Business Machines Corporation 2007. All rights reserved.

This article describes how to use and leverage the Dojo toolkit in portal applications. Dojo is a JavaScript™ based toolkit that you can use to enhance your portal with a rich set of widgets and dynamic interactivity that customers expect from today's modern Web applications. The article guides you through the installation and configuration of Dojo, and helps you use it with IBM® WebSphere® Portal. Then, it shows you how to take advantage of the features provided with Dojo.

To get the most out of this article, you should have a good understanding of JavaScript programming, portal administration and development, and have the desire to make your portal applications sizzle!

1

Page 2: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Table of contentsIntroduction .......................................................................................................................... 3 Integrating Dojo into your portal applications ..................................................................... 4

Using a cross domain build of Dojo ................................................................................ 4 Custom Dojo enabled theme ............................................................................................ 4 Bundling Dojo with your portlets .................................................................................... 5

Instantiating Dojo ................................................................................................................. 5 Step 1 - Define Dojo dijit theme style ............................................................................. 5 Step 2 - Define the Dojo configuration (djConfig) variable ............................................ 6 Step 3 - Load the core Dojo object .................................................................................. 7 Step 4 - Include additional modules and start something! ............................................... 8

Portal and JavaScript considerations ................................................................................... 9 Portlet namespacing ......................................................................................................... 9 Global static JavaScript .................................................................................................. 10

Dojo specific considerations .............................................................................................. 10 AJAX communications .................................................................................................. 10

Internationalization ............................................................................................................ 13 Dojo events .................................................................................................................... 15 Styling dijits ................................................................................................................... 15

Custom modules ................................................................................................................. 16 Step 1 - Create folder structure ...................................................................................... 17 Step 2 - Create module files ........................................................................................... 17 Step 3 - Register your module's package with Dojo ...................................................... 18 Step 4 - Instantiate your object ...................................................................................... 18

Troubleshooting ................................................................................................................. 19 Debuggers ...................................................................................................................... 19 Logging on the client ..................................................................................................... 19 Sending log messages to a server ................................................................................... 20 Common coding mistakes .............................................................................................. 22

Working with the sample files ......................................................................................... 23 Project: DojoPortal_Theme ........................................................................................... 23

Files: DojoPortalInit.jspf and DojoXDPortalInit.jspf ................................................ 24 File: js/ibm/portal/Portal.js ........................................................................................ 25

Project: DojoPortal_Service ........................................................................................... 26 Project: DojoPortal_Portlets .......................................................................................... 26

File: DojoPortletInit.jspf ............................................................................................ 27 File: js/ibm/portlet/Portlet.js ...................................................................................... 28 Servlet: PortletService ............................................................................................... 30 Portlet: LoggingPortlet ............................................................................................... 30 Portlet: I18NPortlet .................................................................................................... 31 Portlet: SessionPortlet ................................................................................................ 34

Conclusion ......................................................................................................................... 36 Download ........................................................................................................................... 37 Resources ........................................................................................................................... 37 About the authors ............................................................................................................... 38

2

Page 3: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

IntroductionIn the Web 2.0 world, users expect your Web-based applications to provide a rich set of user interface and interactivity features. Until recently, you had to use proprietary plug-ins or secondary languages such as Java™, ActiveX, or Flash to add Rich Internet Application (RIA) features to a Web site. These languages tend to be heavyweight, to require additional installation from the user, and are often problematic in cross-browser and cross-platform environments.

With the explosion of Asynchronous JavaScript and XML (AJAX) toolkits, you can now provide full-featured applications on the browser using native and cross-browser JavaScript. There are several great AJAX toolkits available, and many of them are open source. This article focuses on the Dojo toolkit, which has a strong architecture, helpful accessibility and internationalization features, and general feature set. If you hold allegiance to another toolkit, please read on; most of the issues discussed here generally apply to any AJAX toolkit.

This article does not get into the details or history of AJAX as a technology. Also, it assumes that you know how to install new portal themes, create pages, and deploy portlet and servlet WAR files. See Resources for links to other articles on using native AJAX in WebSphere Portal if you want to an introduction to these topics.

This article dives right into getting things done with Dojo inside portal applications. It does not teach you how to use all of the widgets and features of Dojo; however, you will get a nice jump start if this is your first foray into the Dojo toolkit.

Enter the Dojo toolkitThe Dojo toolkit (http://dojotoolkit.org) has undergone a rapid and extreme evolution. The latest release (as of this writing) is 1.0.0, which went live on 5 November 2007. This release is a complete rewrite of the previous versions. It is lean and fast, and is much easier to use than previous releases.

The Dojo packaging has been split up to make it easier to use. These packages include:• The Dojo core (dojo) package, which includes all the base code. • The Dojo widgets (dijit) package. Contains the typical form and input elements

(We will let you ponder that package name.)• The Dojo extras (dojox) package. This final package contains experimental features

and widgets, which might not be fully "baked", so they are not yet ready for inclusion into the main packages.

3

Page 4: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

As you will see later in this article, you can also create your own Dojo-based modules to include in your application.

The primary source of information on Dojo is the online Book of Dojo, and the API reference (see Resources for links). You are strongly advised to read (or even re-read) both of these to gain a strong foundation of the capabilities available in the Dojo Toolkit. Both of these are located on the Dojo Toolkit Web site.

Integrating Dojo into your portal applicationsThe first thing you need to determine is how you will embed Dojo into your portal application. You have a few options, and your decision will determine how you start. Your first decision is if you want to embed Dojo into a custom theme or if you want to load it from each portlet. Either technique will work fine; however, from an architectural standpoint, it is much cleaner to use a Dojo-enabled theme. The only reason you would not be able to use a custom theme is if you are not in control of the portal instance. For example, if you are providing portlets (as a third party) to portal customers, then you must have each portlet define its own Dojo environment.

Next, you need to decide if you want to bundle your own local instance of Dojo with your theme or portlets, or if you want to use a cross-domain build of Dojo. Cross domain builds of Dojo can be hosted on a company intranet. Alternatively, you can use Dojo 1.0.0 that is hosted on the AOL® Content Delivery Network (CDN).

You learn more about these options later in this article when we explore the merits and pitfalls of each. All the example code in this article uses the common cross domain build of Dojo.

Using a cross domain build of DojoObviously, the easiest way to install "something" is to simply not install it at all! No, this is not as obtuse as it seems in this networked world. Dojo now provides a special build that can be hosted on a central server within your organization and accessed from any application, no matter what is the source URL. Previous versions of JavaScript toolkits and earlier versions of Dojo required that AJAX calls be within the same domain URL. With a cross domain build of Dojo, this limitation, as it relates to Dojo and its specific modules, is removed. If you do not want to host the Dojo modules at all, then you can access the global cross domain build hosted by AOL CDN.

Custom Dojo enabled theme

If you are developing a portal-based application for a company Web site, and it will use a custom built theme, then you should establish a Dojo base within the theme. Doing this has several advantages:

• You can define and publish the Dojo version and CSS styling used by all contained portlets.

4

Page 5: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

• You get the advantage of a common browser cache instance of the dojo core and included modules.

• You reduce the amount of boilerplate code that would otherwise be required by each portlet to instantiate Dojo.

Having a common Dojo base from the theme is a valuable feature. If each portlet defines its own instance of Dojo, then the first portlet and, therefore, the first Dojo instance loaded, would take precedence over all other portlets on the page. This could cause some painful debugging when your portlet is expecting a certain version of Dojo, and a portlet loaded earlier in the page aggregation instantiated a different version.

Bundling Dojo with your portlets

In cases in which you do not have a custom theme, or you cannot directly make theme changes, you can instantiate Dojo with each portlet you deploy into portal. In this case, you need to consider:

• Version mis-match concerns (described above)

• Consistent CSS styling for your dijits

• Added size of the WAR file due to bundling the local Dojo toolkit with your code.

The size issue does not apply if you use a cross domain build of Dojo. Other than these considerations, there is no harm in instantiating Dojo from within your portlets.

Instantiating DojoTo use Dojo, you follow these steps, which are described in more detail below:

1. Define Dojo dijit theme styles .

2. Define the Dojo configuration (djConfig) variable .

3. Load the core Dojo object.

4. Include additional modules and start something !

These steps differ slightly depending on whether you use a local instance of Dojo or a cross domain build.

You can download all the Dojo initialization code, which has been abstracted into JSP fragments for both theme and portlet instances.

Step 1 - Define Dojo dijit theme styleWhile this is not technically required to get Dojo started, you might wish to provide custom styling to the Dojo dijits. Basically, you just need to include the CSS files that

5

Page 6: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

define the styling for your dijits, and then add the class name to the <body> tag. For more on styling, see the section Styling dijits.

Listing 1 shows how to include the Dojo supplied soria theme. This code obtains the CSS file from the AOL hosted Dojo cross domain build.

Listing 1. Include custom dijit theme<%-- Load the 'soria' dijit theme style --%><style type="text/css"> @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/soria/soria.css";</style>

Listing 2 shows the document's <body> tag with the matching class name. In the Styling dijits section of this article, you see how to set the body's class name through DOM manipulation.

Listing 2. Body tag including dijit theme class name.<body class='soria'>

Step 2 - Define the Dojo configuration (djConfig) variable

Dojo has several configuration variables that can control Dojo behavior. These need to be set prior to instantiating Dojo. While we do not cover all of them in this article, Table 1 shows a few that you should be aware of.

Table 1: Important Dojo Configuration settings.Setting name DescriptionparseOnLoad Setting this variable to true instructs Dojo to parse the

DOM tree for any elements that include dojoType attributes and turn them into Dojo dijits. You will normally want to set this if you are using any dijits. Then, you need to use the dojo.parse package (described below).

isDebug Dojo defaults to using the JavaScript console, such as Firebug or other JavaScript debuggers, for logging. Setting this variable value to true enables a Firebug Lite IFrame console for browsers that do not have an installed debugger. See the Troubleshooting section of this article for more details.

baseUrl Normally, Dojo looks for any custom packages at the peer level of the base dojo package (that is, /js/dojo/../myPackage). If you want to have your packages located in a different tree (which is a good idea), then set this variable to your base location. Cross Domain Dojo builds require you to set this value to “/” in order to register local packages. See the Custom modules section for more information.

locale By default, Dojo uses the browser's default language setting.

6

Page 7: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Setting this variable forces Dojo to use the language that you specify.

So, now that you know what the key configuration settings are, how do you actually set them? There are two ways to set them. You can either create a global JavaScript object called djConfig and add members to it, or you can add a djConfig attribute to the script tag that loads Dojo. Listing 3 shows creating the global djConfig variable.

Listing 3. Define djConfig variable to configure Dojo's behavior<%-- Define dojo init parameters --%><script type="text/JavaScript"> djConfig = { isDebug: true, parseOnLoad: true, baseUrl: "/", locale: "<%= request.getLocale() %>" };</script>

While this is very descriptive, the trend seems to be to use the djConfig attribute when loading the dojo.js script. Personally, I prefer the variable approach. The example code illustrates both methods.

Step 3 - Load the core Dojo objectYou instantiate Dojo by loading the dojo.js file inside the base dojo package, and using an src attribute in the script tag as shown in the listings below.

Listing 4 shows the command to load the cross domain version of Dojo. The cross domain builds of Dojo are called dojo.xd.js instead of the standard dojo.js. And, there is a closing script tag; null body <script /> tags are invalid.

Listing 4. Load a cross domain build of Dojo<%-- Initialize Dojo cross domain --%><script type="text/JavaScript" src="http://o.aolcdn.com/dojo/ 1.0.0/dojo/dojo.xd.js "></script>

Listing 5 shows how to load a local instance of Dojo, and how to define djConfig as an attribute. Do not define both the global djConfig variable and the djConfig attribute.

Listing 5. Define a local instance of Dojo and djConfig in a single line<%-- Initialize Dojo local and djConfig --%><script type="text/JavaScript" djConfig='parseOnLoad:true, locale:<%=request.getLocale()%>' src="./dojo/dojo/dojo.js"></script>

7

Page 8: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

No, that is not a typo on the path. I typically put all the true Dojo packages (dojo, dijit, dojox) under a directory called dojo to keep them isolated from locally written code.

Step 4 - Include additional modules and start something!

After the base Dojo package has been loaded, you almost always want to include extra packages. Dojo is designed as a packaged system, with core functionality in the base object and everything else loaded as additional modules. You must call the dojo.require() method prior to using any additional modules in Dojo.

If your installation decided to create a custom Dojo build, then you, the developer, could help determine what is packaged as part of the base dojo object. You must also define custom packages and language files prior to using them. You learn more about custom modules later in the article.

In the past, one of the big hassles of writing reliable JavaScript code in portal environments was being unable to control when things were executed. Because you did not have access to the onload attribute on the body tag, to kick-start execution, you were forced to let the browser run JavaScript as it was parsed. When doing serious DOM manipulation, there was the possibility of race conditions when the DOM was not complete and your JavaScript code was trying to alter it. Not an ideal situation.

Dojo's addOnLoad function brings order to this chaos. There is also a matching addOnUnload function to use when the user attempts to navigate away from a page. Each portlet can have its own addOnLoad / addOnUnload block(s) as necessary and Dojo will ensure they are processed, in order, after the page has been fully rendered. This one feature alone is worth the price of admission to using Dojo in your portal applications.

Listing 6 shows an arbitrary JavaScript block that defines several Dojo modules and then starts processing using an addOnLoad call. It uses an anonymous function as the argument to the addOnLoad function, which is a common signature in Dojo. Think of it like an inner class in Java. Also, do not concern yourself yet with the contents of the code inside the addOnLoad; you see that shortly.

Listing 6. defining modules and starting processing<script type="text/JavaScript"> console.debug("Loading required Dojo modules"); // scan page for dijits and instantiate them dojo.require("dojo.parser");

dojo.addOnLoad( function() { console.info("Dojo: Initializing environment"); //-- Can't do this in before load, as body tag does not yet exist document.body.className = "soria";

//-- Do any other global setup here... // ...

console.info("Dojo: Initialization complete");

8

Page 9: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

} );</script>

The source code provided in the download example files is a little more elaborate. It performs a few other actions during the initialization phase than you have seen in this section; however, the basic flow is the same.

We need to look at a few more topics before diving into the downloadable example source code.

Portal and JavaScript considerationsThe following sections provide information on issues that are specific to portal and JavaScript. By applying all of these concepts, you can ensure that you will have a well written and robust portal application.

Portlet namespacingImplementing JavaScript functionality in your portlets can cause unexpected issues if you do not follow a few basic procedures. It is easy to overlook namespacing requirements while you are writing a single portlet. The portal renders this portlet along with several others to form a single DOM entity. If you are not careful, your portlet may conflict with duplicate id attributes and global JavaScript variable names.

The Portlet API (JSR 168) provides a solution in the form of the <portlet:namespace/> tag. Add it to all id attributes and global JavaScript variables. While this is easy to do, it can be a pain and makes the code difficult to read and maintain. This tag is processed on the host and can, therefore, only be used within JSP files, not in stand-alone JavaScript files.

Listing 7 shows an example of a namespaced variable. Most portal documentation shows the namespace tag before variable names and ids. I prefer to put it after the name, which, is a personal preference; to me, this placement makes the code easier to read. Pick a convention and stick with it.

Listing 7. Namespacing global variables and id attributes<div id="msgArea<portlet:namespace/>"></div><script type="text/JavaScript> var myMsg<portlet:namespace/> = dojo.byId("msgArea<portlet:namespace/>"); myMsg<portlet:namespace/>.innerHTML = "Hello";</script>

You can mitigate this namespace pollution somewhat by using JavaScript objects to help encapsulate private member values. Also, limit your use of global variables. Using anonymous functions can help a lot in this regard. For id attribute values, you need to namespace everything. The download example code includes a custom portlet JavaScript object that provides several functions to assist you in working with namespaces and other portlet-specific concerns.

9

Page 10: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Global static JavaScript

For non-instance (or static) functions, which are generally global in nature, you can use an external JavaScript file along with some sort of naming convention, as shown in Listing 8. The test that surrounds the functions ensures that only the first portlet or entity that references the file defines it and any possible implied initializers.

Listing 8. /js/PageCache.js - Static global JavaScript sampleif ( typeof(PageCache) == 'undefined' ) {

var PageCache = { caches: {}, DEFAULT_CACHE: "DEFAULT", //-------------------------------------------------------- getCache: function( /*string*/ cid ) { if ( cid == null ) { cid = this.DEFAULT_CACHE; } if ( this.caches[ cid ] == null ) { this.caches[cid] = new Cache(); } return this.caches[cid]; }, ... }; //---------------------------------------------------------- function Cache() { this.cache = {}; } ...} // end if undef

This example file is bundled with the included theme project, but is not otherwise used in the other examples because it has nothing to do with Dojo or portal. It is included simply to show how to safely use static objects in JavaScript.

Dojo specific considerationsThis section discusses Dojo-specific topics. While these topics do not deal directly with WebSphere Portal, they are related in nature. Having a fundamental grasp of these areas will help you in developing your portal applications.

AJAX communicationsFirst, consider how to perform AJAX style communications (also known as XMLHttpRequest or XHR communications) from your portlet (or portal theme) to a host service. Figure 1 shows the XHR communications options from a portal client. In a portlet context, XHR calls must be made to an external entity. You cannot send an XHR call directly to the portlet.

10

Page 11: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Figure 1. Remote AJAX communications options

You have the option of bundling a servlet with your portlet WAR file. The benefit of doing this is to share session variables among the servlet and the portlets bundled in the same WAR file. The SessionPortlet example in the download shows an implementation of this session sharing.

Dojo provides several XHR-related functions to communicate with a remote host. These functions follow the typical REST style commands. To process an XHR request in Dojo, you make a call to the appropriate function, passing in an object that defines the setting of the call. There are many possible argument members; Table 2 shows the primary entries. Consult the Book of Dojo for more specific details. The Book of Dojo is on the Dojo site and is the single source of documentation. See Resources for a link. As of this writing, it has not been updated to 1.0.

11

Page 12: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Table 2: Important Dojo XHR function argumentsArgument key Descriptionurl URL of the remote service to callcontent Set of key:value pairs to pass to the remote service. Analogous to form

fields.handleAs How should Dojo treat the response object. Common values are: text,

xml, and json-comment-filtered. Note: To prevent cross-site scripting attacks, the json type has been deprecated in favor of the json-comment-filtered type. A host sending back a JSON encoded string must wrap the entire payload as a block comment (/* ... */).

timeout Length of time to wait (in milliseconds) until this request is considered stale and times out with a failure.

preventCache Microsoft® Internet Explorer is very aggressive about caching GET calls in XHR. Unless you really want to allow caching of common XHR GET calls, set this to true.

load Callback function called after the XHR response has been received.error Callback function called if there is a communications error.

The load function is called after the response is received, where you can process the results. Usually, the response object is automatically transformed to be what you would expect, based on the handleAs value. For JSON (json-comment-filtered) types, start using the response as a JavaScript object; for XML type, you have a native document ready to be crawled. Yes, it really is that easy!

All Dojo XHR functions return a deferred object. This deferred object can be used to add extra post-processing logic in the form of one or more callback functions. This is a good way to have an XHR function return a generic response, and then the caller can take the deferred object and apply specific logic to the response. An example of using the deferred callback is shown in Listing 9.

Listing 9. Example of XHR deferred object usagefunction getPasswordFromVault(/*string*/ userid) { var deferred = dojo.xhrGet( { url: "http://www.myhost.com/vault", content: {"user":userid}, handleAs: "json-comment-filtered", timeout: 5000, preventCache: true, load: function(response, ioArgs) { console.debug("getPassword() successful"; return response; }, error: function(response, ioArgs) { console.error("getPassword() Error: ", ioArgs.xhr.status); return null; } } ); return deferred;

12

Page 13: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

};...var vaultDeferred = getPasswordFromVault("admin");vaultDeferred.addCallback( function(response) { logInToAccount("admin", response.password); console.info("Admin account is now logged in");} );vaultDeferred.addCallback( function(response) { savePassword("admin", response.password);} );

The load function returns the response object, which is the input argument to the deferred object's callback functions.

Dojo's I/O facilities go much farther than this, such as with RPC and special form handling. There is a lot more information available from the Book of Dojo. Spend some time reading about this powerful mechanism to really push your portal applications capabilities.

InternationalizationDojo provides a well designed mechanism to handle internationalization (i18n). If you are familiar with the standard Java resources concept, then you will recognize the similarities. Essentially, you define the package that contains the translation files, and then pull in the specific resource definition within that package. The structure of the resources consists of a required nls directory under the package. Inside the nls directory is a default resource file and locale specific directories each containing the same resource file with the specified translation. Figure 2 shows a typical i18n structure in a package called _I18NPortlet.

Figure 2. Sample i18n resource structure

13

Page 14: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

The structure of each resource file is a standard JSON object wrapped inside parenthesis. The body contains a set of keys and values that represent the replacement text, as shown in Listing 13.

Listing 13. Sample i18n resource file({ subtitle: "Dojo NLS sub title from: /js/example/nls/labels.js", title: "Main title"})

Listing 14 presents the process to define and use the i18n resources. The flow presented here defines the module path for the _I18NPortlet package, and includes a similar call to define our localization resource. Because we defined the default locale in the djConfig variable, we do not need to explicitly state it when we actually get our needed language specific resource. We store the reference to the resource into the variable called NLS.

After we have loaded the NLS variable with our resources, we just use the desired member entries like a normal JavaScript object.

Listing 14. Using i18n within Dojo//-- Add our custom Dojo Module<script type="text/JavaScript"> dojo.registerModulePath("_I18NPortlet","/_I18NPortlet"); dojo.requireLocalization("_I18NPortlet","labels"); dojo.addOnLoad( function() { var NLS = dojo.i18n.getLocalization("_I18NPortlet", "labels"); portlet<namespace/>.byId("subtitle").innerHTML = NLS.subtitle; } );</script>

With all this said about how to use Dojo's i18n facilities, we have to recommend that you not use it in portal environments. The reason for stating this is that portlets already have a Java-based solution for i18n resources; so, it should be reused and extended into your JavaScript. This practice keeps all NLS resources contained in a single area. As anyone who has gone through a large-scale translation project can attest, keeping everything together makes the whole process much easier to manage.

So, how should you transfer your Java NLS resources into your JavaScript? Easy. Just transpose your Java values into a JavaScript object within the JSP file, as shown here in listing 15.

Listing 15. Using Java NLS resources in JavaScript<%-- Use Formatting JSTL taglib --%><%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>

<%-- Pull in our Java NLS bundle --%><fmt:setBundle basename="ibm.dojoportal.portlet.i18n.I18NPortletResource" />

14

Page 15: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

<script type="text/JavaScript"> //-- Build NLS object based on strings we need. var NLS = { title: "<fmt:message key='title' />", subtitle: "<fmt:message key='subtitle' />", //-- more entries as needed... }; portlet<namespace/>.byId("subtitle").innerHTML = NLS.subtitle;</script>

The I18NPortlet example project uses a hybrid approach with both the Java and Dojo resources. This example demonstrates how to merge both the Java and Dojo i18n resources. However, I would strongly discourage this technique in a real application! Stick with one of the two conventions as appropriate for your application.

Dojo eventsAnother one of Dojo's powerful features is its event architecture. On the surface, the feature might seem simplistic. However, with just a couple lines of event wiring code, your applications can reach a level of interactivity you never dreamed possible.

In its simplest form, you can attach an event listener to almost anything, from standard DOM events such as onClick to any function in any class. Listing 16 shows a few examples of events. See the Dojo book for an in depth discussion on the event subsystem.

Listing 16. simple event wiring examples// Call MyObj.pusher when a certain button is clickeddojo.connect("myBtn<portlet:namespace/>", "onclick", myObj, "pusher");

// send msg to host on console.error() (assuming internal to obj)dojo.connect(console, "error", this, "sendErrorToHost");

These examples are very simplistic, but they give you an idea of how easy it is to wire anything on your page to anything else. The possibilities are endless.

Styling dijits

As you know, the whole purpose of having a portal theme is to provide a consistent look and feel to the portlets and applications. Dojo provides its own themes for visual dijits using normal CSS style sheets including the gray tundra theme, the blue soria theme, a black noir theme, and a high accessibility theme called a11y. You can either choose to use one of the dijit themes that come bundled with Dojo, or use one as a guide to provide a visual styling that better matches your own portal theme.

One aspect of the dijit theme styling is the structure of identifying the classes. The dijit themes are structured so that the matching classes must be children of a block tag

15

Page 16: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

containing a class attribute that matches the theme name. The logic being that you could use different dijit themes on a page by wrapping different sections with div tags classed to the desired theme name. This concept fails for any dijits that create new floating div's such as the ToolTip dijit. Because they are created outside of the containing class div, they do not pick up the proper styling. This typically means that in order to properly apply to all dijits, you need set the <body> tag to have the desired class value of your theme, including ones created on-the-fly. However, real world scenarios probably do not need to have multiple dijit themes on a single page. The CSS class names used by the dijits are unique enough so that having the theme name as an extra containment rule is not necessary.

So, if you decide to use one of the built-in Dojo themes, you need to either hard code the class name in the theme's <body> tag, typically located in {theme}/Default.jsp, or use a little JavaScript to alter the DOM during rendering. This can be done in either the theme or portlets as shown here in Listing 17.

Listing 17. Alter body class name during render<script type="text/JavaScript> document.body.className = "soria";</script>

The add-on CSS examples forgo the theme name qualifier; they just use the dijit's class name. Consider using this same technique as a standard practice if you are doing a full portal conversion of an existing Dojo theme; then you do not have to bother tainting the <body> tag.

Custom modulesThis section can help develop and register custom objects the "Dojo way". By understanding this topic, you will be able to more easily understand the download sample code and you will know how to start to build your own objects. As described earlier, if you use a good object-oriented (OO) approach to your JavaScript development, you can encapsulate many of the namespace issues in your objects and minimize the use of global JavaScript variables.

To create and use custom modules in a Dojo application, you follow these few simple steps.

1. Create the folder structure for your modules .

2. Create (and extend) your module files .

3. Register the module package with Dojo .

4. Instantiate and use your new module .

16

Page 17: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Step 1 - Create folder structure

First, you define a folder structure to hold your JavaScript files. Do not locate it at the same level as your Dojo installation. Keep your resources in a different area so that when you upgrade Dojo levels, you do not need to worry about mixing resources. Just drop in the new Dojo directory, and go.

Where you put the files is up to you. Depending on how reusable you want your custom modules to be, you need to decide if they should be part of the theme or localized with each portlet. One idea is to put all JavaScript under a top level js directory, and then locate your modules there. You should also prefix all modules similar to the Java package naming conventions. In our case, we use "ibm.xxx" convention as the package name, so that all locally developed objects and resources are under the same tree. In the example portlets project, we also created a couple of specialized (non-reusable) objects that represent the portlet they support.

Step 2 - Create module files

Once you have defined your module structure, you write your objects. Convention has this as a proper case filename. Dojo objects have a clearly defined structure, as shown in Listing 10.

1. First, state what the objects this file provides.

2. Then, list any internally required dojo modules.

3. Finally, define your object using the dojo.declare function. This function takes three arguments: the object name as a string, the object to be extended as an object (no quotes), and the body of the object.

Within the object body, you define any members and functions that your object will provide. Convention states that you should prefix non-public members and functions with an underscore. While it is possible to create real private members, in practice, it is not typically worth the effort. Dojo will look for and process a special function called constructor during instantiation. Typically, you , use this to load your object with parameters passed in during creation. Using the dojo.mixin function makes this easy to complete. Any local members within your object are referenced using the "this." prefix.

Listing 10. /js/ibm/samples/Alerter.js – Fragment showing basic object structure/* File: /js/ibm/samples/Alerter.js */dojo.provide("ibm.samples.Alerter");

dojo.declare("ibm.samples.Alerter", null, { msg: null,

17

Page 18: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

/* Constrctor, set all variables passed in. */ constructor: function(args) { dojo.mixin(this, args); },

print: function() { alert( this.msg ); }} );// Be sure to close both the object body and declare function.

Step 3 - Register your module's package with Dojo

To use your custom module, you must inform Dojo of its existence, as shown in Listing 11. You only need to do this step if your package is outside of the Dojo peer level (as we suggested above). By default, Dojo only looks at the same level as the dojo provided packages. If you are dealing with cross domain Dojo builds, then this is practically irrelevant anyway. So it is best to tell Dojo where your package is located. This example applies our package from within a portlet, so we need to determine the proper path of our files using the getContextPath method.

Listing 11. Register module package with Dojo<script type="text/JavaScript"> //-- tell Dojo where our package is located dojo.registerModulePath("ibm.samples", "<%=renderResponse.encodeURL( renderRequest.getContextPath("/js/ibm/samples") )%>" ); //-- Tell Dojo to get our custom module. dojo.require("ibm.samples.Alerter"); //...</script>

Step 4 - Instantiate your object

After you have registered your package and loaded your module, you can create as many instances of your object as required. Listing 12 shows the standard syntax to instantiate a custom Dojo module.

Listing 12. Register module package with Dojo<script type="text/JavaScript"> dojo.addOnLoad( function() { var alerter = new ibm.samples.Alerter( { msg: "Hello, <%= renderRequest.getRemoteUser() %>" } ); // show a message alert alerter.print();</script>

18

Page 19: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

TroubleshootingJavaScript is an un-typed language and can be challenging to work with. There are cross-browser compatibility issues and odd quirks, as well as idiosyncrasies with the language that can easily trip up even experienced developers. This section discusses various ways to log and debug your JavaScript application. You also see some of those all-too-common coding mistakes that are easy to make and hard to troubleshoot.

DebuggersUntil fairly recently, JavaScript debuggers were either unavailable or complex to use. Today, we have some excellent choices for debugging JavaScript code, such as the Firebug plug-in for the Mozilla Firefox browser. It is easy to use and is considered by some to be the most powerful debugger available for any language. It is worth an hour of your time to learn such a debugger so you can tap into its capabilities.

For Internet Explorer, there are a couple of different options including the Microsoft Script Debugger (MSE), found in either the Office product or the Visual Developer suite. We have not used these products, so experimenting with them is left as an exercise for the reader. If you write clean standards-compliant code, and properly test it in Firefox and Firebug, then you will probably not have problems with Internet Explorer.

Logging on the clientIf you have a good JavaScript debugger, why bother with logging at all? This is a valid question, but there are many times when it is helpful to know how a program is progressing. Using a debugger to set break points and step through code is an invaluable tool for development. But what about when testing different browsers, or when you have a test user that does not have a debugger installed? With well-defined logging, you can easily follow the application flow. If you wanted to get really fancy, you can set an event on the console.error function and have any error message sent directly to the server for analysis. A simple Servlet and Dojo's AJAX support make this a trivial task, as shown in the downloadable sample programs.

Dojo uses the console command for all logging. If you do not have a console-enabled debugger installed on the browser, you can have Dojo instantiate a Firebug Lite console. This mini-console displays as an IFrame at the bottom of the browser to show output from debug and other logging commands.

To enable the mini-console, you must set the djConfig.isDebug variable to true prior to loading Dojo. WebSphere Portal administrators might want to selectively enable this ability only if the user has administrative privileges, as shown in Listing 18.

19

Page 20: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Listing 18. Enabling Dojo mini-console for logging fro portal administrators<%--If you want "Admin" users to be able to see logging in a Firebug Lite console, include this...--%><% boolean adminMode = false; %><wps:urlGeneration contentNode="ibm.portal.Administration"> <% adminMode = true; %></wps:urlGeneration>

<%--Define our Dojo Configuration (djConfig) variable PRIOR to loading the core Dojo.--%><script type="text/JavaScript" djConfig="parseOnLoad:true, isDebug:<%=adminMode%>" src="http://o.aolcdn.com/dojo/ 1.0.0/dojo/dojo.xd.js "></script>

The LoggingPortlet included in the sample code demonstrates various logging commands and how they render within the Firebug console, as shown in Figure 3.

Figure 3. Sample console logging output

Sending log messages to a serverYou can have log messages sent directly to the server for persistent logging and analysis. To make this happen, you need a few things. First, define an event listener so that any time console.error() is called, you also call a function that sends the log message to

20

Page 21: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

your server, using an AJAX call. You see the source code to accomplish this later in this article in the discussion of the download samples, Working with the sample files.

Listing 19 shows the client-side code that creates an event listener in our custom portal object. This code is located in the samples file DojoPortal_Theme/js/ibm/portal/Portal.js and is duplicated in DojoPortal_Portlets/WebContent/js/ibm/portlet/Portlet.js. Do not worry too much about the details in this sample because you learn more about them later in this article.

Listing 19. Enabling Dojo mini-console for logging//-- Create an event listener for console error's. console.debug("Registering Host Logging event handler for errors");ibm.HostLoggingErrorEvent = dojo.connect(console, "error", this, "_notifyHostOfErrorHandler" );

.../* ===================================================================== * Registered handler to send locally generated error messages to host */_notifyHostOfErrorHandler: function(/*event*/ event) { this.logToHost( event, "error");},

/* ===================================================================== * Send a message to the host for logging */logToHost: function(/*string*/ msg, /*string:opt*/type) { type = (type?type:"info"); console.debug("Portal.logToHost: [" + type + "] " + msg); var self = this; var deferred = dojo.xhrGet( { // The following URL must match that used to test the server. url: this.serviceUrl, content: {"action":"HostLoggingWorker", "user":this.user, "type":type, "msg":msg}, handleAs: "json-comment-filtered", timeout: 5000, // Time in milliseconds

// The LOAD function will be called on a successful response. load: function(response, ioArgs) { self.message("Portal: Host received log message: " + msg); },

// The ERROR function will be called in an error case. error: function(response, ioArgs) { //Don't make this an error message else will loop. self.message("Portal: Host failed to receive log message: "+msg); } } );},...

21

Page 22: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Any time console.error() is called, an event is triggered and the method arguments are also passed to our event handler. The handler redirects to the real method (which is provided so that you can send messages to the host on demand). The logToHost function creates an XHRGet object and sends the log details to the host. The host service simply extracts the parameters and adds them to a system log.

On the server side, you need a Servlet or other service to receive this message and append it to a log or take some other action. See the sample code provided with this article for an implementation of a service to log messages from the client. It is included in two places in the samples, based on how you instantiate Dojo, but the code is the same. See the file: DojoPortal_Service/src/ibm/dojoportal/service/workers/HostLoggingWorker.java.

Common coding mistakesLogging and debugging are the best ways to locate and resolve issues in JavaScript code. Still, it can be tricky to figure out what is causing a problem, especially when some browser error messages are not sufficient to identify the problem. Table 3 lists some very common mistakes that cause pages to fail to load or other odd behaviors. Many of these tips come from the Dojo Toolkit FAQ and are not all specific to Dojo or portal applications, but are consolidated here for your convenience.

Table 3: Common JavaScript mistakesCommon coding issue/Symptom

Wrong example Correct example

Do not use null body <div /> tags. Symptom: Dojo will typically fail to initialize.

<div id="hello" /> <div id="hello"></div>

Do not use null body <script /> tags. Symptom: Script resources will fail to load.

<script src="./js/hello.js" />

<script src="./js/hello.js"></script>

Do not duplicate "id" attributes. This is common in portal aggregation, so be sure to namespace all id's. Symptom: Wrong or multiple items in DOM get changed.

Portlet A:<div id='title'></div>Portlet B:<div id="title"></div>

Portlet A:<div id="title<portlet:namespace/>" ></div>Portlet B:<div id="title<portlet:namespace/>" ></div>

Do not have trailing commas in object creations. Symptom: Firefox doesn't care; IE will throw an error.

var myObj = { name:"bob", age: 23, // <bad comma!};

var myObj = { name:"bob", age: 23}

Do not have trailing commas in arrays.Symptom: Firefox doesn't care; IE will throw an error.

// Bad comma after last itemvar a = [1,2,3,4,];

var a = [1,2,3,4];

Ensure numbers are numbers and strings are strings.

// error if 'name' is a number

Dojo has many tests methods to check a variable's type. See

22

Page 23: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Symptom: Unexpected results and errors.

var x = name.length;// NaN result if 'a' is alphavar x = a * 10;

dojo/_base/lang.js

Limit use of global variables.Symptom: As with any language, you can easily get in trouble using globals when you don't need or intend to.

function test() { // 'a' is global here! a = getInput(); }

function test() { // 'a' is local here! var a = getInput(); }

Never manipulate the DOM using inline global JavaScript. This also applies to using the <body> tag's onload attribute in portal. Symptom: Undefined results. Use dojo.addOnLoad.

<script ...>dojo.byId("x").innerHTML = dojo.someAction();</script>

<script ...>dojo.addOnLoad( function() { dojo.byId("x").innerHTML = dojo.someAction();} );</script>

Another good habit to adopt is to run your JavaScript code through a lint checker (code validator). You can use the JSLint web site to check your code. Also, see the documentation on that site for good coding styles in JavaScript. You can save yourself hours, if not days, by checking your code and reading the help documentation. Make sure you take the time to understand the warnings that JSLint produces; do not simply make code changes to pass the tests.

Working with the sample files You are encouraged to download and examine the source code included with this article. The samples expand on the article discussion and show you several ways to improve your portal development. The files are in IBM Rational® Application Developer (hereafter called Application Developer) project interchange format. Simply import this file into your workspace. If you are not using Application Developer, then you can unzip the files into a directory of your choice.

Now, we look at various files of interest in each of the included projects to help you gain a solid understanding of their purpose and to see how you can use them in your own portal application.

Project: DojoPortal_Theme

To make your own Dojo customized theme, you simply copy an existing theme and make the appropriate changes as described in this article. For example:

1. Copy the files included in the DojoPortal_Theme project into the base of your new theme. The examples contain two Dojo-Portal initializer files:• DojoXDPortalInit.jspf - Use with a cross domain version of Dojo.• DojoPortalInit.jspf - Use with a local installation of Dojo. If you use the local

version, you need to download and install the Dojo files into your theme.

23

Page 24: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

2. Load one of these Dojo initializer files into the <head> section of your theme JSP, as shown in listing 20.

Listing 20. head.jspf – Include proper Dojo init JSP fragment<head>...<%@ include file="DojoXDPortalInit.jspf" %></head>

3. After you have made the required changes, install the theme into WebSphere Portal and add it to a new page.

4. Load the page in your browser.

• On Firefox browsers that contain the Firebug debugger, you will see the console log messages along with a list of dojo module loads appear in the console.

• Internet Explorer users see a small console window along with the console log entries. Looking at the code in Listing 3, you see that we defined the "djConfig.isDebug" variable during the dojo load. This code turns on the mini-console in Internet Explorer. Under normal circumstances, you probably do not want this enabled.

If you are using Internet Explorer Version 6 and receive an error regarding "Operation Aborted" with a customized IBM portal theme, then you will need to perform a fix to the head.jspf file. Around line 170 (if you are using WebSphere Portal V6.0.0.0), add a closing </base> tag as shown in Listing 21. Add the last line only. For more information, see http://trac.dojotoolkit.org/ticket/557.

Listing 21. head.jspf – Fix errors in Internet Explorer 6 when using IBM theme<%-- This includes a base URL that can be used by other applications.This can result in much shorter URLs and decrease overallpage size and bandwidth use --%><portal-core:stateBase/><!--[if IE]></base><![endif]-->

Now, examine one or both of these Dojo initializer files.

Files: DojoPortalInit.jspf and DojoXDPortalInit.jspf

These files enable you to load Dojo into your portal theme. The only interesting part that we have not already discussed is near the end of the file. The code in Listing 22 creates a context variable (ctx) that is a URI to the theme base. In the cross domain version of this file, we are setting the djConfig.baseUrl to "/", and we strip the leading slash off of our

24

Page 25: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

theme context path. This is to work-around a limitation in XD builds to enable local modules to be properly located.

Also, the code registers and instantiates a custom Dojo module called ibm.portal.Portal. This is a convenience object to assist you in dealing with portal specifics in your JavaScript code. The result is a global instance variable called portal that is available in the theme and to each portlet. We pass in an initializer object containing several portal specific variables to the portal object.

Listing 22. DojoXDPortalInit.jspf – fragment showing instantiating Portal object.var ctx = "<portal-logic:urlFindInTheme file='js/ibm/portal/Portal.js' />" .replace("js/ibm/portal/Portal.js", "") .slice(1);

dojo.registerModulePath("ibm.portal",ctx+"js/ibm/portal");dojo.require("ibm.portal.Portal");

var portal;dojo.addOnLoad( function() { console.log("Building dojo Portal object"); portal = new ibm.portal.Portal( { context: "/"+ctx, serviceUrl: "/portal/PortalService", user: "<%= request.getRemoteUser() %>", scheme: "<%= request.getScheme() %>" } ); console.debug("Portal object: ", portal );} );

File: js/ibm/portal/Portal.js

The Portal object is a custom Dojo module that provides several valuable members and functions to help you write portal-aware JavaScript. We discuss a similar Portlet object below. Table 4 provides a synopsis of the functions provided by the Portal object.

Table 4: Custom Dojo Portal object APIMember / Function Descriptioncontext Base URI of the theme. Use this value when creating

URL's to theme local resources such as images.serviceUrl URL of an arbitrary host service that will accept requests

from clients. In our examples we use a single service to accept all AJAX based client requests.

user User ID of the logged in portal user.scheme Typically "http" or "https". Useful for building URL's

for images or other resources. This can help prevent IE errors resulting when mixing secure and insecure resources on a page.

constructor( obj ) [Non-public]

25

Page 26: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Creates a logging event listener to send any console.error messages to the host service for persistent logging.

Creates a "toaster" dijit for displaying toaster-like temporary pop-up messages to the user.

loadSessionAttribute(key)saveSessionAttribute(key,val)

Make service call to get or set a session value. Useful for persisting values between portlets in an application.

Notes: Assumes that PortalService is deployed at

'serviceUrl'. This session is outside of the portlet scope and

does not share a portlet session. This implementation only accepts simple

singleton strings.message(msg)error(msg) Writes a message to the console log and also pops up a

temporary toaster message to the user.logToHost(msg,type) Sends a message of type "info" or "error" to the host

service for logging._notifyHostOfErrorHandler() [Private] Handler for console.error event. Simply

calls 'logToHost()' with an error type.

Project: DojoPortal_Service

DojoPortal_Service includes a simple REST-like servlet and worker classes. If you configure your environment to load Dojo in your theme and you plan to use the ibm.portal.Portal object, then deploy this DojoPortal_Service WAR. Ensure that the base URI used during deployment matches the serviceUrl passed into the JavaScript Portal object, which is hard-coded in the samples as /portal/PortalService.

In the servlet, we look for an attribute called action, and from that we attempt to instantiate a class by the same name, passing in the other arguments. The results are created as a commented JSON object and serialized to the client. You could easily expand this metaphor for simple service requests.

In a real world scenario, you could use a REST Servlet like the one presented here, or a true Web Service or any other URL-accessible entity. The implementation of this service is loosely based on the article and code presented in Dr. Dobbs Journal, July 2007 by Eric J. Bruno, called "SOA, Web Services, and RESTful Systems - A framework for building RESTful systems" (see Resources for a link).

Project: DojoPortal_Portlets

This project contains the core of the samples. All the portlets are in a single deployment for ease-of-use. We deviated from the normal file structure somewhat to keep things

26

Page 27: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

more organized. In this project, you see some duplication of files, which is by design and convenience.

When you examine the source code, you see that the portlets simply pass control to the appropriate View.jsp file. This design is to focus and re-enforce the concept that we are dealing with a client-side HTML and JavaScript-based technology. Everything is defined in the JSP files. Remember that Java scriptlets and taglibs contained with the JSP are processed on the host prior to sending to the client. In many places, we seed various JavaScript object with host variables.

Each portlet in this project creates a custom Dojo module named 'Portlet' to aid in managing the local application logic. Each object takes a single constructor argument of the portlet object, which is used internally to encapsulate the portlet and namespace properties.

Look at a few of the supporting files before we dive into the portlets and the concepts they present.

File: DojoPortletInit.jspf

The DojoPortletInit.jspf file is a JSP fragment that is to be included in all Dojo portlets. This file provides two primary roles. First, it provides a boolean flag called USING_THEME_BASED_DOJO that you can set to false if you are not using a theme-based Dojo implementation. If the flag is false, then the same basic steps are followed to properly initialize Dojo. To help manage the size of the deployment WAR file, use a cross domain instance of Dojo if you are instantiating from within individual portlets.

The purpose the DojoPortletInit.jspf file is to load a portlet-specific Dojo object called ibm.portlet.Portlet. (Yes I know, I have zero creativity in naming my packages and objects. I assume this to be a quality, rather than a snooze inducing detriment.) Listing 23 shows the instantiation of the Portlet object. We define a variable called portlet<portlet:namespace/>, which is required so that there are no namespace collisions on the object instance in this portlet with ones in other portlets. We pass in a large number of portlet-specific object members into the constructor. This results in a clean object base that can then be passed into other objects, without having to worry too much about the portal specific environment.

Listing 23. jsp/DojoPortlet.jspf – Fragment showing Portlet object creation// Remove leading slash as we defined our djConfig.baseUrl to "/"// This prevents a XD dojo trying to find our local modules on XD host.if ( djConfig.baseUrl == "/" ) { dojo.registerModulePath("ibm.portlet", "<%=PORTLET_CONTEXT.substring(1)%>/js/ibm/portlet");} else { dojo.registerModulePath("ibm.portlet", "<%=PORTLET_CONTEXT%>/js/ibm/portlet");}dojo.require("ibm.portlet.Portlet");

27

Page 28: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

// This must be a global variable to be used in parent jsp files.var portlet<portlet:namespace/>;dojo.addOnLoad( function() { console.log("Building dojo Portlet object"); portlet<portlet:namespace/> = new ibm.portlet.Portlet( { namespace: "<portlet:namespace/>", context: "<%=PORTLET_CONTEXT%>", serviceUrl: "<%=PORTLET_CONTEXT%>/PortletService", actionUrl: "<portlet:actionURL/>", renderUrl: "<portlet:renderURL/>", user: "<%= renderRequest.getRemoteUser() %>", portletMode: "<%= renderRequest.getPortletMode().toString() %>", scheme: "<%= renderRequest.getScheme() %>", windowState: "<%= renderRequest.getWindowState().toString() %>" } ); console.debug("Portlet object: ", portlet<portlet:namespace/> );} );</script>

All the portlets in these examples create their own custom Dojo modules. Each one receives this portlet instance object into the constructor so that they can safely access portlet-specific values, as you see below.

File: js/ibm/portlet/Portlet.js

The js/ibm/portlet/Portlet.js file is a simple Dojo module that is similar to the ibm.portal.Portal object; however, it provides several extra members and functions. We purposefully did not simply extend the Portal object because we wanted to keep the namespacing different (because of path differences); also, we wanted to ensure separation of concerns for the host service URL. Table 5 provides a synopsis of the functions that the Portlet object provides.

Table 5: Custom Dojo ibm,portlet.Portlet object APIMember / Function Descriptionnamespace Namespace of this portlet. Used heavily for id and

global variable access.context Base URI of the portlet. Use this value when creating

URL's to portlet local resources such as images.serviceUrl URL of an arbitrary host service that accepts requests

from clients. In our examples, we use a single service to accept all AJAX-based client requests.

actionUrl URL used to submit to the portlet's actionPerformed() method. Can be used in dynamic forms or links.

renderUrl URL used to submit to the portlet's doView() method for a page refresh.

user User ID of the logged in portal user.portletMode String indicating the current mode of the portlet.

Values include: "view", "edit", "config"

28

Page 29: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

windowState String indicating the current state of the portlet. Values include: "normal", "maximized", "solo". Minimized portlets do not render, therefore, this object would never be created.

scheme Typically "http" or "https". Useful for building URL's for images or other resources. Use to help prevent Internet Explorer errors resulting from mixing secure and insecure resources on a page.

constructor( obj ) [Non-public] Creates a logging event listener (if none

currently exists) to send any console.error messages to the host service for persistent logging.

Creates a toaster dijit (if it does not exist) for displaying messages to the user.

byId( id )byDijitId( id ) Simple wrapper to the standard dojo.byId and

dijit.byId functions. Tries to obtain the id using a namespace first, and falls back to a non-namespaced id string.

setFormField(name,val,add)submit() Function to build an internal form for later submission

to the portlet's actionPerformed() method. The setFormField function takes a name and value, with an optional boolean to indicate if the value should be appended as an array to an existing entry of the same name. Default is false.

loadSessionAttribute(key,global)saveSessionAttribute(key,val,global)

Makes a service call to get or set a session value. Useful for persisting values in or between portlets in an application.

Notes: Assumes that PortletService is deployed at

serviceUrl. Optional global boolean argument determines

if the load/save occurs at a global level instead of the default portlet level.

This implementation accepts simple singleton strings only.

message(msg)error(msg) Writes a message to the console log and also pops up a

temporary toaster message to the user.logToHost(msg,type) Sends a message of type "info" or "error" to the host

service for logging._notifyHostOfErrorHandler() [Private] Handler for console.error event. Simply calls

logToHost() with an error type.

29

Page 30: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Servlet: PortletService

See the discussion on the Project DojoPortal_Service. The PortletService servlet is essentially a duplicate of the Portal Service, except that it is bundled along with the portlets. The namespacing is handled automatically by the Portlet JavaScript object.

Portlet: LoggingPortlet

This simple portlet example sends several logging messages to the console as shown in Figure 4.

Figure 4. Sample Logging portlet and Firebug output

The logging messages are produced from a custom Logging module. It contains a single testLogging function that is shown in Listing 24. Different console output types are used, as well as a special timer console function.

Listing 24. testLogging function//==================================================================testLogging: function() { var ME = "logging.testLogging: "; var timeEnd = "Logging test complete"; console.time( timeEnd ); console.log(ME + "This is a 'console.log()' message"); console.debug(ME + "This is a 'console.debug()' message"); console.info(ME + "This is a 'console.info()' message"); console.warn(ME + "This is a 'console.warn()' message"); console.error(ME + "This is a 'console.error()' message"); console.log(ME + "The above 'error' should be sent to host.");

30

Page 31: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

try { console.log(ME + "Throwing an Error now..."); throw new Error("An Error thrown on purpose"); } catch ( e ) { console.error(ME + "Caught this error: " + e.message); console.log(ME + "The above 'caught error' sent to host too!"); } // waste some time.... for( var i = 0; i < 1000; i++ ) { Math.log(i); }

console.log(ME + "Next log entry will show how long this took"); console.timeEnd( timeEnd );}

Another aspect of this test function is to generate some errors. As shown earlier, we have established a global event listener on the console.error function. The code in Listing 24 makes two different error calls. Looking at the Firebug console and the host's STDOUT log shows that each error generated an XHR call to the host with the error messages. Listing 25 shows a fragment of the host's error log. While the formatting looks a little odd in this listing, you can see that we have successfully captured the user, source system, and error message in the logs.

Listing 25. Partial log output on the host system[8/29/07 21:09:32:485 EDT] 00000045 ServletWrappe A SRVE0242I: [DojoPortal_Service_war] [/portal] [PortalService]: Initialization successful.

[8/29/07 21:09:32:528 EDT] 00000045 HostLoggingWo E [[email protected]]: logging.testLogging: This is a 'console.error()' message

[8/29/07 21:09:32:528 EDT] 00000048 HostLoggingWo E [[email protected]]: logging.testLogging: Caught this error: An Error thrown on purpose

The site administrator can easily determine which of our users might be experiencing client-side errors while using our application. You could even be proactive to reach out to the user and try to resolve their problem BEFORE they call the help desk. (OK, maybe that idea was a little far fetched.)

Portlet: I18NPortlet

This sample shows how to easily internationalize your applications when using Portal and Dojo. It includes a dropdown calendar dijit, with several different text values. This is a complex dijit that contains many different initializers.

31

Page 32: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Figure 5. Sample calendar shown in English

To show a different language, go into your browser's preferences and set the preferred language.

The sample i18n application contains translations for French (fr), German (de), Spanish (es), and Arabic (ar). (Please forgive any translation errors, as I can only speak and write in English – with mediocre capability at best – and used BabbleFish to do my translations for me. I would also like to thank my Egyptian team members for their help in the Arabic translation.) The Arabic translation is interesting because it uses right-to-left (RTL) formatting. Dojo supports RTL, but does not currently have Arabic translation in its dijits.

Figures 6 and 7 show our i18n portlet rendered in different languages. The calendar headers are automatically presented in the proper locale as well.

32

Page 33: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Figure 6. Sample calendar shown in German

Figure 7. Sample calendar shown in Spanish

The fragment in Listing 26 shows how to take Java properties and apply them to a DropDownCalendar dijit. In the rangeMessage entry, we replace the {min} and {max} tokens with customized values.

Listing 26. Creating an NLS enabled DropDownCalender dijit<script type="text/JavaScript"> dojo.addOnLoad( function() { var NLS = { datePromptHelp: "<fmt:message key='datePromptHelp' />", dateInvalidHelp: "<fmt:message key='dateInvalidHelp' />", dateRangeHelp: "<fmt:message key='dateRangeHelp' />" };

33

Page 34: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

var minDate = new Date(1900,0,1); var maxDate = new Date(1999,11,31); var dateProps = { value: new Date(1965,6,3), constraints: {datePattern:"yyyy-MM-dd", min:minDate, max:maxDate}, promptMessage: NLS.datePromptHelp, rangeMessage: dojo.string.substitute( NLS.dateRangeHelp, { min:minDate.toDateString(), max:maxDate.toDateString() } ), invalidMessage: NLS.dateInvalidHelp, size: "12", required: true }; var startDate = new dijit.form.DateTextBox( dateProps, "DOB<portlet:namespace/>" ); } );</script>

Portlet: SessionPortlet

SessionPortlet introduces the concept of reading and writing session variables from the client, which provides an avenue for managing persistence between a client Dojo application and the portlets. There are two modes available for reading and writing variables. You can use each local session that is private to the specific portlet. You can also use a global session that can be shared among all portlets and clients within the same Web application (WAR). This flexibility in choosing your session persistence scope is a good argument for combining portlets within a single project WAR.

SessionPortlet uses the portlet object and connects to the session service bundled with the WAR file. There is also a session service available from the portal object. The difference with the portal version is that the session variable is truly global, and is maintained within its own Web application scope. In order for portlets or servlets outside of a common Web application (WAR) to share data is to use the external 'portal' scoped service.

34

Page 35: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Figure 8. Sample Logging portlet and Firebug output

Look at the loadValue() function in the SessionPortlet/Session.js object, shown in Listing 27. This function is called when the user clicks one of the load value buttons, and it acts as a localized wrapper for the generic loadSessionAttribute() function of our Portlet class. A lot happens in these few lines, so we will walk through them.

First, we disable the value field and show a "Loading…" message, so that the user knows something is actually happening. Depending on the network and server speed, the user might not get a chance to see this message, but it is always a good idea.

When you are dealing with a deferred object and callbacks such as XHR calls, the typical this variable refers to the XHR object and not the instance of the class you are processing. So, to reference private members of our class, we create a simple alias called self that we can use within the body of the callback function.

Next, we call the portlet object's loadSessionAttribute function and get a deferred object in return. We inform the deferred object that we have a callback to be processed in the form of an anonymous function. This callback outputs a momentary "toaster-like" pop-up message informing the user that the process has completed, and then places the received value into the value field and re-enables the field.

35

Page 36: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Listing 27. _SessionPortlet/Session.js:loadValue() – loading session value//==============================================loadValue: function(/*bool:false*/ global) { console.debug("Session.getValue(): Obtaining value for key: " + this._keyFld.getTextValue() ); this._valFld.setDisabled(true); this._valFld.setValue("Loading..."); //-- In callback, the "this" variable is actually the response obj //-- So we create a reference our top level obj to use in callback! var self = this; //-- Get our value from portlet.loadSessionAttribute() var deferred = this.portlet.loadSessionAttribute( this._keyFld.getTextValue(), global ); deferred.addCallback( function(response){ self.portlet.message( (global?"Global":"Portlet") + " session load completed for: " + response.key + " = " + response.value); console.debug("session.loadValue(): callback response: ", response); self._valFld.setValue( (response.value ? response.value : "*undefined*" ) ); self._valFld.setDisabled(false); } );},

Finally, examine the submit() function of the Session.js file (Listing 28). In this simple function that is called when the user clicks the Submit button, the portlet's internal dynamic form functions generate and submit a form on the fly. This particular example does not send much data to the portlet's actionPerformed()method; it just shows you how easy it is to return dynamic form data to the portlet.

Listing 28. _SessionPortlet/Session.js:submit() – Fragment showing dynamic form//==========================================================submit: function() { this.portlet.setFormField("action", "Session client submit"); this.portlet.message("Session: Submitting form to portlet"); console.debug("Session: Submitting form to portlet"); this.portlet.submit();}

ConclusionThis article has shown you several issues and solutions for using the Dojo Toolkit inside your WebSphere Portal applications. We have also attempted to show you enough of the features and capabilities of Dojo to entice you to exploit it in your applications. While developing complex applications in JavaScript can be frustrating at times, the rewards of pushing the browser as a rich client platform are well worth it. Today's users expect a lot of functionality in their Web applications. Using Dojo and WebSphere Portal together meets that demand. Have fun!

36

Page 37: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

DownloadTo download the code samples, see the cover page for this article:http://www.ibm.com/developerworks/websphere/library/techarticles/0711_bishop/0711_bishop.html

Resources

Ajax and other Web 2.0 resourcesAJAX resource centerhttp://www.ibm.com/developerworks/ajax

Building Ajax portlets for WebSphere Portalhttp://www.ibm.com/developerworks/websphere/library/tutorials/0608_bishop/0608_bishop.html

Creating JSON in Javahttp://www.json.org/java/index.html

Leveraging the new Ajax features in WebSphere Portlet Factory V6.0.1http://www.ibm.com/developerworks/websphere/library/techarticles/0711_cooke/0711_cooke.html

Meet the experts: Creating Web 2.0 portals using AJAX and REST with WebSphere Portalhttp://www.ibm.com/developerworks/websphere/library/chats/0705_hesmer/0705_hesmer.html

SOA, Web Services, and RESTful Systems - A framework for building RESTful systems, by Eric J. Brunohttp://www.ddj.com/architect/199902676

Using Ajax with WebSphere Portalhttp://www.ibm.com/developerworks/websphere/library/techarticles/0606_bishop/0606_bishop.html

Dojo Toolkit ResourcesDojo Toolkit: http://dojotoolkit.org/Download Dojo Toolkit v1.0.0: http://dojotoolkit.org/downloadsThe book of Dojo: http://dojotoolkit.org/book/dojo-book-0-9-0Dojo API: http://dojotoolkit.org/docs/apiDojo Toolkit FAQ: http://dojotoolkit.org/support/faqDojo discussion forums: http://dojotoolkit.org/forum Using Dojo on AOL's CDN: http://dev.aol.com/dojo

37

Page 38: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Support and other related resourcesDynamic HTML, The Definitive Guide, 3rd Ed, by Danny Goodman. O'Reilly Media, Inc., December 2006, ISBN-10: 0596527403.

JavaScript, The Definitive Guide, 3rd Ed, by David Flanagan. O'Reilly Media, Inc., August 2006, ISBN-10: 1565923928.

"IE 6 refuses to load page if dojo is loaded in HEAD and a BASE tag exists before that."http://trac.dojotoolkit.org/ticket/557

ToolsDouglas Crockford's JavaScript Verifier sitehttp://www.jslint.com/

Joe Hewitt's Firebug debugger plug-in for Firefoxhttp://www.getfirebug.com

WebSphere Portal resourcesDownload a free trial of WebSphere Portal Expresshttp://www.ibm.com/developerworks/downloads/ls/wpe/?S_TACT=105AGX10&S_CMP=ART

WebSphere Portal product documentationhttp://www.ibm.com/developerworks/websphere/zones/portal/proddoc.html

Websphere Portal zonehttp://www.ibm.com/developerworks/websphere/zones/portal/

About the authorsKarl Bishop is a Senior Software Engineer at IBM, working out of his home in the Sandhills of North Carolina. He leads an international team that works on several IBM portal based applications. Karl's technology focus areas are in Linux, virtualization, DHTML/AJAX, XML, WebSphere Portal and various IBM middleware products. Doug Phillips is an Advisory Software Engineer for IBM's elite group of skilled professionals known as IBM's Web Enablement and Support team. He has worked in many organizations within IBM and currently designs and develops both internal and external WebSphere Portal applications using IBM middleware and Linux. Doug is WebSphere and DB2 certified.

38

Page 39: Using the Dojo Toolkit with WebSphere Portalpublic.dhe.ibm.com/software/dw/wes/pdf/0711_bishop-Dojo-and-WP… · Dojo is a JavaScript™ based toolkit that you can use to enhance

Trademarks• DB2, IBM, Lotus, Tivoli, Rational, and WebSphere are trademarks or registered

trademarks of IBM Corporation in the United States, other countries, or both.• Windows and Windows NT are registered trademarks of Microsoft Corporation in the

United States, other countries, or both.• Java and all Java-based trademarks and logos are trademarks or registered trademarks

of Sun Microsystems, Inc. in the United States, other countries, or both.• Other company, product, and service names may be trademarks or service marks of

others.

IBM copyright and trademark information: http://www.ibm.com/legal/copytrade.phtml

39