Monday, May 24, 2010

XPage Error Handler

Since we do not have a lotus script debugger sort of facility in XPage, I often had difficulties in debugging server javascript code in Xpages.

Since Server Script allows lotusscript equivalent functions, Its kind of easy to debug them by creating a custom log database.

The following is How I use my log database. It is not an awesome tool. It simply helps you with print statement like feature.

var log=new Log(); //creates a log object
log.init(); //creates a log document
log.record("check point 1="+ message 1); // each of these lines

log.record("check point 1="+ message 2); // goes into consecutive lines in the
log.record("check point 1="+ message 3); // log document
log.close();  
 

you can use this with your custom functions as illustrated in the following statement,

function testMe()  {
 
var log=new Log(); //creates a log object
log.init("","myXpLog.nsf"); //creates a log document

 try {
  var x=session.getCommonUserName();
  log.record("check point 1="+ @UpperCase(x));

  var y=@UpperCase(x);
  log.record("check point 1="+ @ProperCase(x));the
  var z= @ProperCase(x)
 
 }  catch(error)  {
   log.record("Error: "+error.message);
 }  finally {
   log.close();
 }
}

Thus you will get to log the progress of your app.

The log class that I am speaking about is defined by me as follows,

Step 1 : Include this in your script library

function Log()    {
   
    var xpLogDB:NotesDatabase=null;
    var logDoc:NotesDocument=null;
   
    var logDetails="";
    var logExists=true;
   
    this.init=function (
serverName,databasePath)    {
        xpLogDB=session.getDatabase(serverName,databasePath)
        logDoc=xpLogDB.createDocument();
        logDoc.replaceItemValue("Form","log")
    }
   
    this.record=function(detail:String)    {
        logDetails+=detail+@NewLine();
    }
   
    this.close = function (){
        logDoc.replaceItemValue("log",logDetails)
        logDoc.save(true,false);
    }
   
    this.deleteLog=function (){
        logDoc.save(true,false);
        logDoc.remove(true);
        logExists=false;
    }
   
    this.logExists=function    ()    {
        return logExists;
    }
}


Step2:
 Create a notes database with a form named log with a field named log. Preview the database and you will be able to see any logs getting created

Have a technical question? , Post it here......

Wish to ask me a question....

Post it as a comment to this thread...

I will try and reply when time permits.. :)

Thursday, May 20, 2010

Creating Simple Dialog Box In XPage

The following is a procedure that will help you to create a simple Dojo Dialog Box in XPage

1. Create an XPage
2. Create a Panel and put some text inside it
3. In the All properties tab of the XPage, Mark the parameters, dojoTheme and dojoParseOnLoad as true (refer to the following figure)

4.Move to the source code panel and add the following code snippet

<xp:this.resources>
        <xp:dojoModule name="dijit.Dialog"></xp:dojoModule>
    </xp:this.resources>


5. Now add a button and in the onclick event of the button (client side)
put the following client side javascript

dijit.byId("myDialogContainer").show()

Now preview your XPage on the client or on the browser and click the button.
You will be able to see a nice dojo popup

The source code of the Xpage that I developed for this particular task is as follows,

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" dojoParseOnLoad="true"
    dojoTheme="true">

    <xp:this.resources>
        <xp:dojoModule name="dijit.Dialog"></xp:dojoModule>
    </xp:this.resources>
       
    <xp:button value="Dialog Popup" id="button2">
        <xp:eventHandler event="onclick" submit="false">
            <xp:this.script><![CDATA[dijit.byId("myDialogContainer").show()]]></xp:this.script>
        </xp:eventHandler>
    </xp:button>
   
    <div id="myDialogContainer" dojoType="dijit.Dialog"
        style="display:none">
        <xp:panel>Test Popup</xp:panel>
    </div>
       
</xp:view>

Pain Point: Using this method one can probably use these pop ups in places that does not require any server side operations. 'cos server side script does not work with any elements inside this popup.

To work with server side scripts in dojo popups in XPages refer to the following post:
Dojo Popup in Xpages - Working with Serverside Scripts - A simple illustration


Hope this helps :)

#8: Issue in XPage: Inconsistency across browser and client when attempting a new window popup in XPage

My goal was to dump a few html content into a new window and print the same.
I tried the following function on a button in an XPage

The following code goes in the onclick event of the button ,

writeConsole( 'Hello from JavaScript!' );
function writeConsole(content) {
  top.consoleRef=window.open( '' , 'myconsole' ,
  'width=350,height=250'
    + ',menubar=0'
    + ',toolbar=1'
    + ',status=0'
    + ',scrollbars=1'
    + ',resizable=1' )
 top.consoleRef.document.writeln(
  '<html><head><title>Console</title></head>'
    + '<body bgcolor=white onLoad="self.focus();self.print();">'
    +content
   + '</body></html>'
  )
 top.consoleRef.document.close()
}


When I preview the Xpage on the browser and click the button containing the posted code, I get to see the expected functionality. Where as when I see the same on the NotesClient 8.5.1, I see nothing happening -- Absolutely nothing.

I remember IBM telling people that XPages on 8.5.1 will work exactly in the same way, both on the Notes Client and on the browser...

Am I missing some thing.... If not this issue is definitely a bug in 8.5.1 XPages

My Ideas to work upon in XPages

1. Create Simple dojo popups
refer post - http://ozinisle.blogspot.com/2010/05/creating-simple-dialog-box-in-xpage.html

2. working with server side javascript in dojo popups

3. redirect to a dynamically created url in Lotus Notes Client 8.5.1

4. Add samples for all segments in http://www.ibm.com/developerworks/lotus/library/ls-Domino_URL_cheat_sheet/

Tuesday, May 11, 2010

Sending Mails With Rich Text Tables from XPages

I am amazed at the extent to which the lotus script libraries are mimicked in the Server Side Javascript libraries in XPages . The following is a simple illustration of a scenario that amazed me --- sending mails with rich text tables from an XPage.

Copy and paste the following code fragment into a XPage button control, preview the same on the Browser or Notes Client and you are ready to go.
Ensure that you give your own mail address so that you can check the functionality

/*******************************************************/

//change the mail address to test it for your self
var mailAddress="ozinisle.inferno@blogspot.com";

var currDB: NotesDatabase=session.getCurrentDatabase();
var mailDoc:NotesDocument=currDB.createDocument();
var bodyRt:NotesRichTextItem=mailDoc.createRichTextItem("Body");
var RTELEM_TYPE_TABLECELL =7;

mailDoc.replaceItemValue("Form","Memo");
mailDoc.replaceItemValue("SendTo",mailAddress);
mailDoc.replaceItemValue("Subject","XPage Mail");

bodyRt.appendTable(3,4);
bodyRt.update();

var bodyRtNav:NotesRichTextNavigator=bodyRt.createNavigator();
if (bodyRtNav.findFirstElement(RTELEM_TYPE_TABLECELL))    {
    bodyRt.beginInsert(bodyRtNav);
    bodyRt.appendText("hi this is my value");
    bodyRt.endInsert();
}    else {
    getComponent("errs").setValue('no table found');
}

try {
    if (bodyRtNav.findNextElement(RTELEM_TYPE_TABLECELL))    {
        bodyRt.beginInsert(bodyRtNav);
        bodyRt.appendText("hi this is my other value");
        bodyRt.endInsert();   
    }
}    catch (exp)    {
    getComponent("errs").setValue(getComponent("errs").getValue()+ @NewLine()+'no table found 2');
}

bodyRt.update();

mailDoc.send();



/*******************************************************/

Hope this helps :)

Saturday, May 8, 2010

What is 2.0-1.1? Any Idea

This is one funny behavior of the java compiler that I came across.
Create a class file with the following source code

import java.math.BigDecimal;

public class test {
    public static void main (String args[])    {
        System.out.println(2.0-1.1);
        System.out.println(new BigDecimal(2.0).subtract(new BigDecimal(1.1)));
        System.out.println(new BigDecimal("2.0").subtract(new BigDecimal("1.1")));
    }
}


compile the same and run it, and there you go, the funny results that I saw,

0.8999999999999999
0.899999999999999911182158029987476766109466552734375
0.9



I came across this in a session handled by Mr.Venkat Subramaniam in the Great Indian Developer Summit which was held on Banglore 20th to 28th April... (not so precise about the dates... :)

Using Java Methods In XPages

I know how useful Java is as a programming language. But how far can it be integrated with XPages. Yes I am speaking about the custom java classes that the user can create and use on XPages. Upon exploring for the same, I found a way to do it and I am amazed. I feel that I can do almost any thing with XPages now provided that java methods from my custom classes can be called directly into them.

The following is a sample flavor of what I am speaking about.

1. Create a new database or open an existing one in the domino designer 8.5.1

2. Click Windows -> Open Perspective -> Other, a pop up wold appear. Choose Java.


3. Now on the left margin you will be able to see the Package Explorer. Expand the entry corresponding to the database that you just created or opened (in step 1)

4. Navigate to the WebContent folder and expand it

5. Right Click on the WEB-INF folder under the above mentioned entry and Click New-> Package

6. Name the new package as myJavaMethods



7. Now create a class under the package by the name ProcessXPageCall and put the following code in it.

package myJavaMethods;

public class ProcessXPageCall {
    public String processInput(String inputToProcess)    {
        inputToProcess="My Processed " + inputToProcess;
        return inputToProcess;
    }
}


8. Save the class file.Now on the left hand margin right click your database's root node and select Properties

9. Select Java Build Path. On the Source Tab Click the Add Folder button.

10.Navigate to WebContent\WEB-INF\myJavaMethods folder, select the same and click OK



11. Now click Windows->Open Perspective -> Other and select Domino Designer


12. Create a new XPage, put a text field in it and compute its default value with the following code,

var xpCall=new myJavaMethods.ProcessXPageCall();
xpCall.processInput('inputString'); 



You will see the following results on the screen.



Hope you enjoy using Java in XPages

Thursday, May 6, 2010

Hiding tabs in Tabbed Panels - XPages

There was once a requirement where I had to hide and display tabs in XPages as and when the scenario required it.

It took me some time though to find the solution. Though this post may feel simple and straight forward, it discuss about a little trick that you will experience as you follow.

Create an XPage, put two edit boxes named tab1Flag and tab2Flag and give them a default values of 1 and 0 respectively.

In the next line put two buttons.Name them Toggle tab 1 and Toogle tab 2.

Code these buttons such a way that these buttons enable the fields to toogle between values 0 and 1.

Code on Toggle tab 1 button would be some thing like,

var dispVal=getComponent('tab1Flag').getValue();
(dispVal=='1')? getComponent('tab1Flag').setValue('0') : getComponent('tab1Flag').setValue('1')


Replace all 1s by 2s (except for the 3rd line) for the second button

Now drag and drop a tabbeb panel control into the XPage on a new line.

Select the newly created tabbed control, and go to the outline view and select the individual tab properties as illustrated by the following figure.



Select the small diamond near the Visible check box and key in the following code into it.

flagComp=getComponent('tab1Flag').getValue();
(flagComp == '1')? true : false ;


Similarly mark the second tab's visiblity property with the following code,

flagComp=getComponent('tab2Flag').getValue();
(flagComp == '1')? true : false ;


In total the source code of your XPage must be similar to the following,

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

   
    <xp:br></xp:br>
    <xp:inputText id="tab1Flag" defaultValue="1"></xp:inputText>
    <xp:inputText id="tab2Flag" defaultValue="0"></xp:inputText>
    <xp:br></xp:br>
    <xp:br></xp:br>
    <xp:button value="Toggle tab 1" id="button1">
        <xp:eventHandler event="onclick" submit="true"
            refreshMode="complete">
            <xp:this.action><![CDATA[#{javascript:var dispVal=getComponent('tab1Flag').getValue();
(dispVal=='1')? getComponent('tab1Flag').setValue('0') : getComponent('tab1Flag').setValue('1')}]]></xp:this.action>
        </xp:eventHandler></xp:button>
    <xp:button value="Toggle tab 2" id="button2">
        <xp:eventHandler event="onclick" submit="true"
            refreshMode="complete">
            <xp:this.action><![CDATA[#{javascript:var dispVal=getComponent('tab2Flag').getValue();
(dispVal=='1')? getComponent('tab2Flag').setValue('0') : getComponent('tab2Flag').setValue('1')}]]></xp:this.action>
        </xp:eventHandler></xp:button>
   
    <xp:br></xp:br><xp:tabbedPanel id="tabbedPanel1">
        <xp:tabPanel label="New Tab" id="tabPanel1">tab 1<xp:this.rendered><![CDATA[#{javascript:flagComp=getComponent('tab1Flag').getValue();
(flagComp == '1')? true : false ;}]]></xp:this.rendered></xp:tabPanel>
        <xp:tabPanel label="New Tab2" id="tabPanel2">tab 2<xp:this.rendered><![CDATA[#{javascript:flagComp=getComponent('tab2Flag').getValue();
(flagComp=='1')? true : false ;}]]></xp:this.rendered></xp:tabPanel>
    </xp:tabbedPanel>
    </xp:view>


Now save and preview your XPage. Now you can toggle the tabs visually. That is either hide them or show them.

The trick here is "Atleast one of the tabs must be left visible" . i.e. you can toggle tab2 when tab1 is visible alone and viceversa. If this condition is not satisfied you are going to get your XPage to bombard a run time error.

I dont like this behavior of tabbed panels in XPages, honestly. I think this is an issue with the XPages. I surely know that there are always ways to work around issues and get the desired solutions but, I feel this is not an acceptable behavior of tabbed panels - I mean why should it give you a run time error for a mistake that you are not responsible for... It can simply go hidden instead of giving me a run time error ...

Wednesday, May 5, 2010

function to get design element names from a database

'**********************************************************************************
'@Author : Karthikeyan A
'@Purpose : To get the names of all the desing elements from a database
'@Type : Function
'@Name : getDesignNames
'@Param : targetDB - the database from which the design names needs to be assimilated
'@Return : variant - array of design names
'**********************************************************************************
Function getDesignNames(targetDB As NotesDatabase) As Variant
    'declare all variables and functions necessary for further manipulation
    Dim nc As NotesNoteCollection
    Dim designDoc As NotesDocument
    Dim noteID As String
    Dim designNames As String
    Dim designItr As Integer
    Dim designTitle As String
   
    'handle errors in case of abrupt termination
    On Error Goto errHandler
    'create a note collection of all the design elements in the database
    Set nc=targetDB.CreateNoteCollection(True)
    Call nc.BuildCollection()
    'get the first note id from the collection
    noteID=nc.GetFirstNoteId
    'set the handle of the design document associated with the above mentioned noteid
    Set designDoc=targetDB.GetDocumentByID(noteID)
    'loop through all the design documents and get their titles
    designItr=0
    While Not designDoc Is Nothing
        designItr=designItr+1
        'ensures that you are saved from an infinite loop
        If designItr>nc.Count Then Goto loopOut
        designTitle=designDoc.GetItemValue("$Title")(0)
        designNames=designNames+designTitle+"$#$"
        noteID=nc.GetNextNoteId(noteID)
        Set designDoc=targetDB.GetDocumentByID(noteID)           
    Wend
loopOut:
    designNames=Strleftback(designNames,"$#$")
    Msgbox designNames
    'explode the concatenated design element names and return the same
    getDesignNames=Split(designNames,"$#$")
   
    Exit Function
'prompt the errors that resulted in abrupt termination
errHandler:
    'to by pass invalid noteId error 
    If Err=4270 Then Goto loopOut
    Msgbox "Error: ***" & Error & "*** encountered on line *** " & Cstr(Erl) & " *** with error number *** " & Cstr(Err) & " ***"
    Exit Function
End Function