Archive

Posts Tagged ‘JavaScript’

Rich Internet Applications with Dojo

April 30th, 2010 Tom 1 comment

Last week I gave a talk at BIRM, an organization which organizes education for adults, organized a “Day of knowledge”. This event highlighted the importance of education and continuous learning during one’s career. During the event, several workshops in different domains, such as IT, marketing, insurance, … were organized. I had the privilege to give a workshop on “Rich Internet Applications with Dojo”.

In the talk I motivated why we chose Dojo as a technology to build internet applications, highlighted the internal structure of the Dojo toolkit and showed some web pages and applications that we’ve built on the Dojo. In conclusion, I touched the importance of web applications and web standards in a word where mobile devices will soon outnumber desktop and laptop computers.

These are the slides, don’t hesitate to contact me in case of questions:

Categories: JavaScript, dojo Tags: ,

dojo.beer() @ Devoxx09: Dojo Crud Components

January 12th, 2010 Tom Comments off

I had the privilege to host a dojo.beer() mini workshop at Devoxx09 as BOF session. The session was pretty late (9pm) and not during the university track, which probably explains why not too many people showed up. Nonetheless, I talked about our experiences with dojo there and got some positive feedback about our architectural approach. In the talk, I mainly discussed why we chose dojo as RIA technology, elaborated on the custom dojo components we developed and explained how we integrated DWR and our custom dojo components with an enterprise computing software architecture.

These are the slides:

Creating a Custom WaveMaker Editor component

December 22nd, 2009 Tom 2 comments

A comment I received while developing a WaveMaker application was that WaveMaker TextArea Editors do not retain line breaks (\n). Apparently when the TextArea is in read-only mode, the line breaks are lost. When the editor is active (editable) the line breaks appear to be still there:

EditorWithoutLineBreaks

The left hand side of the picture shows the WaveMaker TextArea Editor in read-only mode, the right hand side shows the editor in editable mode. What we really want is this:

EditorWithLineBreaks

If the editor is in read-only mode (left hand side), the line breaks should be preserved. Also, a scrollbar should appear when the editor cannot display the entire contents.

Creating a custom WaveMaker editor

The reason line breaks are lost in WaveMaker’s TextArea editor is that a ‘\n’ character has no meaning in HTML. In read-only mode, the display value (including new-line characters) of a WaveMaker editor is put in a <div>-tag. Of course, a new-line character in a <div> tag does not translate to a line break in your browser.

WaveMaker allows you to create your own components. It is explained on the WaveMaker developer pages and forums. This post describes how I applied that information to create a custom WaveMaker editor. This NewLineTextArea editor replaces new-line characters with HTML line breaks (<br>) when it is in read-only mode. Additionally, a scroll bar is added in case the read-only mode editor cannot show the entire value.

Creating WaveMaker components is usually done by manually editing files. Since WaveMaker 5 there appear to be visual ways to create new, custom components. However, that approach is not feasible for our custom TextArea Editor. It is much simpler to inherit from WaveMaker’s default TextArea component, modify its behavior where necessary and then register it with the studio. WaveMaker is built on dojo, so we will be editing dojo classes.

WaveMaker Editor design

WMEditor

The figure shows a simplified UML model of WaveMaker’s editor implementation. WaveMaker editors are all subclasses of wm.Editor. This class aggregates the label (captionLabel) and the actual editor implementation (editor). The editor implementation is the actual editor and is displayed next to the label. The type of editor that is instantiated is always a subclass of wm._BaseEditor. The exact type that is instantiated is determined by the value of the display attribute in the wm.Editor subclass.

In the studio, you create an editor by dragging it from the palette to the canvas. You can always change the type of editor by modifying the display attribute using a drop down box. Possible editor implementations are simple text boxes, text areas, checkboxes, currency editors, etc.

The NewLineTextArea Editor implementation

To create a custom WaveMaker editor, you create a subclass of wm._BaseEditor, and plug it in to your WaveMaker studio. This is the source code for my new line aware text editor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
dojo.provide("common.packages.ppwcode.NewLineTextArea");
 
dojo.require("wm.base.widget.Editor");
dojo.require("wm.base.widget.Editors.Text");
 
wm.editors.push("NewLineTextArea");
 
dojo.declare("wm._NewLineTextAreaEditor", wm._TextAreaEditor, {
    autoScroll: true,
    setReadonly: function(readonly) {
        this.autoScroll = readonly;
        this.inherited(arguments);
    },
    _getReadonlyValue: function() {
        var t = this.inherited(arguments);
        var rex = new RegExp("[\\n\\r]", "gi");
        return t.replace(rex, "<br>");
    },
    sizeEditor: function() {
        // sizeEditor is an exact copy of wm._TextAreaEditor with one
        // modification: the width is reset to zero if it appears no be
        // negative.  A negative width is returned from getContentBounds
        // in IE8 when autoScroll is turned on. The DOM model seems to
        // have a problem with a negative width.
        if (this._cupdating)
            return;
        var e = this.editor;
        if (e) {
            var
                bounds = this.getContentBounds(),
                // note, subtract 2 from bounds for dijit editor border/margin
                height = bounds.h ? bounds.h - 2 + "px" : "",
                width = bounds.w  ? bounds.w - 4 + "px" : "",
                d = e && e.domNode,
                s = d.style,
                fc = d && d.firstChild;
 
            // Keep IE(8) happy
            if (parseInt(width) < 0) width = "";
 
            if (!this.editorBorder) s.border = 0;
            s.backgroundColor = this.editorBorder ? "" : "transparent";
            s.backgroundImage = this.editorBorder ? "" : "none";
            s.width = width;
            if (height) {
                if (fc) {
                    dojo.forEach(fc.childNodes, function(c) {
                        if (c.style) {
                            c.style.height = height;
                        }
                    });
                }
                if (e.focusNode && e.focusNode.style)
                    e.focusNode.style.height = height;
            }
        }
    }
});
 
dojo.declare("common.packages.ppwcode.NewLineTextAreaEditor", wm.Editor, {
    display: "NewLineTextArea"
});

The first 3 lines of code are mandatory dojo dependency management. We will be extending WaveMaker’s editor components, so they must be loaded before we can use them.

Line 6 adds our NewLineTextAreaEditor to the list of supported editors. wm.editors is an array of strings that contains the list of supported editors. This list is shown in the display drop down box in the studio.

Line 8 declares the editor’s class. The name of your custom editor is important. The class name of the editor implementation is determined by prepending wm._ and appending Editor to the value of the display attribute. So if we add NewLineTextArea to wm.editors, we must declare a class wm._NewLineTextAreaEditor. The class inherits from wm._TextAreaEditor because the class effectively behaves like WaveMaker’s TextArea editor. Except in read only mode, we want line breaks to be preserved.

The autoScroll property on line 9 is an inherited property that determines the scroll behavior of the HTML element that shows the value in the editor. In read-only mode, this element is a simple <div> node. The autoScroll value is initialized to true. This corresponds to the value we want the autoScroll property to have when the editor is in read-only mode; scroll bars will added to the <div> node if necessary. When the editor is in write mode, the <div> is replaced by a <textarea> node in which line breaks are already preserved. A <textarea> node also adds scrollbars automatically when necessary. autoScroll is set to false when the editor is not in read-only mode. The setReadOnly method (line 10) is overridden to alter the autoScroll property depending on the value of the readonly parameter.

The _getReadonlyValue method (line 14) is probably the most important method in this class. It transforms newline characters in a string to <br> tags. This preserves the line breaks when the editor shows the value in read only mode. The method is normally seen as a private method because it starts with an underscore. In principle, this method hence should not be overridden. On the other hand, other editor implementations override it too. So I guess it can be considered as a friend function or a package visible function.

The sizeEditor method (line 19) implementation is the same as the method in the superclass, with one modification. We verify if the width of the editor is smaller than zero. If you application runs in Internet Explorer and scrollbars are present, the calculated editor width can be negative. The DOM model however can not cope with negative widths. The overridden sizeEditor method works around this problem: if the width is negative – this only occurs when the page is being loaded, and the editor is not yet shown on the page – we reset it to zero (line 39).

Last but definitely not least, on line 60 the WaveMaker editor class that encapsulates the NewLineTextArea editor is declared. This is done by creating a subclass of wm.Editor and assigning the string “NewLineTextArea” to the dispay property.

Adding the editor to WaveMaker Studio

Having an implementation of an editor is one thing. You must still tell WaveMaker studio where to pick up your code. This is also explained in WaveMaker’s documentation on creating Custom Widgets.

Custom code is located in your WaveMaker workspace. The workspace is in a directory you created the first time you installed WaveMaker. Custom code should be placed in the commons/packages directory in the WaveMaker workspace:

Our editor provides common.packages.ppwcode.NewLineTextArea, so all our code goes into common/packages/ppwcode/NewLineTextArea.js in the WaveMaker workspace. You then need to modify lib.js en packages.js to load your code into the studio, and eventually your WaveMaker application.

In lib.js you must add dojo.require statements for the extra javascript files you want to load:

dojo.require("common.packages.ppwcode.NewLineTextArea");

In packages.js you must add an array with information about your custom widget. This will add your custom widget to the Palette in WaveMaker studio.

[ "PeopleWare", 
  "NewLineTextArea", 
  "common.packages.ppwcode.NewLineTextAreaEditor",
  "common.packages.ppwcode.NewLineTextArea", 
  "images/wm/edit.png", 
  "A Text Area that supports new lines."
]

The first element in the array is the name of the widget category in the palette. In our example, we create a new category called PeopleWare. The second element is the name of the widget, which we call NewLineTextArea. The third element is the dojo class name of the widget. The fourth element is the name of the module in which that class is located. This is the name of the module you’ve added to lib.js. The fifth element is an icon for your widget; here we use a standard editor icon. The last element in the array is a short description of the widget.

If everything is in place, the palette of your studio looks like this:

From the palette, you can drag your custom widget to the application canvas. This widget will behave like WaveMaker’s TextArea Editor, but in read-only mode line breaks will be preserved.

Creating custom dojo builds in maven

June 25th, 2009 Tom 8 comments

We make extensive use of the dojo toolkit in our Java web applications. An important step in the development process of a dojo web application is creating a custom dojo build.  This post describes how we create custom dojo builds as part of our maven build process.

Why custom dojo builds

We use a lot of dijits and custom built dojo components in our web applications.  By consequence, you can easily end up with a web application that uses dozens of components. In a non-cross domain dojo setup, each component is downloaded synchronously in order not to break the component dependency graph. No need to explain that your application will load slowly if you don’t take extra precautions (slow script error, anyone?).  A custom dojo build optimizes the load and execution time of a dojo application (more details can be found in the dojo documentation).

We build, test, package and deploy our Java (web) applications with maven, and creating a custom dojo build is part of that build process.

Our maven approach

Preparing your maven project for a custom dojo builds consists of three steps:

  1. Obtaining a dojo source distribution
  2. Unpacking the source distribution
  3. Running the build script in the obtained dojo source distribution

Step 2 and 3 require configuring a plugin in the project’s POM file. We only use standard maven plugins, i.e. plugins that exist in the maven repository.  We did not write custom plugins.

After executing these steps, you can do two things:

  1. Build a war file that contains a web application with a dojo production build
  2. Prepare Eclipse configuration files to run the application on a WTP enabled Eclipse IDE

The rest of this post describes the 5 points outlined above in greater detail. The build process is parametrized using parameters in the maven POM file. Each parameter is explained at the end of the post.


1. Obtaining a dojo source distribution

To be able to make a custom dojo build, you need a source distribution of dojo. Unfortunately, dojo source distributions are not released to the main maven repository. There are two options:

  1. Download the source distribution from the dojo download page using the wagon-maven-plugin. However, this plugin downloads the dojo source distribution each time you preform a maven build. Not very efficient.
  2. Download the dojo source build and install it manually in your local repository, or a maven repository server hosted by your own organization. Obtaining the source distribution of dojo then boils down to adding a maven dependency for the source distribution (explained in Step 2).

We only describe the second option. As soon as dojo source releases are also deployed to the main maven repository, your maven build process will download the source release automatically, provided the group and artifact ID are the same as the ones used in this post.

The command we use to install a dojo source distribution in our local maven repository is (for version 1.3.1):

mvn install:install-file \
  -DgroupId=org.dojotoolkit \
  -DartifactId=dojo \
  -Dversion=1.3.1 \
  -Dpackaging=zip \
  -Dclassifier=sources \
  -Dfile=./dojo-release-1.3.1-src.zip \
  -DgeneratePom \
  -DcreateChecksum

To install the source distribution to a remote maven repository server, you must use the deploy plugin instead (mvn deploy:deploy-file).


2. Unpacking the source distribution

Before we can make a custom build, we must first unpack the dojo source distribution. Now that we have the source distribution in our maven repository server/local maven repository, this can be done easily with the maven-dependency-plugin. Adding the following piece of XML to the <build> section of your POM file unpacks the source distribution during the generate-sources phase of the maven build lifecycle. The dojo version you want to use and the location to which the sources are extracted are configurable with the dojo.version and the webresources.javascript.location parameter respectively.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>unpackDojo</id>
      <phase>generate-sources</phase>
      <goals>
        <goal>unpack</goal>
      </goals>
      <configuration>
        <artifactItems>
          <artifactItem>
            <groupId>org.dojotoolkit</groupId>
            <artifactId>dojo</artifactId>
            <classifier>sources</classifier>
            <version>${dojo.version}</version>
            <type>zip</type>
            <outputDirectory>
              ${webresources.javascript.location}
            </outputDirectory>
          </artifactItem>
        </artifactItems>
      </configuration>
    </execution>
  </executions>
</plugin>

We also rename the directory name of the unpacked directory from the verbose “dojo-release-<version>-src” to the more convenient “dojo-<version>” (the name you want to give is configurable through the dojo.source.local.unpacked.location parameter):

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <id>move</id>
      <configuration>
        <tasks>
          <move 
            file="${webresources.javascript.location}/${dojo.source.basename}"
            tofile="${dojo.source.local.unpacked.location}" />
        </tasks>
      </configuration>
      <phase>process-sources</phase>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>
</plugin>


3. Running the dojo custom build script

Once the sources are unpacked, we run the custom build script by means of the exec-maven-plugin. The plugin runs the build script in the Rhino JavaScript interpreter, which is included in the dojo source distribution. Again, some POM parameters can be configured to guide the build process. The POM parameters can be mapped directly to the parameters that can be passed to the dojo custom build script.

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
 
  <configuration>
    <executable>${java.home}/bin/java</executable>
    <workingDirectory>
      ${dojo.source.local.unpacked.location}/util/buildscripts
    </workingDirectory>
    <arguments>
      <argument>-classpath</argument>
      <argument>../shrinksafe/js.jar:../shrinksafe/shrinksafe.jar</argument>
      <argument>org.mozilla.javascript.tools.shell.Main</argument>
      <argument>build.js</argument>
      <argument>profileFile=${dojo.build.profileFile}</argument>
      <argument>action=${dojo.build.action}</argument>
      <argument>version=${dojo.build.version}</argument>
      <argument>releaseName=${dojo.build.release.name}</argument>
      <!-- releaseDir: don't forget the slash at the end! -->
      <argument>releaseDir=${dojo.build.release.location}/</argument>
      <argument>optimize=shrinksafe</argument>
      <argument>layerOptimize=shrinksafe</argument>
      <argument>internStrings=true</argument>
    </arguments>
  </configuration>
 
  <executions>
    <execution>
      <id>dojo-custom-build</id>
      <phase>compile</phase>
      <goals>
        <goal>exec</goal>
      </goals>
    </execution>
  </executions>
</plugin>


4. Building the WAR

After creating the custom dojo build, it must now be added to you web application’s WAR. This must be done by configuring the maven-war-plugin. The files created by the custom build must be added as additional web resources. The following POM excerpt adds additional web resources that are located in a directory defined by the webresources.location parameter. We put all generated web resources in that directory, which includes the files that are generated by the custom build process. Note that the unpacked dojo source distribution, which is in fact also a generated resource, is excluded from the war.

<build>
  ...
  <plugins>
    ...
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-war-plugin</artifactId>
      <version>2.1-beta-1</version>
      <configuration>
        <webResources>
          <resource>
            <!-- this is relative to the pom.xml directory -->
            <directory>${webresources.location}</directory>
            <excludes>
              <exclude>**/${dojo.source.friendlyname}/**</exclude>
            </excludes>
          </resource>
        </webResources>
      </configuration>
    </plugin>
     ...
  </plugins>
  ...
</build>


5. Generating eclipse project files

If you configure your POM file as described above, you can generate WTP compliant eclipse project files with the maven-eclipse-plugin.

mvn -Dwtpversion=2.0 -DdownloadSources=true -DdownloadJavadocs=true \
    eclipse:clean eclipse:eclipse

The maven-eclipse-plugin runs in the generate-resources phase of the maven lifecycle. The unpacking of the dojo source distribution is done in the generate-sources and process-sources phases of the maven build lifecycle, which both occur before the generate-resources phase (for more information, see the maven documentation on the build lifecycle.

Also, since version 2.6 of the maven-eclipse-plugin, all web resources that are defined in the maven-war-plugin section of your POM file are also added to the eclipse project. By consequence, the dojo source distribution you are using in your project is automatically deployed to the server that you’re using in your eclipse IDE for testing and debugging purposes.

Note that creating the custom build is done in the compile phase of the maven lifecycle, which occurs after the generate-resources phase. This means that the custom build won’t be available in your eclipse IDE unless you first compile the project using maven and refresh your project. The prerequisite for this to work is that the custom build must be placed somewhere inside the web resources directory that you have defined in the maven-war-plugin section.


POM Parameters

In this post we have made extensive use of POM parameters. This section enumerates and explains all the parameters we’ve mentioned in earlier sections

<properties>
  <!-- files and directory locations -->
  <webresources.location>
    ${project.build.directory}/WebResources
  </webresources.location>
  <webresources.javascript.location>
    ${webresources.location}/js
  </webresources.javascript.location>
  <dojo.version>1.3.1</dojo.version>
  <dojo.source.basename>dojo-release-${dojo.version}-src</dojo.source.basename>
  <dojo.source.friendlyname>dojo-${dojo.version}</dojo.source.friendlyname>
  <dojo.source.local.unpacked.location>
    ${webresources.javascript.location}/${dojo.source.friendlyname}
  </dojo.source.local.unpacked.location>
 
  <!-- dojo custom build parameters -->
  <dojo.build.profileFile>
     ${basedir}/facebookdemo.profile.js
  </dojo.build.profileFile>
  <dojo.build.action>clean,release</dojo.build.action>
  <dojo.build.version>${project.artifactId}-${project.version}</dojo.build.version>
  <dojo.build.release.name>dojo-release</dojo.build.release.name>
  <dojo.build.release.location>
    ${webresources.javascript.location}
  </dojo.build.release.location>
</properties>
  • webresources.location: the location where all generated webresources will be located. Since these resources are generated, they will end up in the target directory of your maven project
  • webresources.javascript.location: the location where all generated javascript resources can be found. This location is relative to the webresources.location; in this example in the js subdirectory.
  • dojo.version: the version of dojo you’re using in this maven project
  • dojo.source.basename: the name of the directory that is created when you unpack the dojo source distribution. This is typically “dojo-release-<dojo.version>-src”.
  • dojo.source.friendlyname: a less verbose name for the directory that holds the dojo source distribution. Here it is “dojo-<dojo.version>”
  • dojo.source.local.unpacked.location: this is the fully qualified location of the dojo source distribution in the maven project. This defines a directory with the name configure in dojo.source.friendlyname in the javascript webresources directory

The remainder of the parameters is used to parametrize the dojo build script. For more information on custom builds, please see the dojo documentation on custom builds.

  • dojo.build.profileFile: the location of the javascript file that contains the build profile
  • dojo.build.action: what actions must be performed in the dojo build process. This is typically “clean, release”
  • dojo.build.version: the version this dojo custom build will carry. We use a combination of the project’s artifact ID and version
  • dojo.build.release.name: How will the release be named. This corresponds with the name of the directory in which the custom build will be placed
  • dojo.build.release.location: the location where the custom build will be created. In this location a directory will be created with the name that you’ve configured in the dojo.build.release.name parameter.

There are obviously more parameters that you can pass to the build script, feel free to add your own.

Concluding remarks

It may require some tinkering before you get things working, or before things work the way you want. In the end, it’s a bit of juggling with files to get them all in the correct location. But once you’re there, you get dojo custom builds for free each time you do a maven build… provided you create a correct dojo build profile of course.

BeeWork’s WaveMaker review

June 23rd, 2009 Tom Comments off

Jurgen Lust, a colleague of mine, wrote a pretty to the point WaveMaker review.  We’ve been using WaveMaker at a client to design a 0.1 version of a project follow-up system.

A year ago, we tried to use WaveMaker to replace an ASP.net application.  An attempt that failed miserably because of the poor (not-normalized) database model, which we could not refactor for some reason I forgot.  One year and two versions of WaveMaker later, we tried again, mainly because we could start with a well-designed database model.  The experience was quite interesting:

  • Within a month we had a prototype of the project follow-up system that covered the entire workflow of the business problem it was trying to solve.  The database enforced data consistency, while the workflow was programmed in WaveMaker (using WaveMaker components and custom JavaScript code).  In that month we could show the application to the users, which could give feedback on a fully functional system.
  • In that month, the project was transferred to another software engineer; from me (who basically tested WaveMaker) to Jurgen, who redesigned the application’s workflow and fine tuned the interface.

That said, I feel obliged to add some notes to Jurgen’s post:

  • It is amazing how accessible WaveMaker is.  Jurgen picked up the WaveMaker way of working by watching some WaveMaker screencasts, half a day of hands-on pair-programming in WaveMaker and a quick introduction to using Firebug with WaveMaker.
    It must be noted that the learning curve is steeper if you have to find out everything by yourself and your JavaScript knowledge is close to non-existent.  On the up side, however, the WaveMaker documentation is quite good, and the forums on the WaveMaker website are pretty active.
  • Developing a WaveMaker application is mainly a single person effort.  Even without built-in subverion support it is not possible to import a WaveMaker project into Subversion using your favorite Subversion client. While you’re editing your WaveMaker project, directories may be deleted and created, which is something subversion does not like at all.  Maybe some other source control systems than subversion are more feasible?
  • Contrary to Jurgen, I like the the way WaveMaker mimics a desktop application.  Web 2.0 technology allows much more rich and intuitive user interfaces (e.g. drag-and-drop of components), which are easily deployable and distributable (see the cloud edition of WaveMaker) and enable extensible collaboration environments such as Bespin or Google wave.  Nonetheless, the remark concerning consistent user interface behavior is valid.