XPAGES DRAG AND DROP WITH DOJO TUTORIAL, PART 2: ISSUES AND BASIC DnD

This is part 2 of a series on drag and drop with Xpages and Dojo. Part 1 is here.

Issues implementing drag and drop in XPages

Resource referencing

The first issue with using Dojo.dnd in your XPage is with resource referencing. As discussed in detail in REFERENCING WEB SERVER FILE SYSTEM RESOURCES IN XPAGES, we’d like to take advantage of the existing Dojo.dnd CSS and image resources in Domino’s distribution, rather than embed our own. The CSS file that Dojo.dnd uses also contains references to default images used in displaying the dragging “avatar” (see previous post.) XPages, of course, has a mechanism for resource inclusion in the resources tab of an XPage’s properties browser, but there is no way to statically link to a relative resource in the filesystem. Any resource referenced in the resources section of an XPage that is not absolutely specified gets the database URI prepended to it, which is not what we want. To get around this limitation, we can dynamically compute the fully qualified URI of the resource file we want by using the built-in JSF facesContext object to query the underlying externalContextObject’s request object. What we need from the request object is the server’s name, port being used, and the protocol. Most cases can assume http as the protocol and port 80, but if you will not be sure of your application’s home, you may want to programmatically derive those as well. Here’s an example of a dynamically computed reference to the requisite Dojo.dnd CSS file:

  1. request = facesContext.getExternalContext().getRequest();
  2. server = request.getServerName();
  3. protocolFull = request.getProtocol(); //returns protocol/version (ex: HTTP/1.1)
  4. protocolOnly = protocolFull.split("/")[0]; //get just the protocol (lowercase it in next step...)
  5. port = (request.getServerPort().equals(80)) ? "" : ":" + request.getServerPort();
  6. protocolOnly.toLowerCase() + "://" + server + port + "/domjs/dojo-1.1.1/dojo/resources/dnd.css"

We begin by binding the HTTPServlet request object to the request variable. (Note that if you were running your XPages code as a portlet, the object returned would be a portletRequest, but the methods we call would be the same.) The getProtocol method returns a fully qualified protocol with a version number, so we’ll need to disregard the version number, which is what the split()method call on line 4 does. The port variable in line 5 queries the request’s port to see if it’s anything other than port 80, if it is we’ll need to append a colon and the port number to the server component of the URI before the file location component. If the port is the standard port 80, though, we don’t need to include anything, as port 80 is assumed if none is specified. If you are running this example from a local web preview process, you may have to adjust the relative portion of the URI accordingly.

Custom Dojo attributes

The second vexing problem in implementing Dojo.dnd is that the container object –whether it be a simple list or a table- needs a custom dojo attribute in its markup in order to be recognized as a Dojo.dnd container. This is where the purely declarative approach to implementing Dojo.dnd breaks down and we need to programmatically enhance our XPage DOM objects with Javascript. Fortunately, that’s not to difficult either and the logical extension of what we’ll need to do compared to the purely declarative approach in the example in Part 1 should be easy to understand. We’ll delve into the code for this technique in the example below.

Basic drag and drop in XPages

For the basic portion of the XPages Dojo.dnd tutorial, we’ll use a simple Notes database that contains “produce” documents. A produce document may either be a fruit or vegetable and has a name such as “Apple,” “Orange” and so on. You can download my example application here.

Rearranging an ordered list

Let’s start with a simple list. We’ll create a new XPage (called dnd_list in my example application) and drop a repeat control onto it. If you’re using my sample application, you’ll want to bind the repeat control to the “Produce” view which has two columns - “Name” and “Type”- and call the collection and collection index name “rowData” and “rowIndex” respectively. (Strictly speaking, we don’t need the index in this example.)

We’ll drop a computed field into the repeat control and set it to display the produce name and type with the dynamically computed value of rowData.getColumnValue("Name") + " (" + rowData.getColumnValue("Type") + ")."

Now we need to include Dojo directives in our XPage. Dojo conveniently works by loading the master Dojo file and then asking it to load any used modules in turn. For our example, we’ll be asking Dojo to load the dnd and parser modules (since we’re calling parser explicitly, rather than ordering Dojo to parse on load by setting the XPage’s “parseOnLoad” attribute to “true.”)  We accomplish this from the basics>>resources section of the All Properties tab of our XPage’s properties browser. Click the “add” plus sign and select “xp:dojoModule.” Expand the dojoModule[n] twistie, set the name to “dojo.dnd.Source” and repeat for “dojo.parser.

We’ll also need to include the aforementioned dojo CSS file by adding a stylesheet in the resources section, navigating to the stylesheet’s href property, clicking the diamond to select a computed value and pasting in the Javascript code from the resource referencing issue section of this tutorial.

One last thing we can do while still in the visual Design tab before we drop into the source code view is set the styleClass property of the computed field to “dojoDndHandle.” This is a server-side directive that will render on our web page as the style tag of the computed field control that is repeated inside the repeat control. This is the style tag that tells Dojo that the individual elements of the list are drag handles and can thus be clicked and dragged around. For our first example, the entire list item value is a drag handle, but in later examples, only the first cell of a table row will be marked as such.

Now we need to rearrange some items from the source editor so that the repeat values in the repeat controls are displayed as list items in an ordered list:

  1. <ol>
  2. <xp:repeat id="repeat1" rows="30" value="#{vProduce}" var="rowData"
  3. indexVar="rowIndex">
  4. <li class="dojoDndItem">
  5. <xp:text escape="true" id="computedField1" styleClass="dojoDndHandle">
  6. <xp:this.value><![CDATA[#{javascript:rowData.getColumnValue("Name") + " (" + rowData.getColumnValue("Type") + ")"}]]></xp:this.value>
  7. </xp:text>
  8. </li>
  9. </xp:repeat>
  10. </ol>

Click on the source tab in your XPage and move things around so that there’s an ordered list element (lines 1&10) wrapping the repeat control and there’s a list item element (lines 4&8) inside the repeat control wrapping the “xp:text” element. Notice that we’ve given the list item a class of “dojoDndItem.” This tells Dojo that each list item is a drag and drop participant. Notice also that the “styleClass="dojoDndHandle" attribute of the “xp:text” is present –we put this there earlier by specifying it in the styleClass property of the repeat control.

TIP: Use the Eclipse code formatting function to clean up your code in your XPage's source view. When in source view, Press Ctrl-Shift-F or right click in the source editor and choose Source>>Format

We’re now almost ready to deploy our drag and drop XPage. What’s missing is the logic that tells Dojo where the drag and drop source or container is. We’d love to specify this declaratively, but as the repeat control dynamically creates a DIV container for the repeated elements that will situate between the <ol> and <li> tags that we cannot declaratively style, we’ll need to programmatically set up the rest of the drag and drop functionality. To do this, we’ll need to know the id of the DIV we need to access in the DOM. By convention, Domino will ID the DIV it creates as view:_id1:repeat1. If this is not the first repeat control on your page, you’ll have to run the XPage in a web browser and look at the source code to determine the ID you need to reference. We use this ID to grab a handle to this DIV tag in Javascript and add the required Dojo objects to the DIV so it can function as our Dojo.dnd container.  To add the Javascript to our XPage, go to the “All Properties” tab of the Xpage properties box, scroll down to “resources,” click the “+” sign and add an xp:script element.


Then, specify the “clientSide” property of true, switch to the source view of the XPage and add the Javascript code between the <xp:script clientSide="true"></xp:script> tags:

  1. dojo.addOnLoad(function() {
  2. var wl = document.getElementById("view:_id1:repeat1");
  3. wl.setAttribute('dojoType','dojo.dnd.Source');
  4. wl.setAttribute('withHandles','true');
  5. dojo.parser.parse();
  6. });

We are adding an anonymous function to the dojo.addOnLoad() event. We can just as easily create a named function and call it from the dojo.addOnLoad() event as well, if that is your preference. First we get the aforementioned DIV element that will serve as the Dojo.dnd object container by referencing the view:_id1:repeat1 id (line 2.) Once we have a handle to the DOM object, we can add the properties to the object programmatically that we couldn’t declaratively due to the limitations of the XPages design environment. Line 3 is the equivalent of declaring dojoType=“dojo.dnd.Source” inside the DIV tag and line 4 is the equivalent of a withhandles=“true” custom attribute as well. Had we been able to declaratively add these elements at design time, we would not require the final line of the anonymous function (line 5) that calls the Dojo parser function to initalize all the Dojo objects on the page and enables the drag and drop functionality. The entire function is run when the dojo.onLoad event is triggered, which ensures that all the precursors to the functionality are in place before we try to activate it. (The Dojo equivalent of the body onLoad event.)

Run the XPage in your web browser and you’ll see a reasonable facsimile of the example in part 1 of this series. The only thing missing is some additional CSS style rules that enhance the drag and drop experience such as turning the cursor into a hand when hovering over a drag handle and highlighting drop locations when hovered over by a drag avatar. These CSS rules were embedded directly in the example in part 1 and need to be included as a database CSS resource for our purposes. The file, dnd.css, is included in the sample database for this lesson and can be embedded from the style tab of the XPage’s property browser by clicking on the “Add style sheet to page…” button and selecting it from the subsequent dialog box. Now the example is complete and all the building blocks for enabling drag and drop are in place.

As always, your comments, feeedback, suggestions and Scribnia author rating are appreciated!

Link to example application (zip file, on skydrive) for this tutorial.

NEXT: Implementing drag and drop in tables and views and advanced drag and drop.

SHAMELESS PLUG: Like what you see? Hire Me! Contact info@critical-masses.com or use the contact page to learn more about engaging Jake Ochs for your development needs.