Aug 142007
 

As many bloggers out there, including Rob Novak, Ed Brill and Mary Beth Raven, has posted; Lotus Notes & Domino 8 will be available this Friday.

Speaking of above bloggers, Collaboration University for Notes & Domino 8 still have seats available. This is the first technical conference on the new release. Other notible IBMers present at the event are Bob Balaban and Kevin Cavanaugh.

Hope you can join us.

UPDATE! I must be really tired. It’s not September but August 17 for the release date. I’ve changed the title of this post.

Aug 062007
 

The Collaboration University website has been updated for the September event. CU is the first major technical training event following the release of Lotus Notes and Domino 8.

We have lined up some incredible talent for both speakers and keynote addresses. Ed Brill will deliver the keynote in Kansas City on September 10 and Kevin Cavanaugh, Vice President of Lotus Notes and Domino Development on September 19 in London. Other speakers that we can announce are Mary Beth Raven, Ph.D. and Bob Balaban. All the speakers and sessions are now posted on the CU site.

We also welcome three partners this time around. SNAPPS, The Turtle Partnership and BE Systems.

Register Now for Kansas City (September 10-12) or London (September 19-21)

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.

Jul 032007
 

For the ninth demo, QContacts, we are getting into some eye candy and heavy Dojo work. I showed you a preview of it in my post Embedded Domino forms with Ajax submit and JSON view refresh a couple of days back. From Rob Novak’s blog:

Contacts? Why would you need that when you have a member list? Good question, easy answer. You need more information than the member record can supply, or the project contact isn’t a member of the place, or you need to share role-specific information about this contact with the team. There’s nothing more frustrating than having an out-of-date, incomplete, or low-confidence contact list. QContacts help to solve these problems, centralizing contact information while automating much of the work involved in maintaining it.

The use case is simple. You’re running a project using Lotus Quickr, and you want to maintain a contact list with more comprehensive information than is available in the member list (which is, in fact, mostly for authorization). You also don’t want to re-enter information from the member list, and it makes no sense to duplicate information available about a contact that may be a member of another place, or not a member of a place at all. QContacts consists of a single form for the Lotus Quickr place, and a Domino database to coordinate, automate, and consolidate contact data. It lets you add information about people that can be shared across places including all pertinent addressing information, personal contact information, a photo, and place-specific comments that are kept in context even if the contact is a member of multiple contact lists.

Take a look at the QContacts demo.

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.

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

Apr 272007
 

Rob Novak announced the keynote speakers for Collaboration University, and the list is very impressive.

Mike Rhodin
General Manager
Workplace, Portal and Collaboration Software
IBM Software Group

Mike will deliver the keynote address at Collaboration University on July 9 in Kansas City.

Ken Bisconti
Vice President, Lotus Software Products
IBM Software Group

Ken will deliver keynote addresses at Collaboration University in London on both July 18 and September 19.

Ed Brill
Business Unit Executive
Worldwide Lotus Notes/Domino Sales
IBM Software Group

Ed will deliver the keynote address at Collaboration University on September 10 in Kansas City.

These keynotes, together with some of the best experts assembled exclusively for each event will make Collaboration University 2007 your gateway to the most in-depth, advanced, highly focused, and complete coverage of IBM, Lotus Quickr, Lotus Sametime, and Lotus QuickPlace.

If you are like me and want to see stuff now, there is a new version of Sametime 7.5.1 and a new demo of Lotus Quickr.

Register today

Apr 122007
 

Ed Brill blogged today about the conference ratings from Lotusphere 2007. I’m really proud to say that Rob Novak’s and my session “BP311 — The Great Code Giveaway — Web 2.0 edition” was at the top of the list.

We here at SNAPPS put a lot of time and effort on our presentation material for the conferences that we speak at, and it’s fun to see that people appreciate it. If you haven’t already downloaded the pdf and the code samples from the session, go to SNAPPS download site and do it today. There are many other code samples there as well.

If you want to attend one of our sessions and see new code being developed as I write, head over to Collaboration University and sign up for one of the four events this summer and fall.

Apr 092007
 

Collaboration University just went live with their new website announcing new events this summer and fall. After much success with last years events in Kansas City and London, they are putting on 4 events this year. 2 events in Kansas City and 2 in London.

The events are:

Collaboration University™ for IBM Lotus Quickr™ and Lotus Sametime®

July 9-11: Kansas City, MO
July 18-20: London, England

Collaboration University™ for IBM Lotus Notes® and Domino® 8

September 10-12: Kansas City, MO
September 18-20: London, England

New Bonus for 2007

CU will this year, by requests from former CU Alumni, have optional 3rd day work-shops at all four events.

So new for Collaboration University 2007, we will be holding optional hands-on workshops on the final day of the conference. These 3-4 hour workshops will have you building systems, applications or learning more in-depth materials on a topic of your choice.

Head over to the CU website and register today for big Early Bird discounts.