Wednesday, 4 June 2008

IBM Lotus Technical Conference Amsterdam finished

The IBM Lotus Technical Conference in Amsterdam has finished. And to be honest I was a bit disappointed by the number of participants at this event (maybe caused by that other event that started today, the ILUG 2008). Only about a hundred-twenty people turned up and at least a quarter were IBM staff, compare that to Lotusphere !!
That aside, most of the sessions were of the standard that can be expected by IBM, although some of them could have been a bit more technical to give the name of the conferene more credit.

Alan Lepofski kicked off the conference keynote and gave a very efficient and to the point presentation of what I call a summary of the Lotusphere Opening General Session in an hour. Good show.

And now I am back at work and I am working on a business case to setup some trail enviroments.

Monday, 26 May 2008

Lotusscript NotesDateTrouble

The other week marketing requested a function (agent) to send a follow up email x days (follow up days) after recieving a document (an order in this case).
Not a difficult function to build and NotesDateTime gives us the properties and methods to determine if a document is more than x days old.
So I build the agent that compares the created date of a received document to the date of today, both transferred to a NotesDateTime class. For the today value I used the "today" function. The agent will run once a day at appr. 14:00 hrs.

Sample of the code (simplified for ease of reading)
Dim dtToday As NotesDateTime
Dim dtCompare As NotesDateTime
Set dtToday = New NotesDateTime ( Today )
Set dtCompare = New NotesDateTime ( Now )
If dtCompare.LSLocalTime <= dtToday.LSLocalTime Then
...Print 'compare date is less-equal today, send follow up'
End If


All seems to works fine if you work with documents that are older than a day (x > 0), but when we wanted to test if it worked when x = 0, no follow up emails were send.
In the sample code above I replaced the created date by "Now" but the problem is in the "Today" function.
Only when inspecting the assigned values in the debugger, you can see why it doesnot work. The "Today" function doesnot set any time value in the NotesDateTime class (see the screenshot), but in the comparison it seems to assume a time of 00:00:00 (the start of the day) and thus the follow up is not send.

To solve the problem setting dtToday to "Now" is an option, but will only partially solve the problem as it will ignore documents received after the time set by "Now" until the next day.
So instead I decided to set dtToday to the end of the day by combining the "Today" function with a fixed time string of "23:59:59".
In the (simplified) code below you can see how it works.



Set dtToday = New NotesDateTime ( Today & " 23:59:59" )
Set dtCompare = New NotesDateTime ( Now )
If dtCompare.LSLocalTime <= dtToday.LSLocalTime Then
...Print 'compare date is less-equal today, send follow up'
End If


The message I want to give here is when using NotesDateTime comparisons, carefully look at the values displayed in the debugger to see if it works the way you think it should work.
Initially I did not do this and was puzzled as to why the comparison did not work until I started looking at the assigned values of the classes in the debugger.

Wednesday, 21 May 2008

CIAO! - end of june is here

Two weeks ago I posted a warning about a bug in TeamStudio CIAO! where all checkout comments would be lost when checking in a group of design elements.
In this post I mentioned that TeamStudio gave me an e.t.a. for the fix by the end of june.

But with the end of june still six weeks away, this monday I found an email in my inbox notifying me the bug has been fixed in edition 24a.
I have installed this edition yesterday and indeed the bug is fixed.

Good work TeamStudio, it is so much easier again checking in a group of design elements rather than one by one.

Thursday, 15 May 2008

I won (IBM Lotus Technical Conference in Amsterdam)

You probably know the feeling. Entering yet another raffle to win a nice price, but somehow the price always goes to someone else.
I had the same feeling when I entered a draw held by the SNUG (the Dutch user group for IBM software) for tickets to the IBM Lotus Technical Conference in Amsterdam, featuring Alan Lepofsky. I only had to answer three not too difficult questions which could be found on their website. Obviously I did not expect to win, but to my big suprise this morning I received an email from the SNUG to let me know I won (woehaa!!).
So on 2 and 3 june I will be in Amsterdam and maybe I will meet you there.

More details about the conference can be found at link to the conference above or via the image below.


Tuesday, 6 May 2008

Warning for TeamStudio CIAO! users !!

If you are using the TeamStudio Edition 24 CIAO! tool, please be aware of the following bug:
When checking in multiple design elements and ticking the "Use check out comment" option, the check out comments are "erased" and gone is your history.

As a workaround you will have to check in all checked-out design elements seperately !!

This bug has been reported to TeamStudio. However the fix is not expected to be ready until the end of june.

Monday, 5 May 2008

New functionality and look & feel for Lotus forums. Q: when IBM ?

Ever since I attended the BP203 session at Lotusphere, "A look under the hood of a world class IBM-Lotus web application", everytime I go to the Lotus forums I expect to see the new look and feel presented.
In this BP203 session Scott Good and Henry Newberry of Teamwork Solutions inc., showed what they had build on request of IBM to get the forum look & feel and most importantly the performance into the web 2.0 era. The solution Scott and Henry presented was stepping away from full roundtripping for every page to making the best use of AJAX and JSON in building the pages.
During the presentation Scott hinted to some legal issues with IBM that where blocking a roll-out, but by now I would have expected that to be solved.

I have no commercial attachment to either party, nor do I know what the status of the issues are.
But here is my plea: go ahead IBM and suprise me the next time I go to the forums to participate to see this new functionality.

Tuesday, 22 April 2008

The sustainable enterprise (what is your company doing?)

I do not want to make a habit of doing semi-advertising on this blog, but I could not resist and let the coincendence pass by unnoticed.
Today being the international Earth Day and yesterday InterfaceFLOR, the company I work for, announced receiving a prestigious royal award in the UK for sustainability.
Led by our sustainability pioneer Ray Anderson, InterfaceFLOR are striving to be a fully sustainable enterprise by the year 2020 and the enthousiasm of this initiative is carried out by employees from the factory floor up to the board. And given the raw materials we use in our products are all based on oil, not an easy goal. But a goal well worth pursuing if we want to pass on a live-able earth to our children and grandchildren.
More on the sustainable efforts of InterfaceFLOR can be found here and here.

Thursday, 17 April 2008

I am on Planet Lotus

Thanks to Yancy Lent, this blog now feeds into the Planet Lotus site. Now the task is mine to keep adding content here at a regular basis.
Although there is not much here yet it wil grow.
At the moment I think my focus when blogging will mainly be Lotus Notes / Domino development, but who knows, this may change in the future.

I really like how Planet Lotus works. I can follow almost all (and more) of the blogs I am interested in on one page. Not a day goes by without picking up an interesting topic. And as a result I now only have a few feeds left in my Google reader.

Wednesday, 16 April 2008

I tweeked the default layout (a bit)

When setting up this blog I chose the standard available Demin Stretch. But I did not like the used colours in the sidebar header.
So I decided to make some changes to that and make it more in line with the rest of the colours used in this template. So here it is, a nice blue border.

And while I was at it, I also added some borders to the post headings and I added an image in the header reflecting my all time favorite hobby, kayaking.

Monday, 14 April 2008

detecting language settings for a website using @formula

The company I work for is a multinational in Europe and their website, reflecting Europe, is multilingual. The main url for this website however directs to a general page for all of Europe and is in English. And you get it, soon the request came for the site to be able to detect where the visitor is coming from and redirect this visitor to his local language homepage if it is available.
After some discussion we decided to use the setting for browser language rather than using the some IP-detect to determine the preferred language of the visitor.
Initially I started using the @LanguagePreference, which given the name of the function would be the right one to use. And it did for a while, until we started rolling out the website to countries where more than one language is spoken. Like Belgium with french and dutch or Switzerland with german, french and italian.
In these countries we would like the visitors to be redirected to the homepages of that country in the preferred language of the user. And that is where @LanguagePreference starts to fail.
Lets take an example: A Belgian visitor would most likely set their preferred language to french or dutch (vlemish), respectively fr-be & nl-be in the browser.
But @LanguagePreference respectively returns "fr" and "nl". And thus we do not have enough information to route the visitor to the proper homepage and they are redirected to the french or dutch homepage.
As I do not know all the @functions by heart, I turned to our admin (Dennis), to see if this could be solved in our firewall. But instead of configuring the firewall he pointed me to the @GetHTTPHeader function and its HTTP_Accept_Language parameter.
As it turns out, this function nicely returns a string of the set languages as set in the browser. Although the browsers have their differences, the major ones are comparable when languages are defined for countries that have multiple languages.

So here is how it works:
When opening the default homepage, before processing the rest of the page, some @function code determines the visitors language and does a dblookup to see if a homepage exists in visitors browser defined language. If so, a meta refresh is set to re-direct the visitor to the local language homepage.

This is the code that is used:
(Underneath the second rem block a keyword is retrieved as the naming of the languages in the site is not always in line with what the browsers use and somtimes the browsers are not using the same language coding.)


REM {== get the languagesettings from the browser (retrieve the first setting in the list) ==};
brlang := @LowerCase(@Subset(@Explode(@GetHTTPHeader("Accept-Language"); ",");1));
brlang_2 := @Left(brlang; 2);

REM {== get the Languages Browser keyword for languages that differ between browser and site ==};
REM {== and replace if preflang is found in browserlangs ==};
lb := @LowerCase(@DbLookup("Notes" : "NoCache"; ""; "luKeywords"; "languages browser"; 2; [FailSilent]));
browserlangs := @Left(lb; "~~");
sitelangs := @Right(lb; "~~");
preflang:=
@If(
@IsMember(brlang; browserlangs);
@Subset(@Subset(sitelangs; @Member(brlang; browserlangs)); -1);
@IsMember(brlang_2; browserlangs);
@Subset(@Subset(sitelangs; @Member(brlang_2; browserlangs)); -1);
brlang_2
);

REM {== try to get indexpage for user browserlanguage ==};
key := "index_" + @UpperCase(preflang) + ".html";
page := @DbLookup("Notes":"NoCache";""; "webpages"; key; 1; [FailSilent]);

REM {== if path_info ends in /, remove it, so it compares better to dbPath ==};
pathinf :=
@If(
@Right(Path_Info; 1) = "/";
@Left(Path_Info; @Length(Path_Info)-1);
Path_Info
);
REM {== show default homepage when path in url is not blank or identical to dbpath or ==};
REM {== if language homepage for browserlanguage is not found ==};
REM {== else reroute to language homepage ==};
@If(
pathinf != "" & pathinf != dbPath;
"";
page = "";
"";
"<meta http-equiv=\"refresh\" content=\"0;url="+dbPath + "/webpages/" + page +" />"
)

Wednesday, 26 March 2008

I stand corrected, form formula and Dojo Dialog does work !

It seems I made a small mistake with big consequences. And the good news is that the form formula does work with dojo dialog.
While I was preparing the functionality mentioned in yesterdays post for go live, I discovered it did not work after cleaning up (deleting) all the trial code.

The mistake was, I called the wrong view in the "/viewname/docid?OpenDocument" for the dojo dialog. This mistake was caused by the application having 2 views with an almost similar name and the view I called did not have a form formula, which is why it rendered the Notes format of the form in the dojo dialog instead of the webformat.

Fortunately this mistake was quick to fix, by pointing the url to use the correct view.
So when reading yesterdays post, please ignore the text about the form formula not working.

Tuesday, 25 March 2008

Form formula with Dojo Dialog

It has been a while since Lotusphere, but today I put some functionality live that I had created after being stunned at Lotusphere by the session (BP212) that displayed some of the features in Dojo together with Notes/Domino. In fact Viktor Krantz had made a real effort in creating seperate javascript objects for Domino to show in his demos at BP212.

Putting this code live, reminded me that I wanted to write something about Dojo and the fact that for some reason the form formula is not working when opening a document using dojo dialog.

So returning from Lotusphere I started looking into Dojo and implemented the Dojo grid and Dojo dialog. As I wanted to have some handson with dojo, I did not re-use the Domino objects from BP212.
I made a grid working using the JSON setup Scott Good had shown in his ajax/json session (JMP205). This was actually the most work and required the most lines of javascript (mainly building the search url and the grid layout).

I then created a simple html form to open in a dojo dialog that will be triggered by clicking on a row on the dojo grid. All works fine, except the form specified in the form formula of the view that is used to retrieve the document does not seem to work. It uses the Notes version of the form instead of the specified web format.
I double checked twice and using the same "viewname/docid?OpenDocument" directly in the browser does open the specified web format as specified in the form formula.
Searching the web (LDD a.o.) did not give any clues into this problem having occurred before, nor did posting this problem on the LDD forum result in any answers.
So in the end I solved this problem by using computed subforms, one for the Notes client and one for the web
.

Has anyone else come accross this problem? Forget this, it does work, see the post on 26-03-2008.

For samples of code look at the Lotusphere session:
JMP205 AJAX and JSON for IBM Lotus Domino Applications (Scott Good)
BP212 The Great Code Giveaway: "Beyond Cool" (Rob Novak & Viktor Krantz)

Sunday, 9 March 2008

Moving values up and down in multiple multivalue fields

A while ago I received a request to be able to maintain a table of values. In Notes that means creating several multivalue fields that are displayed in a table.
I had done this before using the tablewalker solution by Michael Rohrbach and it still works fine after all these years.
However the current user was not really satisfied with the sorting option in the Tablewalker solution and wanted to be able to visually move rows up and down. This is basically moving values up and down in multivalue fields. So I started thinking about how to do this while the user is viewing the table on the form using @functions.
Based on an application I found on OpenNTF by Tomas Ekström, TEd, Table Editor I build a fairly simple solution for this using @functions.

This is the solution:
To start I created a computed multivalue field in which the fields to sort are stored, I called this field "MoveFields".

On the form there are a couple of (hidden) multivalue fields to hold the user data and computed for display fields to display the values of the hidden fields neatly in the table (cut-off if need be for each seperate value to fit on one line).
To move the values up and down in the array I added an extra field in which the user can enter the row to move "CurrPos".
Finally two arrows (up and down) are added with action hotspots, in which the sorting is done. The code should be self-explanatory.

Screenshot of the (part of) the table and buttons:











Code for the up hotspot:

REM {CODE FOR MOVING UP };
Fields := @GetField("MoveFields");

NoOfFields := @Elements(Fields);
NoOfElements := @Elements(@GetField(Fields[1]));

@If(CurrPos < 1 | CurrPos > NoOfElements;
@Return(@Prompt([Ok];"move up"; "Number must be within range of available rows"));
""
);
@If(CurrPos = 1;
@Return(@Prompt([Ok];"move up"; "Cannot move the first row further up !"));
""
);
REM { ----------------------------------------------------------------------------------------------------------
move the current row one position UP
1st subset gets the elements above the current element and the element to switch (only when current position is below second row)
2nd subset gets the current element
3rd subset gets the element above the current element
4th subset subset gets the elements below the current element (only when current position is above the last position)
-------------------------------------------------------------------------------------------------------------------- };
@For(n:=1; n <= NoOfFields; n:=n+1;
@SetField(Fields[n];
@If(CurrPos <= 2; null; @Subset(@GetField(Fields[n]); CurrPos-2)) :
@Subset(@Subset(@GetField(Fields[n]); CurrPos);-1) :
@Subset(@Subset(@GetField(Fields[n]); CurrPos-1); -1) :
@If(CurrPos = NoOfElements; null; @Subset(@GetField(Fields[n]); CurrPos-NoOfElements))
)
);
REM { set currunt position to new rownumber };
@SetField("CurrPos"; CurrPos -1);
@Command([ViewRefreshFields])


Code for the down hotspot

REM {CODE FOR MOVING DOWN };
Fields := @GetField("MoveFields");

NoOfFields := @Elements(Fields);
NoOfElements := @Elements(@GetField(Fields[1]));

@If(CurrPos < 1 | CurrPos > NoOfElements;
@Return(@Prompt([Ok];"move down"; "Row number must be within range of available rows"));
""
);
@If(CurrPos = NoOfElements;
@Return(@Prompt([Ok];"move down"; "Cannot move the last row further down !"));
""
);
REM { ------------------------------------------------------------------------------------------
move the current row one position DOWN
1st subset gets the elements above the current element and the element to switch (only when current position is below first row)
2nd subset gets the element below the current element
3rd subset gets the current element
4th subset subset gets the elements below the elements to switch (current element +1) (only when current position is at least 2 rows the last row)
----------------------------------------------------------------------------------------------------- };
@For(n:=1; n <= NoOfFields; n:=n+1;
@SetField(Fields[n];
@If(CurrPos = 1; null; @Subset(@GetField(Fields[n]); CurrPos-1)) :
@Subset(@Subset(@GetField(Fields[n]); CurrPos+1);-1) :
@Subset(@Subset(@GetField(Fields[n]); CurrPos); -1) :
@If(CurrPos = NoOfElements-1; null; @Subset(@GetField(Fields[n]); CurrPos+1-NoOfElements))
)
);
REM { set the current position to the new row };
@SetField("CurrPos"; CurrPos +1);
@Command([ViewRefreshFields])

Thursday, 6 March 2008

Another blog about Lotus Notes / Domino development

Indeed yet another weblog about Lotus Notes / Domino development. After roaming other blogs for answers and solutions I thought it would be time I started sharing my coding experiences on a world wide weblog.
Now, being a Notes / Domino developer it would seem appropriate to use a domino database for blogging. But as I found, hosting a domino site is rather expensive for a private person, I chose to start blogging through Google.
I do not have the idea that I can do a better job than some of the bloggers out there that have been around for several years now. But I consider this as much a personal diary as an attempt to share my experiences with a broader audience.

For now I have picked a readily available template, but I hope to create a more personal layout in the near future.