Jan 302008
 

This is the third posting going more in depth of the code I showed at my Lotusphere session BP212: The Great Code Giveaway: “Beyond Cool”. If you haven’t read the first and second article yet I recommend doing so. You find them by clicking the links. You can download the instructions, code and databases here.

What is a Grid

The Book of Dojo explains it well.

Grids are familiar in the client/server development world. Basically a grid is a kind of mini spreadsheet, commonly used to display details on master-detail forms. From HTML terms, a grid is a “super-table” with its own scrollable viewport.

The domino.view.grid that I showed in my session contains two classes. The domino.view.grid class that extends dojox.grid.Grid and the domino.view.model class that extends the dojox.grid.data.DojoData class. It also uses domino.data.ViewStore for doing the XMLHttpRequest (XHR). I wrote about the domino.data.ViewStore in the previous postings.

Instead of going through 630+ lines of code, I’m going to show how to add it to your pages or forms. First the easy one and we’ll gradually move to more complex examples.
All the examples I’m going to show require you to add a couple of lines of code to your page/form.

In the HTML Head Content you have to add a style sheet, tundraGrid.css, and the dojo.js JavaScript. The tundraGrid.css file contains all the classes needed for the Grid to display properly.

"<style type="text/css">" + @NewLine +
"@import "/dojo102/dojox/grid/_grid/tundraGrid.css";" + @NewLine +
"</style>" + @NewLine +
"<script type="text/javascript" src="/dojo102/dojo/dojo.js" djConfig="parseOnLoad: true, usePlainJson: true"></script>"

In the HTML Body Attributes we add a class of tundra.

"class="tundra""

In the JS Header we add the required JavaScript files for the domino.view.grid and the dojo.parser. This is done the very specific Dojo way. It looks like Java but is really JavaScript. Dojo does this really smart by checking if the external JS file is already loaded and available to the browser. If it is not it gets/loads it.

dojo.require("domino.view.grid");
dojo.require("dojo.parser");

All those have to be added in all my examples here. In some of the examples in the download I have added more CSS classes and more JavaScript. In the very basic example this is all we need.

Now let’s add the HTML code to our page/form.

<div dojoType="domino.view.grid" url="sessiongrid1" style="height:600px;"></div>

As you can see (click on thumbnail for larger view) this is a very basic example that just displays a 600 pixel high grid from a view called “sessiongrid1” in the same database as the page/form. If you would look at the “sessiongrid1” view you would see that these columns are in the same order and widths. If you have specified that a column is not Resizable than you can’t resize it in the Grid either.

In the next example we add an attribute of handleViewDesign=true. That will also read in font families, sizes, colors, style and justification of both column headers and bodies. It will also read in colors for Alternate rows in the view property. You also see in this example that when Display values as icons is selected on the column, it displays in the Grid. Both numbered and shared Resources work.

<div dojoType="domino.view.grid" url="sessiongrid2" handleViewDesign="true" style="height:600px;"></div>

Structure

A really neat feature of Dojo’s Grid is that you can have multi row headers. That gives us a way of displaying more data in less space, especially when we have columns with a lot of text. Again the Book of Dojo explains it for us.

In standard spreadsheet and table terminology, a cell is the basic unit of displayed data. A row is a horizontally aligned contiguous group of cells, and a column is a vertically aligned contiguous group of cells. (Wow, that makes a simple concept sound complex!)

In grid-land, there’s a distinction between rows and subrows. A subrow is what people normally think of as a row – it’s exactly one cell tall. In Grid, a row may be more than one subrow – but it is selectable as a unit.

A View is a group of contiguous logical rows with the same inner and outer “shape”… You specify this in JavaScript with an array of arrays. Each array element is an object literal. The most important property of the object is “name”, which names the column. The column name always appear as the top logical row of the grid, and unlike other rows, it doesn’t scroll up or down.

<div dojoType="domino.view.grid" url="sessiongrid3" structure="myStructure" style="height:600px;"></div>

As you can see we are using a view called “sessiongrid3”. You can find that view in the “Sessions.nsf” database in the download. In that view we have added a column with the SessionAbstract field. This field contains a lot of text and if we displayed it in the same way as the previous examples we would see only two/three documents and we would have to scroll the grid a lot. But as you can see we have added a new attribute to the div, structure="myStructure". That tells the domino.view.grid class NOT to read in the design of the view and creating the structure dynamically, but instead that we are supplying it to the grid. Below you see the code example from the page “Grid 4” inside “Sessions.nsf”.

var myViewDesign = {
cells: [
[
{
name:'Session ID',
field:"SessionID",
width:'68px',
sortAsc:true,
sortDesc:true
},
{
name:'Location',
field:"SessLocs",
width:'113px',
sortAsc:true,
sortDesc:true
},
{
name:'Begin',
field:"BeginTime",
width:"96px",
sortAsc:true,
sortDesc:true
},
{
name:'End',
field:"EndTime",
width:"96px",
sortAsc:true,
sortDesc:true
},
{
name:'Session Abstract',
field:"SessionAbstract",
width:'auto',
rowSpan: 2
}
],
[
{
name:'Title',
field:"TITLE",
colSpan: 2
},
{
name:'Speaker',
field:"Speaker",
sortAsc:true,
sortDesc:true,
formatter: withLineBreaks,
colSpan: 2
}
]
]
};
var myStructure = [ myViewDesign ];

Let’s take a look at this code. First we create an object called myViewDesign and in that object we have a property of cells which is an array containing two arrays. Each array represents it’s own row. The first array contains five column objects and the last array two column objects.

Let’s look at the first column object: Session ID. As you can see we have a few properties to this object. The first two are required. The name property is what we want it to say in the column header. The field property is the Programmatic Name of that column specified in the view column with Domino Designer. Width is the default width of the column when first displayed. sortAsc and sortDesc set to true is if we have selected that the column can be sorted ascending, descending or both.

If you look at the Session Abstract column object, you’ll see that we have a width of auto and that we added a property of rowSpan: 2. This column is going to span over 2 rows but also extend to the width of the grid.

The last two column objects are in their own array. As you can see both have a colSpan property with a value of 2. Just as you can do in a HTML table these two columns will span over two columns each, leaving only the Session Abstract column by itself. It however spans over two rows as mentioned earlier. The last thing we do is to create an array, myStructure (named so as to match the structure attribute on the div HTML tag representing the grid), and set it to our object myViewDesign. You can see the result to the right.

In this posting I have only scratched the surface of what you can do with Grids. If you download the demo databases you will see many more examples including how to open documents by clicking cells or rows. You also see examples of how to use several Grids in conjunction with each other, i.e. click on a user document in the first Grid and display his/hers sessions in the second.

If you read up on Dojo Grids on the Dojo Toolkit website you’ll see that there are many more things we can do with Grids. One is to update document data inline right there in the Grid. This doesn’t work in the domino.view.grid class yet but I’m working on it. We also need an Agent for that to work. This Grid class does not work with categorized views as of yet, but I’m working on that as well. Check back here on my blog for updates.

I hope you enjoyed this demo/tutorial and as always if you have any comments or questions please post them here.

Jan 292008
 

Today we explore two extended form widgets I used in my Lotusphere session BP212: The Great Code Giveaway: “Beyond Cool”. The first article in this series can be found here. You can download the instructions, code and databases here.

domino.form.ComboBox & domino.form.FilteringSelect

These widgets are extended from dijit.form.ComboBox and dijit.form.FilteringSelect to accommodate for the URL syntax that a Domino view requires when doing a view search. They are modern and Ajax based. You can open both by clicking the down arrow but you can also type in the field to narrow down the choices. The important part of these widgets is in the _startSearch function.

if(key != ""){
var sLetters = "abcdefghijklmnopqrstuvwxyz**";
var lastChar = key.substring(key.length-1,key.length);
var sUntilKey = "";
if(isNaN(lastChar)){
var iCharNum = sLetters.indexOf(lastChar);
sUntilKey = key.substring(0,key.length-1) + sLetters.substring(iCharNum+1,iCharNum+2);
}else{
sUntilKey = key.substring(0,key.length-1) + (parseInt(lastChar)+1);
}
query["StartKey"] = key;
query["UntilKey"] = sUntilKey;
}else{
query["StartKey"] = null;
query["UntilKey"] = null;
}

What we do here is creating the URL syntax for a Domino view search that requires the &StartKey= and &UntilKey= arguments to find the document(s) the user is searching for.

From Domino Designer 8 Help:

StartKey=string
Where string is a key to a document in sorted view. The view displays at that document. In cases where there is no match for the StartKey, the next document is returned. So, for example, if the StartKey is “A” and there are no documents that begin with “A”, StartKey returns the first document that begins with “B.”

UntilKey=string
UntilKey is only valid when used with StartKey. It allows you to display the range of view entries beginning with the document specified by StartKey until the document specified by UntilKey. For example, &StartKey=A&UntilKey=B would give you all the entries that start with A. Use the &Count keyword to further limit the number of entries returned within any given range.

How to add to them to your form

Both these widgets are very easy to add to your forms. Both require the domino.data.ViewStore discussed in the previous article so you start by adding that.

<div dojoType="domino.data.ViewStore" jsId="DominoStore" url="../sessions.nsf/sessionlookup"></div>

Here we add a div tag with dojoType of domino.data.ViewStore, we give it a jsId of DominoStore and the url is pointing to a database and view. In this case a database called sessions.nsf parallel to the current database and a view named sessionlookup.

We add a Notes field to our form and make it type Dialog list. In the HTML Attributes of the field we add the following:

"dojoType="domino.form.ComboBox" store="DominoStore" searchAttr="IDTitle" pageSize="10" autoComplete="false""

The store attribute is the same as the jsId attribute of our domino.data.ViewStore above. The pageSize attribute is the number of documents we get/show at a time and the autoComplete attribute is for making the top search value auto complete the field. Try if for yourself by setting it to true.

I left the searchAttr attribute for last because it need some explaining. As you know we are using a store to get the values for the field.

If we open up the view sessionlookup in the database sessions.nsf in Domino Designer we see that the view has two columns. If you look at the Programmatic Name for the first column you’ll see that it is IDTitle. This column is what we want values from so we set the searchAttr to IDTitle. The value saved by a domino.form.ComboBox is the same as what you see.

The difference between a domino.form.ComboBox field and a domino.form.FilteringSelect field is that the latter has an onChange attribute and that the value of the field is always the identifier of the store it is using. What is an identifier you ask? Well, all data stores has a unique identifier. In some cases that is just an incrementing number starting at zero, but in the domino.data.ViewStore I created I used the NoteID. Why not the UNID? Because a document can actually exist several times in the same view.

So in a domino.form.FilteringSelect field representing all speakers I have the following attributes.

"dojoType="domino.form.FilteringSelect" store="SpeakerStore" searchAttr="Name" pageSize="10" autoComplete="false" onChange="setMentor(arguments);""

You can see this field in the “Mentor Selection” form in the “Mentors.nsf” database. It is part of the download. We now need the setMentor function.

function setMentor(arguments){
var identityRequest = {
identity: arguments[0],
onItem: function(item){
var sEmail = SpeakerStore.getValue(item, "Email");
alert(sEmail);
},
onError: function(){
console.error("Fetch failed.");
}
};
SpeakerStore.fetchItemByIdentity(identityRequest);
}

A version of this function can be found in the “index” page inside the “Registration.nsf” database. In this function we first create an object, identityRequest, and set the property identity to the first value in the passed in arguments array by setting identity: arguments[0]. We also have an onItem property. This is the function we call when we have retrieved a value. onError is being called if an error occurs. In the bottom of the function we do the call to the store and pass in our identityRequest object. SpeakerStore.fetchItemByIdentity(identityRequest); In this case we only alert the email address of the user we selected but if you look at the same function in the “index” page mentioned above you’ll see that we call another function to go get the profile from greenhouse.lotus.com for that email.

If you want to dig deeper in all possible attributes that a ComboBox and a FilteringSelect can change see the dijit.form.ComboBox and the dijit.form.FilteringSelect JavaScript files. Remember that in Dojo the name space is done by the periods you see in the names above. So in the folder dijit you find a folder called form where you’ll find the files ComboBox.js and FilteringSelect.js.

I hope this tutorial together with my code examples will clarify these two widgets for you. If not please comment below and I will try to explain further.

May 072007
 

Today I’m starting a new series of blog entries about extending the upcoming Lotus Quickr. The series will cover some of the new features, from a developers point-of-view, that will be available for you. You will be able to test most of them on upcoming beta releases, if you’re part of the beta program.

The tutorial today will show you a way of creating modal floating windows that can have any HTML you want in it. Click the thumbnail to see a larger image of what it looks like. The code is developed on top of the Dojo Toolkit that is now distributed as part of Lotus Quickr.

It is a modal window because the end user can not do anything else on the page until he clicks either of the buttons in the floating window or the close button in the top right corner of the floating window. (This “window” does not prevent the user from clicking the browsers back or close buttons.) It really is not a floating window. It’s not a window at all. It is a div object that is set to be on top of everything else on the web page when it is shown. The good thing about this is that we don’t have to worry about pop-up blockers. Another thing that the modal floating window does is that it darkens everything else on the web page to really focus in on the contents of the floating window. On to the tutorial.

First we create a new HTML page in our favorite editor. My new favorite is Eclipse Callisto with the Aptana plug in. Add a script tag inside the body tag. We have to add the script tag inside the body tag because Lotus Quickr will strip everything from our HTML code that is not within the body tag. So we have something like this:

<html>
<head>
</head>
<body>
<script type="text/javascript">
</script>
</body>
</html>

Time to add some functionality to our HTML code. First we add the reference to the ModalInput widget by adding the following code inside our script tag:

<script type="text/javascript">
dojo.require("dojowidgets.widget.ModalInput");
</script>

dojo.require is the Dojo way of referencing one of its JavaScript files. This happens to be a widget created by me and not by the Dojo developers but can still be called this way since it is referenced by its name space “dojowidgets”. Let’s not go in more on that. This tutorial would lose its focus very quickly, if I did that. If you want to read more about the Dojo Toolkit and how to create your own widgets please visit their website.

Next we want to add the button and the function that opens the floating window. Just before the end of the body tag we add:
<input name="mybutton" type="button" value="Open Modal" onclick="openMyModal()" />

Inside the script tag we add the function openMyModal:

function openMyModal(){
var sHTML = 'Your Name';
sHTML += '<br />';
sHTML += '<' + 'input type="text" id="modal_name" value="" style="width:95%;" />';
sHTML += '<br />';
sHTML += 'Your interests';
sHTML += '<br />';
sHTML += '<' + 'textarea rows="3" id="modal_interests" style="width:95%;"></textarea>';


var myModalParams = {
widgetId: "MyModalInput",
title: "My Custom Modal Form",
formText: sHTML,
submitFunction: "myModalSubmit"
};
var myModal = new dojowidgets.widget.ModalInput(myModalParams);
}

This function is what opens or show the “window” and whatever HTML we have chosen pass in. Let’s go over the function in more detail. The first part is where we declare a variable sHTML and add a string of the HTML that we want to show inside the floating window. As you can see we have a couple of labels, a text field and a text area field in the string representing the HTML. In the next part of the function we declare a variable myModalParams and add an object to it. This object represents the parameters that we pass into the floating window widget. More on these parameters in a moment. Last we call the ModalInput widget code and pass in our parameter object. We do this by setting a variable myModal.

Back to the parameter object that we created. As you can see we declared 4 properties to our object: widgetId, title, formText and submitFunction. These are not the only parameters that we can pass into the widget and all parameters, including these 4, are optional. Let’s go over them one by one.

  • widgetId:
    • Default: “modalInput” (string)
    • If you have more then one floating ModalInput on the page it is important to set their unique ID’s.
  • title:
    • Default: “” (string)
    • This is the title text in the window bar.
  • iconSrc:
    • Default: “information.gif” (string)
    • This is the image icon before the title in the window bar. Pass in the full URL to the image. The image should be 22×22 pixels.
  • formText:
    • Default: “” (string)
    • This is the HTML that you pass in to be displayed within the window.
  • width:
    • Default: “350px” (string)
    • The width of the window in pixels.
  • height:
    • Default: “250px” (string)
    • The height of the window in pixels.
  • resizable:
    • Default: false (boolean)
    • Should the window be re-sizable or not.
  • displayCloseAction:
    • Default: true (boolean)
    • Should we display a close button in the top right corner of the window.
  • submitFunction:
    • Default: “” (string)
    • The name of the function we should call when the Submit button is pressed. This function should return true or false if we should hide the window.
  • cancelFunction:
    • Default: “” (string)
    • The name of the function we should call if the Cancel button is clicked. This function should return true or false if we should hide the window. Use only if you need to have a Cancel function. I.E. you need to undo something when the user clicks Cancel.
  • submitValue:
    • Default: “Submit” (string)
    • The text inside the Submit button. Could be “OK” or “Yes”.
  • cancelValue:
    • “Cancel” (string)
    • The text inside the Cancel button. Could be “Close” or “No”.

Now we only need to add one more thing to our code to complete this tutorial, the function we call by clicking the “Submit” button inside our floating “window”. Inside our script tag we add:

function myModalSubmit(){
var sName = dojo.byId("modal_name").value;
var sInterests = dojo.byId("modal_interests").value;
if(sName == ""){
alert("FAILURE!nn" + sName + 'n' + sInterests);
return false;
}else{
alert("SUCCESS!nn" + sName + 'n' + sInterests);
}
return true;
}

We had added the value myModalSubmit to our submitFunction property above so we need to add a function with that name to our code. This function would in reality probably be much more complex than alerting “SUCCESS” or “FAILURE”. However in this basic demo that’s all we are doing. The function checks if you added a name in the field and alert result either way. If we did add a name it will close/hide our modal window by returning true, if not it will leave the window open by returning false. In the code you see that I’m using dojo.byId. That is just a more robust and shorter way of using document.getElementById.

Now all you have to do is to create a new “Imported Page” inside your Lotus Quickr place and select your HTML file as the file to import. Save and you will see the page with the button to click to open the modal floating window.

If you are lazy like me, and don’t want to create the file yourself, you can download the [download#3#nohits] zip file, unzip it and upload like above.

Now you can go and update the HTML to whatever you want and play with the widget parameters to suit your needs. In reality we would add this code to a custom HTML form and save our data down to regular or hidden fields on it. As an example I’ll show you a screen shot of the upcoming Lotus Quickr QMeeting template that we just finished.

If you have any comments about this tutorial, please submit them below. I will have a new tutorial for you as soon as I have another sleepless night.

Mar 012007
 

UPDATE: (Nov. 19, 2009) This widget only works for Dojo 0.4x.

At times I have had the urge to update the code and add extra features, but I just don’t have the time right now.

About this tutorial

After using Dojo for some time and looking for a calendar widget I gave up and started coding one myself. I had several goals with this widget: Using any back-end database for the entries, time zone changes, localized (internationalization i18n) and being able to drag entries to other dates.

This tutorial gives you all the code and files to get this calendar up and running on your server.

Continue reading »