@URLEncode and the JavaScript equivalent!

JavaScript has many different encoding function with different approaches. Some of them does not encode all special characters.
escape() - does not encode: *@-_+./
encodeURI() - Does not encode: ,/?:@&=+$#

But encodeURIComponent() encodes all special characters! Link to W3SChool

@URLEncode(“ISO-8859-1;”,/?:@&=+$#”) will encode to the following string: “%2C%2F%3F%3A%40%26%3D%2B%24%23%22″
Which means that @URLEncode is similar to encodeURIComponent()!

But be warned @URLEncode/@URLDecode in standard uses “Domino” as decode type. “Domino” uses UTF-8 char set which will not work together with standard encoding on a  web page togehter with the JavaScript encode and decode functions . To work well with international characters use “ISO-8859-1″.

When it comes to encoding keep in mind that the decodeURI() function will skip decoding escaped characters which encodeURI() will not encode (at least in Firefox). @URLDecode and the JavaScript functions unescape() and decodeURIComponent() will decode all % escaped characters.

So decoding the string above will give the following result:

unescape() => ,/?:@&=+$#”
decodeURI() => %2C%2F%3F%3A%40%26%3D%2B%24%23″
decodeURIComponent() => ,/?:@&=+$#”

Conclusion:
@URLDecode will decode anything encoded with any of the JavaScript alternatives correctly.
@URLEncode will only be correctly encoded by the JavaScript functions unescape() and decodeURIComponent().

Am I a Domino Developer …

… or do you configure applications on the Domino server.

Sometimes when comparing Domino with more “glorious” products, for example SAP or Sharepoint. I have the feeling that most customer think you only have to configure them to work as you want.  Maybe I’m just configuring Domino to, or can it be that they are actually developing?

I like the word configure since it is a very good marketing trick! When comparing develop and configure most people would say configuring is much faster and cost less. It also give the impression it is a standard application you are using!

But comparing how long it takes to “configure” an application/functionality on those systems, I wounder if I’m really a developer?

So to annoy customers and my colleges, I have started to say I can configure such an application!

To get Domino to be more glorious. I believe IBM should do a search for the word develop and replace it with configure.

There is a flaw in my logic! It takes much longer to completely rebuild SAP for Domino then it takes to “configure” SAP to do what you want!

Linking Notes and Domino directories and application

A very powerful feature in linux is linking files and directories. Used in the right way it can save you a lot of space and keep thing often used or changed in one directory structure to be easily find.

All Administrators knows the feature in the Admin client where you can create links to directories and nsf files. For some developers it may be new! For some admins and developers it may also be new that it works really well within the notes client on the local machine.

You can easily create links to directories and nsf files which is then resolved by the notes client.

Personally I try to keep a folder structure on my PC where important stuff is located under one directory.
Doing a back of the machine is then much easier and the number of folders to consider in a backup set is greatly reduced.

So how does it work!

  1. Create a text file in the domino/notes data directory and name it eg.  BackupedData.txt.
  2. Open the text file in your preferred text editor and type in the path to the source directory eg. C:\Documents and Settings\Tomas\My Documents\DominoData.
  3. change the file type from .txt to .dir. (“BackupedData.dir”)

The linked folder will be shown as “BackupedData” when browsing for files in the Notes client.

This can also be done on single NSF files. Instead of naming it .dir change it to .nsf and the content in the file should contain the full path to the target nsf file.

Step by step guide linking nsf file:

  1. Create a text file in the domino/notes data directory and name it eg.  myApplication.txt.
  2. Open the text file in your prefered text editor and type in the path to the application eg. C:\Documents and Settings\Tomas\My Documents\DominoData\myApplication.nsf.
  3. change the file type from .txt to .nsf

The link files can be  put anywhere in the data directory structure!

NotesNames in LotusScript

Just wanted to show how easy creating names, authors, and readers fields can be in LotusScript?

As always there are different ways to accomplish that. Here’s two of them.

1) Use New NotesItem:
Set item = new NotesItem(“SendTo”, sendToArray,NAMES) ‘ For other type use the SpecialType parameter with AUTHORS or READERS instead of NAMES depending on what you want to create.

This is useful if you want to do something more with the field/item.
Eg. Change some properties.

2) Using ReplaceItemValue
set item = doc.replaceItemValue(“SendTo”,sendToArray)

This will only create a text field item. We need to change it to an Names item.
item.isNames = true

This can be shortened since ReplaceItemValue returns a notes item:
doc.replaceItemValue(“SendTo”,sendToArray) .isNames = True

If you want it to be readers field or authors field do this.

doc.replaceItemValue(“SendTo”,sendToArray) .isReaders = True

doc.replaceItemValue(“SendTo”,sendToArray) .isAuthors = True

Personally I tend to use the shortened version since I find it easier to read. That is if I do not need the NotesItem further down in the code.

It saves me a dummy variable which may not be using further down in the code.
I do not like to set variables which are never used.

It’s like in a movie where you get to see a shotgun in the beginning of the film. You then sort of expect it to be used before the end.

MacBook with wrong HDD size

Last week I went to the local Apple dealer to purchase a new Notebook for my stepfather. Since he recently retired he had to give back the company notebook.

To give him a new challenge my step sister and I decided he should try Mac.
Since he does a lot of presentation as wine connoisseur, good presentation software was one criteria and Keynote is the best I’ve seen. So I found it to be the perfect match.

We decided that the 2.4GhZ, 2Gb Ram, 250Gb HDD version of MacBook would be the best! Back lit keyboard is really good when presenting (Especially in dimmed rooms). And size optimal for transportation. So that was a perfect match to! Still the price is a bit high. So that is not a perfect match.

Back @ home we did some unboxing and I started to configure and install the necessary software. I was rally surprised as I wanted to resize the hard drive (needed a partition for Windows XP) and found it only to be 160GB. First I thought it may be an extra 90GB partition some where, but I could not find it.
Opening the battery lid, the HDD size of 160GB could easily be confirmed!

Today we brought it back to the Apple reseller and they confirmed it. They also did do some checking and Apple in Ireland apparently had never heard of some thing like this.

So my recommendation, to anyone with a new 2008 generation MacBook with 2.4GHz cpu, is to check that you did get a 250GB HDD (if you didn’t order a larger one). If you have something smaller then that, it is not what you have paid for! Minimum configuration is 250GB HDD.

I have personally decided to buy one, but since renovating two baths in our house, did get a little more expensive then calculated. A MacBook Pro more expensive to be precise! I have to wait until I can afford one form my self. But I will for sure check the size of my HDD

So now they have ordered a new hard drive! At least it easy to switch, since I have a Time Machine backup of the smaller drive.

NotesAgent.ServerName with consequences

NotesAgent.ServerName may not give you the server you expect!

In the properties for scheduling the agent, you can set on which server the agent shall run.

But from time to time you may want to trigger it manually.

If so, be careful when you use NotesAgent.ServerName, since it will give you the server name set in the agent property described above and not the server on which it was manually triggered.

To get the current server be sure to use NotesSession.CurrentDatabase.Server instead.

JavaScript in Domino – Unobtrusive JavaScript and mandatory fields

Finally I found a name for it. Chris Blatnick named it on his blog Interface Matters.

The technique was presented to me by Patrick Kwinten a while back. He as also blogged about it here.

Since then I find the technique really appealing since it in my opinion makes the coding in domino a lot cleaner. You can create a javascript library and put all the event management in there instead of having it in forms and subforms. Personally it goes along very well with my belief in separating style and content.

Here’s an example how to dynamically change the behavior on mandatory fields. In this case it uses css to show a red border around the field which is mandatory and is missing a value. I have not included the css here. But it is basic knowledge so it should not be hard to create one your self.

This example requires prototype.js

First a function is used to get a Hash of mandatory fields. In this case the mandatory fields are different depending of a previous selection in a field. The selections are “IBAN”, “US-ABA”, “SE-BG”…
There is a function for this so that the source of the information easily can be changed. Later its easy to implement a configuration document and fetch the information via ajax.

function getMandatoryFields(){

var mandatoryFields = {

"":{"mandatory":["Tx_BankName","Tx_BankID","Tx_AccountNumber
"IBAN":{"mandatory":["Tx_BankName","Tx_BankID","Tx_AccountNumber"]},
"US-ABA":{"mandatory":["Tx_BankName",
"Tx_BankID", "Tx_AccountNumber"]},

"SE-BG":{"mandatory":["Tx_AccountNumber"]},
"SE-PG":{"mandatory":["Tx_AccountNumber"]},
"SE-Clearing":{"mandatory":["Tx_BankName",
"Tx_BankID","Tx_AccountNumber"]},

"DE-BLZ":{"mandatory":["Tx_BankName", "Tx_BankID","Tx_AccountNumber"]},
"CANADA":{"mandatory":["Tx_BankName",
"Tx_BankID", "Tx_AccountNumber"]}};

return mandatoryFields;

}

Here’s the code:
Function refreshMandatoryBankInfo(accountType, mandatoryFields){

//Get the list of fields to the specific account type
mandatoryList = mandatoryFields[accountType].mandatory;

//This is not very modular for now.
var allFields = ["Tx_Recipient","Tx_BankName","Tx_BankID","Tx_AccountNumber"];

//Now we reset all fields. Removing onFocus and onBlur events and styles for mandatory fields
for (var i = 0; i < allFields.length; i++){

$(allFields[i]).setAttribute('onFocus','');
$(allFields[i]).setAttribute('onBlur','');
$(allFields[i]).removeClassName('mandatoryField');
$(allFields[i]).removeClassName('required');

};

//Go through all mandatory fields and assign an onFocus and onBlur event.
for (var i = 0; i < mandatoryList.length; i++){

Event.observe($(mandatoryList[i]), 'focus', mandatoryOnFocusEvent);
Event.observe($(mandatoryList[i]), 'blur', mandatoryOnBlurEvent);

//Set initial class for the field.
if (IsEmpty($(mandatoryList[i]))){

$(mandatoryList[i]).addClassName('mandatoryField');
$(mandatoryList[i]).addClassName('required');

}else{

$(mandatoryList[i]).removeClassName('mandatoryField');
$(mandatoryList[i]).removeClassName('required');

}

}

}

//Function to check if field is empty
function IsEmpty(aTextField) {

if ((aTextField.value.length==0) || (aTextField.value==null)){

return true;

}else {

return false;

}

}

//The onFocus function
function mandatoryOnFocusEvent(e){

//Find source element (field which event was triggered) read more about the technique here. The difference is due to different handling in ie and mozilla.
if (typeof e == undefined) {

var e = window.event;

}
var source;
if (typeof e.target != undefined) {

source = e.target;

} else if (typeof e.srcElement != undefined) {

source = e.srcElement;

} else {

//Since it is a target type we do not handle, exit function
return true;

}

//Set class for active field (You can define a special style to show in which field the cursor is placed).
source.addClassName('activeField');

}

function mandatoryOnBlurEvent(e){

if (typeof e == undefined) {

var e = window.event;

}
var source;
if (typeof e.target != undefined) {

source = e.target;

} else if (typeof e.srcElement != undefined) {

source = e.srcElement;

} else {

return true;

}

//Remove class for active field
source.removeClassName('activeField');

//Different handle for text and textarea and a select object
if (source.type =="text" || source.type =="textarea"){

if (IsEmpty(source)){

source.addClassName('mandatoryField')

} else{

source.removeClassName('mandatoryField')

}
source.value = Trim(source.value);

//Check if select statement is empty. Select-one is for on selection if you have a multiple selection object test for select-multiple. The test if it is empty may then have to be rewritten to work.
}else if (source.type =="select-one"){

if(source.options.text == ""){

source.addClassName('mandatoryField')

}else{

source.removeClassName('mandatoryField')

}

}

}

How the function is called:
refreshMandatoryBankInfo($F("Tx_AccountType"), getMandatoryFields());

Summory of the time between blogs

Have been very bussy trying to get old things done. Had a lot of old development project I wanted to finish.

In my free time I’ve been:
- working on two bathrooms. One at a time of course.
- Preparing our summer pool.
- Isolating our small summer lodge.
- Time with the kids.
- Garden work.
- Playing with Joomla.
- Guests, guests and another guest. I’ve been thinking off opening a Hotel.

Still it’s always nice having guests but it is not good if you want to get things done.

Most projects are now at an end. Bath close to be finished…
Now I’ll try to be more productive, logging what I have found.

Easy implementation of multiple configurable global stylesheets

The concept is to have a profile document with a multi value field containing the stylsheet path. First entry has the lowest priority the last the highest priority.

First create a profile document and a multi value field
In my example the profile form is named “(DbSetup)” and the field is named “globalCSS”.

In the Form you add the following code into to the “HTML Head Content” form object. Explanation follows.

startTagCSS := "<link rel=\"stylesheet\" type=\"text/css\" href=\"";
endTagCSS := "\">";
s := @Name([CN]; @ServerName);
@If( s= "" ; varGlobalCSS:="css/global.css";varGlobalCSS:=@GetProfileField("(DbSetup)"; "GlobalCSS") );
@Implode((startTagCSS) + varGlobalCSS + (endTagCSS);@NewLine) + @NewLine

First I define the start and end tags. I then try to find out if it runs local or on a server. If it is local it gets the css path from the local application it self, otherwise it gets it from the profile document. Needed that to be able to debug without network access.

Then, on each entry in the GlobalCSS field, the start and end tag is added in front and back of the path. By using @Implode and @NewLine each entry will be separated with a new line. Last but not least I add an extra new line after. To make it look more readable.

If the field GlobalCSS contains [http://myserver.com/css/global.css", http://myserver.com/css/second.css, http://myserver.com/css/third.css] we would get the following in the “<head>” tag on the web page.

<link rel="stylesheet" type="text/css" href="http://myserver.com/css/global.css">
<link rel="stylesheet" type="text/css" href="http://myserver.com/css/second.css">
<link rel="stylesheet" type="text/css" href="http://myserver.com/css/third.css">

This is only for absolute paths, since the relative path changes depending on if the document is new or already exists.
In this case each entry has to be tested for the existence of http or “//” in the beginning of the path and add “../” in the beginning if it is not a new document. Hint use @IsNewDoc in combination with @Transform.

Debootsrap ubuntu and locale problems

I’m trying to install a ubuntu gutsy xen guest. I’ve had some problem to get the locale to work.

Thereby installing it on lvm volume group with xfs as file system. Using debootstrap to get gutsy on it.
Since xfs is not installed with debootstrap you have to install the xfsprogs package to get it to work.

After installation i mounted it and chrooted the system to continue the configuration.

Executed “apt-get upgraded” to get the newest version of every thing.

Doing that I got this error message:
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LANG = "en_US.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory

So, I googled about it and found some statements telling you to execute the following command:
$ sudo dpkg-reconfigure locale

When you have installed Ubuntu by using debootstrap it will not work, since it to will fail with the same message. So to run the command you need to have at least one locale language generated.

The solution is to first generate one language by executing the following:

$ sudo locale-gen en_US.UTF-8

This will generate the necessary files for the first command.

It is also possible to generate all locale languages by just executing it without the en_US.UTF-8 parameter. That will take some time since all language combinations are generated.

No I’ll continue and pray I will start and that I do not get any tls warning message.