Jul 292008
 

Today's tutorial: Dojo Tag Cloud Widget using dojo.data store

So I though it was time to post another Dojo widget tutorial. This time I have written a widget for displaying a tag cloud. Even though you could use it for any kind of links, the most common use is obviously tags from your blog or other website. The TagCloud widget is using dojo.data and any kind of store to display the tags. Let’s jump into some code shall we. In the bottom of this tutorial you will find links for downloading all the code.

First we need to add our core Dojo and dependencies to our JavaScript in the head of our HTML page.

[code=”xhtml”]
[/code]

You can see that we added the ItemFileReadStore, after that we have the topic of the tutorial: mydojo.TagCloud and last we added the dojo.parser so that we can create our widgets by HTML markup. You can see that the name space for my widget is mydojo.TagCloud. That means that I’ve created a folder named mydojo in the same folder as the dojo, dijit and dojox folders.
Now we add the dojo.data store and the markup HTML for our Tag Cloud widget inside our body.

[code=”xhtml”]

[/code]

You can see what it looks like in example 1.

The link above will give you the default TagCloud widget. If you look at the code, through Firebug naturally, you’ll see that it is made up of a DIV element with an unordered list, UL, inside. The list has all the tags from our dojo store with different sizes. Larger for tags with more values.

Most people want a tag cloud to look like a tag cloud though 😆 For that we need to add some style to our code inside the head tag.

[code=”css”]

[/code]

See example 2.

As you can see in the style classes above we declared a font and width inside a class named “TagCloud”. That class is always added to the div tag that the widget creates. That default class name can be changed and you can also add other classes that I will explain later. We also declared that any UL tag inside “TagCloud” will not have any margin or padding. That is because the browser automatically adds some margin and padding to unordered lists and we don’t want that for our tag cloud. Last in our style sheet we add the definition of our list item, LI. We want it to display inline and not be in a list format.

Lets add some more style to our tag cloud before I explain what attributes we can pass in to our widget. We add some more attributes to our existing classes and add two more rules.

[code=”css”]

[/code]

View it in example 3.

Tag Cloud Widget Attributes

There are a number of attributes we can pass in to change behavior and/or functionality of our widget. If we open up our widget JavaScript file we will see a number of variables at the top. You can actually change all of those by just adding attributes to our widget HTML code. They are documented inline in the code but lets look at a few of them.

[code=”javascript”]//sizeDifference: Boolean
//If we should show larger font for more tags
sizeDifference: true,

//fontMaxSize: Integer
//The size of the largest tag in percent
fontMaxSize: 200,

//fontMinSize: Integer
//The size of the smallest tag in percent
fontMinSize: 100,[/code]

So we can choose not to have a difference in size on the tags. How would we add that? Let’s look at the example below.

[code=”xhtml”]

[/code]

See what it looks like in example 4.

We have just added the sizeDifference attribute with a value of false to our widget code. Other then that it is the same code as example 3 above.

We can also choose to have bigger difference in size on tags. As you can see I’ve added the fontMaxSize attribute to our widget DIV tag.

[code=”xhtml”]

[/code]

Really large fonts in example 5.

I mentioned earlier that you can also add more style sheet classes besides the default class “TagCloud” to your widget. By adding the normal “class” attribute to our DIV tag. Classes will be appended after the “TagCloud” class. The default class can also be changed by changing the “baseClass” attribute.

What happens when the user clicks the tag? Well, since I don’t know what should happen because it depends entirely on what your tags represent and also on what kind of server the code sit on. In this blog, based on WordPress, the tag when clicked would take you to a url that look like:

[code=”javascript”]/index.php/tag/the_tag[/code]

So how do we do that? Well, one of the variables/attributes in our TagCloud widget is “clickFunction” with a default value of “tagItemClicked”. So you can add JavaScript funtion named “tagItemClicked” or pass in a new value to “clickFunction”. I’m going to show you the first way. Let’s add the following code to our JavaScript in the head of our HTML page.

[code=”javascript”]function tagItemClicked(sTag){
alert(“You clicked on ” + sTag);
}[/code]

See example 6.

If you click a tag it will alert the tag. Not very useful so let’s change it a little to make it work on my blog.
[code=”javascript”]function tagItemClicked(sTag){
location.href = ‘/index.php/tag/’ + sTag;
}[/code]

Updated to example 7.

Two other very important variables that we can change in our widget are the names of the item value names in our data.store. Default are “name”, “slug” and “count” and you can obviously keep those. Many times however you might not have the luxury over what your Ajax (XHR) call will return, or you just don’t like mine. 😥 In that case you can change them by adding the attributes “tagAttr”, “slugAttr” and “countAttr”.

Below is the JSON i’ve been calling with the ItemFileReadStore in all our examples so far.

[code=”javascript”]{items:[
{name:”ajax”, count:15},
{name:”beth”, count:2},
{name:”blog”, count:4},
{name:”calendar”, count:3},
{name:”calendar entries”, slug:”calendar-entries”, count:2},
{name:”Collaboration University”, slug:”collaboration-university”, count:14},
{name:”cu-2007″, count:11},
{name:”demo”, count:6},
{name:”dojo”, count:31},
{name:”domino”, count:20},
{name:”family”, count:9},
{name:”google”, count:2},
{name:”ibm”, count:5},
{name:”lotusphere”, count:11},
{name:”lotus quickr”, slug:”lotus-quickr”, count:27},
{name:”movies”, count:2},
{name:”podcast”, count:3},
{name:”snapps”, count:30},
{name:”templates”, count:17},
{name:”tutorial”, count:11},
{name:”widget”, count:4},
{name:”xhr”, count:3}
]}[/code]

As you can see it uses the default “name” and “count” attributes for each item. If however that would be changed to “word”, “special” and “number” everywhere…

[code=”javascript”]{items:[
{word:”ajax”, number:15},
{word:”beth”, number:2},
{word:”calendar entries”, special:”calendar-entries”, number:2},

{word:”xhr”, number:3}
]}[/code]

…we would change our HTML markup to:

[code=”xhtml”]

[/code]

What is the “slug” attribute you might ask. When a tag need a different call than it’s name you can add the slug attribute. If none is there it will just use the name attribute instead. In the example above the tag “calendar entries” has a slug of “calendar-entries” that way we can display one way but still link to the right URL.

Calling our widget with JavaScript

What if we wanted to do all this by JavaScript instead? Well Dojo widgets have this build in so all we have to do is code our HTML page a little different.

We can delete the reference to “dojo.parser” in our SCRIPT since we no longer are parsing HTML markup and we would add the following JavaScript.

[code=”javascript”]function createTagCloud() {
var oStore = new dojo.data.ItemFileReadStore({
url:”tagcloud.json”
});
var oCloudDiv = dojo.byId(‘tagCloudDiv’);
var oCloud = new mydojo.TagCloud({
store: oStore
},oCloudDiv);
}

dojo.addOnLoad(function(){
createTagCloud();
});[/code]

Then in our body we would add the following HTML.

[code=”xhtml”]

[/code]

JavaScript version example 8.

I hope you enjoyed this tutorial and I would love to read your comments. Here you can download the [download#1]. Happy coding.  🙄

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.

Jan 282008
 

At Lotusphere in my session BP212: The Great Code Giveaway: “Beyond Cool” I showed a couple of widgets and a Grid based on the Dojo Toolkit. I’m going to show you how I did those in a couple of articles the next few days. Instead of going through the code line for line I’m just going to highlight some of the changed variables and code. All the code for these examples and demos can be found here.

Extending Dojo code

One of the really powerful things you can do with a large toolkit like Dojo is that you can extend a widget/class instead of having to change the underlying code in the toolkit itself. Instead of having to write all the code for your class you just extend an existing class and change the functions/variables you need to. You can also add your own variables and functions. Extending Dojo code is really easy. You create your own JavaScript file and “require” the existing class/widget.

dojo.provide("my.new.Widget");
dojo.require("dijit.widgetToExtend");
dojo.declare("my.new.Widget", dijit.widgetToExtend, {
variablesToChange: "myNewValue",
functionToChange1: function(arg1){
//New code
},
functionToChange2: function(arg1, arg2){
//New code
}
}

In the example above we have extended a widget class called “dijit.widgetToExtend”. You would copy this JavaScript in a file named Widget.js inside a folder structure of “/my/new/” located parallel to the dijit, dojo and dojox folders. There are other places you can put your code but this is the simplest.

Using dojo.data

What is dojo.data?
Dojo.data is a uniform data access layer that removes the concepts of database drivers and unique data formats. All data is represented as an item or as an attribute of an item. With such a representation, data can be accessed in a standard fashion.

Ultimately, the goal of dojo.data is to provide a flexible set of APIs as interfaces that datastores can be written to conform to. Stores that conform to the standard interfaces should then be able to be used in a wide variety of applications, widgets, and so on interchangeably. In essence, the API hides the specific structure of the data, be it in JSON, XML, CSV, or some other data format, and provides one way to access items and attributes of items consistently.

The great thing about dojo.data stores are that they use a predefined way of getting/setting/updating code in the store. Whoever writes code for widgets that use stores does not have care about where the underlying data is located. It could come from a MySQL database, a XML file on the file system or now a Domino view.

domino.data.ViewStore

I’ve added three variables to this class. You see them below with their default value.

parseTypes: false,
dateFormatLength: "short",
handleAsJSON: true,

parseTypes: Parses all view data into it’s correct format. Numbers become floats, dates become locale dates. Locale dates are dates that show up in the format that the current browser language want to show them.
dateFormatLength: If parseType is true, then show the date in this “length”. Can be long, short, medium or full.
handleAsJSON: Default is that all data from the Domino view is returned with JSON using the “&OutputFormat=JSON”. If you set this to false all data is retrieved using XML instead. JSON was not implemented on the Domino server until version 7.0.2 so if you use a server prior to this you need to set this variable to false.

There are five functions I want to mention briefly.

_filterResponse: Used for parsing view data in JSON format to the required format for a store.
_filterXMLResponse: Used for parsing view data in XML format to the required format for a store.
_returnColumnValue: Helper function to get the value for a specific object. Used from _filterResponse.
_returnEntryValue: Helper function to get the value for a specific XML node. Used from _filterXMLResponse.
_returnDateTime: Helper function to format the Domino date string to a dojo.date.locale.

That’s it for this time. Next time we’ll look at domino.form.ComboBox and domino.form.FilteringSelect that both use the domino.data.ViewStore. Happy coding.

Jul 052007
 

Rob Novak’s and my session, BP311: The Great Code Giveaway – Web 2.0 Edition, at Lotusphere 2007 is added as one of the 14 (so far) podcasts that IBM put up on the DeveloperWorks website. The podcast is a recording of the session and a transcript of it is also available, even though they did spell my name wrong in there. Click here to listen or read. You can also go download the session materials and code.

Jun 292007
 

In today’s three part tutorial I’m first going to show you how to create a sign in form directly on a Domino page. Secondly, I’m going to show how you can embed a Domino form, with security, directly into a floating pane and submit it using Ajax. Last I’m showing you some code how to display a Domino view on the page using JSON and give you some of the code we at SNAPPS used for the Lotus Quickr templates we developed, free for you to download.

I have also created a short Flash preview of what I’m going to show today. It’s a good idea to view that first to get an idea of what I’m trying to explain.

Prerequisites

To get this to work there are a few things that are required and you need a basic to medium skill-set of how JavaScript works inside Domino.

The Domino server has to be version 7.0.2 or later. This is because we are getting JSON from the view and this was introduced on that version of the Domino server.

We need to have the Dojo Toolkit library downloaded to our Domino server. Unfortunately, Domino on Windows has a problem. The file name Shadow.js cannot be used. The file just does not show up through the web server. I have created a Dojo version where Shadow.js is renamed to Shadow2.js and everywhere it’s being referenced is changed. This is the version of Dojo that IBM is using inside Lotus Quickr 8. You can download it here: [download#5#nohits]. Remember to put the “dojo” folder inside the “html” directory on your Domino server. If you have a Lotus Quickr 8 server, you don’t have to do this step, but you need to modify the “src=” of the JavaScript to “/qphtml/html/dojo/dojo.js”.

We also must have session based authentication on our Domino server for the Sign In form to work. If you don’t you can still use the other code in this tutorial.

You need to download the database with all the code in it, [download#6#nohits]. You don’t want to type it all yourself do you?

Embedded Sign In FormSign In Form on a Domino Page or Form

What I’m doing here is a sign in form that we can put directly on a Domino Page or Form to let the user sign in without leaving the page to go to the Domino log-in form that redirects us back to where we came from. There is not much code to it. Let’s start.

We start by looking at the “HTML Head Content” of the “Dojo Forms Submission” Page.

"<script type="text/javascript" src="/dojo/dojo.js"></script>" + @NewLine +
"<script>" + @NewLine +
"var dbURL = '/" + @WebDbName + "';" + @NewLine +
"</script>" + @NewLine +
"<style>" + @NewLine +
"body, td {
color:#333333;
font-family:Helvetica,Geneva,Arial,Verdana,Sans-Serif;
font-size: 0.9em;
}" + @NewLine +
"</style>" + @NewLine

All we are doing here is calling the Dojo JavaScript file, adding a variable for the database URL and adding some style to our page. Next we look at the “JS Header”. Inside here we have 239 lines of JavaScript code. Don’t worry, we are only going to use 14 of them for this first part of the tutorial. The function we are using for the sign in is “directLogin()”.

function directLogin(){
var poststring = "username=" + dojo.byId("Username").value + "&password=" + dojo.byId("Password").value;
var kw = {
url: "/names.nsf?Login",
postContent: poststring,
load: function(t, txt, e) {
location.href = location.href;
},
error: function(t, e) {
alert(e.message);
}
};
dojo.io.bind(kw);
}

As you can see we are constructing a string variable “poststring”, by adding the values of the “Username” and the “Password” fields to it. We are setting the “url” to “names.nsf?Login” and the “postContent” to our “poststring” variable. The “load” is what what we want to do after the Domino server returns that it was successful. All I do here is reload the page. We don’t have to that, we are actually signed in, but for the Hide-When formulas to take effect we need to in this case. More on this later. Dojo takes care of the rest by calling the “dojo.io.bind” and passing in the “kw” object.

Let’s look at the HTML part of our Domino Page. At the top of the Domino Page I have added some text to show who you are signed as and what access level you have. In a normal application, you would obviously not have those there.

<fieldset id="loginFieldset" style="padding-left:5px; padding-right:5px; padding-bottom:5px; width:200px;">
<legend style="font-weight:bold;"> Sign In </legend>
Name<br />
<input name="Username" id="Username" value="" maxlength=256 style="width:100%;" /><br />
Password</br>
<input name="Password" id="Password" value="" type=password maxlength=256 style="width:100%;" /><br /><br />
<input type="button" value="Sign In" onclick="directLogin()" />
</fieldset>

We make the form pretty by adding the “fieldset” and “label” HTML tags. The important parts of the HTML code are the two fields and the button. There is nothing special with the fields other than they need to be there and the only thing I added the call to our function. I have also added a Domino Hide-When formula to this text.

@TextToNumber(@UserAccess(@DbName ; [AccessLevel])) > 2

All that the above @Formula does is hide the HTML if we have a user access greater than 2. Which is Reader access. This is the Anonymous access to the database. Default is Author. That’s it, not to hard was it?

Embed Domino forms and submit them using Ajax

Now lets embed a Domino form inside a floating pane on our page. This is not done by any IFrames or pop-up windows. This is the actual HTML code of the form in question embedded onto our page. We will also submit this form using Dojo’s Ajax way.

The form we are going to embed is called “Favorites”. It is a very basic form with three Text fields, a Checkbox field and a Readers field together with two buttons.

I also created a view called “Favorites View” that contains the documents using the form. More on that later in the next part of the tutorial.

First we add some HTML to our Domino Page so that we can open up the form in the floating pane.

<a href="<Computed Value>">Sign Out</a> | <a href="javascript:createNewDocument();">New Document</a>

The first link is the “Sign Out” link. It’s only there so that we can sign out. (It really belongs to the previous section.) The second link is our link to create a new “Favorite” document. As you can see it calls the function “createNewDocument()”. Let’s take a look at that code inside the “JS Header” on our Domino Page.

function createNewDocument(){
if(!dojo.byId("ff-newdocument")){
var oDiv = document.createElement("div");
oDiv.innerHTML = "Loading...";
document.body.appendChild(oDiv);

var floatingPaneAttr = {
position: "absolute",
top: "100px",
left: "100px",
width: "300px",
height: "255px"
};

for(var s in floatingPaneAttr){
oDiv.style[s] = floatingPaneAttr[s];
}

var floatingPaneArgs = {
widgetId: "ff-newdocument",
title: "New Document",
href: dbURL + "/Favorites?OpenForm",
displayCloseAction: true,
toggle: "fade",
windowState: "normal",
cacheContent: false,
refreshOnShow: true,
hasShadow: true,
executeScripts: true
};

g_FloatingPane = dojo.widget.createWidget("FloatingPane", floatingPaneArgs, oDiv);
}else{
dojo.widget.byId("ff-newdocument").show();
}
}

First we check that we don’t already have an object named “ff-newdocument”. If we don’t we create a new Div element and append it to the document body. Then we add some style attributes to the Div. Here you see an example of how to use JSON directly in your JavaScript code. Then we create the “floatingPaneArgs” object. This is again Dojo and we are using a Dojo widget called “FloatingPane”.

The interesting part of the object is the “href” value. As you can see we are using the “dbURL” variable that we declared in the “HTML Head Content” area of our Page. If you recall, it was using an @Formula; @WebDbName. We then add the name of our form and the ?OpenForm to the string. What the other name-value pairs are I’m not going to go over here.

The last thing we do is to create our FloatingPane widget. We also have to declare to Dojo that we are going to use the FloatingPane widget, so we add this code to the top of our JavaScript.

dojo.require("dojo.widget.FloatingPane");

That’s all there is to it. You can see an example of what it looks like when we open the pane to the right.

As you can see, I have also added a Set Reader Access check-box on the form. If checked, only authenticated users can see the document.

If you open the “Favorites” form and examine the two buttons you’ll see that they both contain JavaScript calls. The Cancel button calls “cancelFavoritesForm();” and the Submit button calls “submitFavoritesForm();”.

These two JavaScript functions do not exist on the Domino Form. They are both in the “JS Header” on our Page. Another proof that we are not doing this by an IFrame or a pop-up window. These two functions looks like this:

function cancelFavoritesForm(){
if(dojo.widget.byId("ff-newdocument")){
dojo.widget.byId("ff-newdocument").closeWindow();
}
}

function submitFavoritesForm(){
var formObject = document.forms["_Favorites"];
var kw = {
formNode: formObject,
load: function(t, txt, e) {
dojo.widget.byId("ff-newdocument").closeWindow();
//Reload view
getDocumentViewJSON();
},
error: function(t, e) {
alert(e.message);
}
};
dojo.io.bind(kw);
}

The first function, “cancelFavoritesForm” is not to exciting, it just closes our Floating Pane. The same result as if you click the X at the top of the Pane. The “submitFavoritesForm” is much more interesting. In Domino all forms you open from the web gets a form tag with the name of the form with an _ (underscore) before it. So we create an object “formObject” by calling document.forms[“_Favorites”]. Now the fun begins. In dojo.io.bind we can declare a “formNode” value with the form object as it’s value. Dojo recognize that you are passing in a form and submits it using Ajax in the background. You can even have WebQuerySave agents run on the form and it will work. Really super cool.

Just as in our Sign-In JavaScript function, the “load” event is where we declare what will happen after the server returns that it was successfully loaded. Here we call “closeWindow” to close the Pane. We also call a function “getDocumentViewJSON()”. That is for the last part of this tutorial. You can see an example of much more complex Domino Form embedded into a web page by clicking the image on the left. This is from one of the Lotus Quickr templates that we have created, QContacts. It has a WebQuerySave agent, multiple tabs, attachment control and much more. There is also a function called “openDocument” where we just open documents after they have been saved. It looks a lot like the “createNewDocument” function I described earlier. We call this function inside our JSON function. Let’s jump to that.

Displaying a Domino View with JSON

The last part of today’s tutorial is all about Domino views, getting JSON from them and displaying the items on our Domino Page. First on our Page, we add a empty table to the HTML.

<table border=0 cellpadding=0 cellspacing=0 width="500">
<thead id="documentHead"></thead>
<tbody id="documentBody"></tbody>
</table>

This is where the documents show up when the JavaScript call is done. We also need to add some more functions to the “JS Header”. Don’t worry, it looks worse then it is.

function getDocumentViewJSON(){
var sURL = dbURL + '/favoritesview?ReadViewEntries&Outputformat=JSON';
sURL += '&Start=' + g_NumOfStartDoc;
sURL += '&Count=' + g_NumOfDocs;
dojoGetJSON(sURL, 'printDocumentTable');
}

dojo.addOnLoad(function(){
g_DocumentHead = dojo.byId("documentHead");
g_DocumentBody = dojo.byId("documentBody");
getDocumentViewJSON();
});

The bottom JavaScript, “dojo.addOnLoad” is a really handy way of not calling anything until we are sure that everything on our page has loaded in the browser window. All we do here is to assign two global variables for the table header and the table body and call the function above, “getDocumentViewJSON()”. That is also the function we called from within our submit function in the previous section. In that function, we create a URL string that we pass to the “dojoGetJSON” function. We also pass in a string “printDocumentTable” to that function. That is the name of the function that we want to call when the server has passed back the JSON to the”dojoGetJSON” function. The two functions “dojoGetJSON” and “returnJSONValue” I’m not going to examine in this tutorial, it would be to long. All I can say is that “dojoGetJSON” get JSON back from a server and “returnJSONValue” returns specific column values from a Domino View. Examine them and try them out. We at SNAPPS use them daily in our code. Let’s look at the “printDocumentTable” function instead.

function printDocumentTable(oJSON){
try{
var oRow, oCell;
if(oJSON["@toplevelentries"] && oJSON["@toplevelentries"] > 0){
var viewentries = oJSON.viewentry;
var n_viewentries = viewentries.length;
var unidAttr, entrydata, sTitle;

//Delete all rows in the table
var iRows = g_DocumentBody.rows.length;
for (var i = 0; i < iRows; i++){
g_DocumentBody.deleteRow(0);
}

if(n_viewentries > 0 && g_DocumentHead.rows.length < 1){
oRow = g_DocumentHead.insertRow(-1);

oCell = oRow.insertCell(-1);
oCell.style.fontWeight = "bold";
oCell.innerHTML = "Name";

oCell = oRow.insertCell(-1);
oCell.style.fontWeight = "bold";
oCell.innerHTML = "Pet";

oCell = oRow.insertCell(-1);
oCell.style.fontWeight = "bold";
oCell.innerHTML = "Color";
}

for (var i = 0; i < n_viewentries; i++){
unidAttr = viewentries[i]["@unid"];
entrydata = viewentries[i].entrydata;

oRow = g_DocumentBody.insertRow(-1);
oCell = oRow.insertCell(-1);
sTitle = returnJSONValue(entrydata[0]).items[0];
oCell.innerHTML = '<a href="javascript:openDocument('' + unidAttr + '', '' + sTitle + '');">' + sTitle + '</a>';

oCell = oRow.insertCell(-1);
oCell.innerHTML = returnJSONValue(entrydata[1]).items[0];
oCell = oRow.insertCell(-1);
oCell.innerHTML = returnJSONValue(entrydata[2]).items[0];
}
}
}catch(e){}
}

All I’m doing here is to create rows and cells with values for every document I get back from the call to the view. It might look like a lot of code but it is mostly repeated steps from creating rows and cells and adding values to them.

I will explain a few things though. “unidAttr” is just the UNID of the document. “entrydata” in the for loop represent all the column values that a document have. Calling returnJSONValue(entrydata[0]) returns an object with column type and an items array, even if there was only one value in the column for that document. Remember that a column can have multiple values for each document, a field with multiple values for instance. The function also returns the type of column the items come from, so that we can know what to do with the items. If for instance the column contains date strings we can parse them in the correct format for the application using JavaScript.

That’s if for this tutorial. I hope you have found it useful and maybe even learned something. As always please submit comments on the code and how I can do it better. Until next time. UPDATE! I have corrected some spelling errors. Why can’t everybody just learn Swedish?

Jun 062007
 

There are many articles out there explaining what JSON is and where to use it, including a very good article written by Scott Good titled JSON and Domino.

What I’m going to try to explain in this tutorial is why associative arrays are our best friend when coding with JSON and Ajax. We have all seen how JSON is starting to dominate the Ajax calls. Face it, XML is so 2006. But let’s jump to the code shall we?

Normal Arrays

We made an Ajax call to our table, or view if we live in the Lotus Domino world, using our favorite way (mine is using the Dojo toolkit) and we now have an array of objects that we need to iterate through. Let’s see an example of what the array might look like.

var aArray = [
{unid: "111AAABBBCCCDDD111", first: "Rob", last: "Novak", phone: "(555) 111-1111", zipcode: "11111"},
{unid: "222AAABBBCCCDDD222", first: "Troy", last: "Reimer", phone: "(555) 222-2222", zipcode: "22222"},
{unid: "333AAABBBCCCDDD333", first: "Jerald", last: "Mahurin", phone: "(555) 333-3333", zipcode: "33333"}
];

If all we want to do is write the array out to the browser this is fine, we just use a normal for loop.

var sHTML = '<table border=1>';
for (var i = 0; i < aArray.length; i++){
sHTML += '<tr>';
sHTML += '<td>' + aArray[i].unid + '</td>';
sHTML += '<td>' + aArray[i].first + '</td>';
sHTML += '<td>' + aArray[i].last + '</td>';
sHTML += '<td>' + aArray[i].phone + '</td>';
sHTML += '<td>' + aArray[i].zipcode + '</td>';
sHTML += '</tr>';
}
sHTML += '</table>';
document.write(sHTML);

Output:

111AAABBBCCCDDD111 Rob Novak (555) 111-1111 11111
222AAABBBCCCDDD222 Troy Reimer (555) 222-2222 22222
333AAABBBCCCDDD333 Jerald Mahurin (555) 333-3333 33333

But what if we have a little bit more complex example. (Stay with me.) What if we had a way of updating user meta data from this document or form and later call code on the server to actually update the record or document in the back-end.

So we have created JavaScript that when a row is clicked, fields are populated with data from the array so the user can update them. The end user clicks a button and our array should be updated with the new meta data. We also want to add a property of “updated” with a value of true (boolean) if it is changed so that we later only pass in those documents that have changed to our back-end code (agent if Lotus Domino).

So in our scenario we have updated one of the records and call a function to update the array. With a normal array this would be done like this.

function updateUserMetaData(sUnid, sFirst, sLast, sPhone, sZip){
for (var i = 0; i < aArray.length; i++){
if(aArray[i].unid == sUnid){
aArray[i].first = sFirst;
aArray[i].last = sLast;
aArray[i].phone = sPhone;
aArray[i].zipcode = sZip;
aArray[i].updated = true;
break;
}
}
}

This works but if we have hundreds or thousands of records in the array it can take a long time. We have to iterate over all the values in our array to find the one with the right “unid”. Even though we are using a break statement when we have found our record it can still take a long time. Associative arrays to the rescue.

Associative Arrays

In JavaScript we have something called objects. They are a mapping from property names to values. Objects are an associative array with one caveat: since property names are strings, only string keys are allowed. That doesn’t matter to us.

We write an object literal as { property1: value1, property2: value2, ... }

Let’s rewrite our code to create an object instead of the array above.

var oObject = {
"111AAABBBCCCDDD111": {first: "Rob", last: "Novak", phone: "(555) 111-1111", zipcode: "11111"},
"222AAABBBCCCDDD222": {first: "Troy", last: "Reimer", phone: "(555) 222-2222", zipcode: "22222"},
"333AAABBBCCCDDD333": {first: "Jerald", last: "Mahurin", phone: "(555) 333-3333", zipcode: "33333"}
};

Can you see the difference? Not much difference in the text but a huge difference in what we can do.

First we can’t use a normal for loop to write our table any more. We need to use a for(in) loop.

var sHTML = '<table border=1>';
for (var unid in oObject){
sHTML += '<tr>';
sHTML += '<td>' + unid + '</td>';
sHTML += '<td>' + oObject[unid].first + '</td>';
sHTML += '<td>' + oObject[unid].last + '</td>';
sHTML += '<td>' + oObject[unid].phone + '</td>';
sHTML += '<td>' + oObject[unid].zipcode + '</td>';
sHTML += '</tr>';
}
sHTML += '</table>';
document.write(sHTML);

The output is exactly the same as above so we haven’t gained any value there. The big difference is in our function to update our meta data.

function updateUserMetaData(sUnid, sFirst, sLast, sPhone, sZip){
oObject[sUnid].first = sFirst;
oObject[sUnid].last = sLast;
oObject[sUnid].phone = sPhone;
oObject[sUnid].zipcode = sZip;
oObject[sUnid].updated = true;
}

As you can see we no longer need to iterate through an array to find our record. Since it is an object we can just update the property values directly.

Conclusion

In search for fast JavaScript code, associative arrays will help many times. It may seem a little difficult to code to begin with but after a while it actually makes much more sense. Object oriented programmers will find it easier.

Exactly one year ago from today, June 6th 2006, James Mc Parlane declared JavaScript Array and Object.prototype Awareness Day. Read that article. It will help you code better associative arrays (objects) in JavaScript.

Jun 042007
 

Several people have commented and emailed me wanting some sort of forum where I can post updates to code, examples and tutorials and where you can post your code variations, updates and ask questions to me and others.

So I have created eKrantz.com Forums where you can register and ask questions and write your comments about Dojo Calendar and Lotus Quickr code and tutorials. So go there now and register so we can get some good discussions going.

May 212007
 

Many of you have requested that I publish the sample database I used for the Faster Ajax with Domino and JSON speed test. I posted the article back in March and I should have done this a long time ago.

All documents/notes has been deleted from the Domino database to save some space and bandwidth on my server. If you want to run the tests yourself on your server you need Firebug so it can calculate the time it took for the XHR (XMLHttpRequest) to run. If you just want to check out the code, feel free to do so.

All code are in two Domino Pages: TestJSON and TestXML

  • Download [download#4#nohits] and put it on your server.
  • Open it up in Notes.
  • Create a few dummy documents by selecting Create/TestForm.
  • Copy & Paste the dummy documents many times so that you have a lot of them.
  • Browse to: your_server_and_directory/XML_JSON.nsf/TestXML?OpenPage for the XML version.
  • Browse to: your_server_and_directory/XML_JSON.nsf/TestJSON?OpenPage for the JSON version.

Enjoy

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.