TexasSwede
texasswede@gmail.com
  • About this blog
  • My Website
  • My Resume
  • XML Export Tool
  • Photos

Monthly Archives: May 2012

Regular Expressions in Notes (Lotusscript)

Posted on May 29, 2012 by Karl-Henry Martinsson Posted in Lotusscript, Old Blog Post Leave a comment

Today I needed to use regular expressions (a.k.a. regexp) in a Lotus Notes application. I just wanted to check if the user entered a claim number (in the format “nnXXXXXnnnnn”, e.g. 12RICTX12345) in a field. A quick online search found a blog entry with some code using the VBScript object available in Windows, and I adapted it for my application.
Just in case someone need this, I am posting the code below. I am not taking credit for the code, I found it on Giles Hinton´s blog and just adapted it a little bit.

I also found information about using LS2J and Java to handle regular expression in Notes, which should be platform independent, not restricted to just Windows. Since all our users are on Windows (either directly or through Citrix), I could use the quick method below. But I would probably use the script library posted on OpenNTF for more serious code.

 

Dim ws As New NotesUIWorkspace
Dim uidoc As NotesUIDocument
Dim regex As Variant
Dim pattern As String
Dim result As String
Dim match As Boolean

'*** Define pattern and get text value to check for match
pattern = |b([0-9]{2}[a-zA-Z]{5}[0-9]{5})b|
Set uidoc = ws.CurrentDocument
subject = uidoc.FieldGetText("ShortDescription")
'*** Create RegExp object
Set regex = CreateObject("VBScript.Regexp")
regex.Global = True
regex.IgnoreCase = True
regex.Pattern = pattern
'*** Test for match of pattern in text
match = regex.Test(subject)
If match = True Then
    Msgbox "Claim number was found in the field."
End If

Review: LEGO Lord of The Rings

Posted on May 27, 2012 by Karl-Henry Martinsson Posted in Featured, Hobbies, LEGO, Old Blog Post, Reviews Leave a comment

This weekend I spent with my son building some of the new LEGO kits from the new Lord of The Rings series. Here is a quick review of the kits we have built this far. You can click on the images for high-res versions of them.

 

9469 Gandalf Arrives – 83 pieces

GandalgArrives

A small but nice set. Contains Gandalf in his cart loaded with fireworks, as well as Frodo welcoming him.
Plenty of nice details, like the fireworks, a carrot for the pony and an envelope for Frodo to put the ring in.

 

9472 Attack on Weathertop – 430 pieces

Weathertop_Closed

This is a very nice set. It contains five minifigs: Aragorn, Frodo (with the ring), Merry and two Nazgûl (ringwraiths), as well as two horses. The three first minifigs have a feature I have not seen before, they have two sets of faces. By turning the head and exposing the part hidden by the hair, you get two different facial expression, like stern and aggressive or scared. The Frodo minifig in 9460 got the same feature, but not Gandalf as the back of his head is visible. All the minifigs are extremely detailed, it is obvious that the designers of the kits realized that collectors and adults will buy these kits.

Weathertop1_Details

 

The kit itself is of the ruins on top of Weathertop (Amon Sûl), and it features a trap door and a cooking fire. The ruins can be opened and in the inside you find weapons, toches and much more. Even a rat! There is also a stand-alone pieved of ruin with a bush and some plants.

WeatherTop_Open

The plants are the only thing I did not like with the kit. For some reason, perhaps the kind of softer plastic used, they don’t stick well to the bricks they are placed on. But that is a minor detail, otherwise this is a great kit.

 

9473 The Mines of Moria – 776 pieces

Moria2_Finished

This is a big set, the second largest in the series, and it depicts the events in the Chamber of Mazarbul. It contains six minifigs (Gimli, Legolas, Boromir, Pippin and two Moria orcs), as well as the cave troll. There are four separate sections, a large wall section, the doors to the chamber, the well with the skeleton and the chain and bucket, as well as Balins tomb, containing the skeleton of Balin. By pulling a lever, the skeleton, bucket and chain will fall down in the well, just like in the book and movie.

There are plenty of details, from old weapons to gems and even the Book of Mazarbul.

BalinsTomb_Details

 

9476 The Orc Forge – 363 pieces

OrcForge

This is currently my son’s favorite kit. It features a light brick, so when a rod is pushed, it looks like fire under the melting pot. In addition, there are four minifigs: Lurtz, two Mordor orcs and one Uruk-hai. To be really picky, Lurtz was created by Sauron, just like the Uruk-hai, so there should not have been any Morder orcs, but Isengard orcs. There is two sets of Uruk-hai armor (complete with the white hand of Sauroman), a crane to lift material to melt for the forge, etc.

OrcForge_Details1

OrcForge_Details2

 

 

So what is the verdict? As a Lord of the Rings fan (both the books and the movies by Peter Jackson), I am very happy with the LEGO kits this far. The quality is good, the instructions are very clear (recently I have seen some instructions where it was easy to miss a piece of pick the wrong shade of gray) and the detailing is amazing.
I still have two more kits to build that I already purchased, and I have to get the last kit (Battle of Helms Deep). I will report on them later.

 

35 years ago in a galaxy far, far away…

Posted on May 24, 2012 by Karl-Henry Martinsson Posted in Old Blog Post Leave a comment

May 25, 1977. Imagine it has been 35 years”…”

When the first movie (then called just "Star Wars", later renamed "Episode IV ?A New Hope") was released in Sweden, the age restriction was set to 11 years. With a parent you were allowed to see it even if you were younger. I was 8 years old, but my parents did not want to go see it.
It was not until "Episode VI ?The Return of The Jedi" was released in 1983 that I actually got to see the two first movies. They were shown back-to-back with a short break in-between, and a few days later the last movie premiered.

I had of course read the book that was released around the time the original Star Wars came out, so I was familiar with the story even before watching the movie. As a young boy, I really enjoyed the movies, and I still do. I recently watched "Episode I ?The Phantom Menace" in 3D.
I am however slightly irritated at George Lucas and how he keep changing the movies”…”

StarWarsMoviePoster1977

 

From Wikipedia:

Star Wars debuted on Wednesday, May 25, 1977, in 32 theaters, and eight more on Thursday and Friday. It immediately broke box-office records, effectively becoming one of the first blockbuster films, and Fox accelerated plans to broaden its release.
 
Star Wars remains one of the most financially successful films of all time. The film earned $1,554,475 through its opening weekend, eventually earning over $220 million during its initial theatrical run. Star Wars entered international release towards the end of the year, earning $410 million in total. Reissues in 1978, 1979, 1981 and 1982 brought its cumulative gross in Canada and the U.S. to $323 million, and extended its global earnings to $530 million.
 
Following the release of the Special Edition in 1997, Star Wars briefly reclaimed the North American record before losing it again the following year to Titanic. In total, the film has earned $775,398,007 worldwide (including $460,998,007 in North America alone). Adjusted for inflation, it has earned $2.5 billion worldwide at 2011 prices, making it the most successful franchise film of all-time; at the North American box-office it ranks second behind Gone with the Wind on the inflation-adjusted list.

 

Lord of The Rings LEGO

Posted on May 24, 2012 by Karl-Henry Martinsson Posted in Hobbies, LEGO, Old Blog Post Leave a comment

Today I got the final delivery of the new Lord of The Rings LEGO I purchased the other day.

The kits I got were:
The Mines of Moria
Gandalf Arrives
The Orc Forge
Attack on Weathertop
Uruk-hai Army
Shelob Attacks
The one I am still missing is The Battle of Helm’s Deep, but I plan to get it shortly.

I have a very excited 11 year old son who can’t wait to come over this weekend and build with me. :-)

Lord of The Rings LEGO

 

Lotusscript Code – HTML retrieval class

Posted on May 23, 2012 by Karl-Henry Martinsson Posted in Old Blog Post Leave a comment

I saw a question in the DeveloperWorks forum about retrieving a web page (in this particular case in order to get some data out of it), and realized that I never posted my HTML retrieval class…

So without further ado, here it is. It should be fairly self-documenting… Create a new object, then call the GetHTTP method with a URL to get a string representing the HTML code of that URL.  This is Windows only, by the way.

Class RemoteHTML
  Private httpObject As Variant
  Public httpStatus As Integer
 
  Public Sub New()
    Set httpObject = CreateObject("MSXML2.ServerXMLHTTP")
  End Sub

  Public Function GetHTTP(httpURL As String) As String
    Dim retries As Integer
    retries = 0 
    Do
      If retries>1 Then
        Sleep 1   ' After the two first calls, introduce a 1 second delay betwen each call
      End If
      retries = retries + 1
      Call httpObject.open("GET", httpURL, False)
      Call httpObject.send()
      httpStatus = httpObject.Status
      If retries >= 10 Then
        httpStatus = 0     ' Timeout
      End If
    Loop Until httpStatus = 200 Or httpStatus > 500 Or httpStatus = 404 Or httpStatus = 0
    If httpStatus = 200 Then
      GetHTTP = Left$(httpObject.responseText,16000)
    Else
      GetHTTP = ""
    End If
  End Function

End Class

How IBM could make my life a little easier

Posted on May 17, 2012 by Karl-Henry Martinsson Posted in Old Blog Post Leave a comment

Dear IBM,

I like that I now can use database icons with more than 16 fixed colors. I have updated pretty much all our applications (or is it called databases again?) with new and modern looking icons. The users likes it too.

However, with the old icon editor,it was easy to use the flood-fill tool to add a (in my case red) background to all templates. This made it very easy to differentiate between applications and templates. There is no option like that when I use the new database icons, I have to make a second icon in Photoshop and manually re-color it.

Why not add some kind of indicator to the application icon, to show that it is a template?  Below is my attempt to design something.  You see the red indicator that it is a template, you see the version number of the template and the server at the bottom is alwasy visible, as it is in a section of it's own.

Template Indicator in Lotus Notes Domino

As you see above, I use version numbers on my templates. Would it be too much to ask for a version number property and have the version number displayed on at least the template icon, like I have in my image above?
The version number should be transferred over to the application at design refresh time. The build number could be automatically updated when a "Recompile All Lotusscript" is performed, or automatically when any design element is modified and the build number has not been updated the same day already. A fully manual option shold also be available. How the build number gets updated should be an option in the settings for Domino Designer.

Of course, you need to create a way to access the version number programatically. Something like this:

 
 Dim version as NotesVersionNumberSet version = db.VersionNumberPrint version.Major ' Returns 1 Print version.Minor ' Returns 3 Print version.Revision ' Returns 0 Print version.Build ' Returns 1234 Print version.FullVersion ' Returns "1.3.0.1234" 

A formula function like @AppVersionNumber would be nice as well.

 

Thank you,

Your friend Karl-Henry

 

 

YUI3: Powerful Javascript Framework

Posted on May 15, 2012 by Karl-Henry Martinsson Posted in Frameworks, Old Blog Post, Web Development Leave a comment

Last week I came up with a small side project. It was basically a simple web chat, working pretty much like the comments on a blog. I decided to build this as a classic Domino application, not using Xpages. I started development Wednesday mid-afternoon, and the application needed be done Thursday evening, and I of course had my regular job to do. So I could not justify spending the time I needed to learn doing it in Xpages, and then try to write CSS to get it to look like I wanted it. So there you have the reason for why I did not use Xpages.

I decided to take a look at YUI, the framework developed by Yahoo. The latest version is version 3, and it is really nice and powerful. I looked into in, and realized that I could do things very quickly, getting the same functionality as using Xpages (partial refresh  or page, etc) in just a few lines of code.

So what did I need for my application? I started with a blank Notes database. I created a page, which is where all the action would take place. On the page I created a header section (logo), a content section (where the messages/chat would be displayed) and a form section where I put a few fields for the users to fill out. The fields were name/handle, email, (optional) website and lastly the message to send. I also put two images there, one to use as a submit button, and one to refresh the chat content without having to submit a text.

Bloggfika Webchat using YUI3

I added some javascript at the top of the page, loading YUI3 (hosted by Yahoo, I did not even have to download anything):

 
<script src="http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js"></script> 

The next step was to add some code for the actual logic on the page. YUI works by binding functions to events on elements on the page. I wanted to bind function functions to the onClick event of the two buttons, "submit" and "refresh". To avoid this blog entry to be too long, I will just show the code behind the refresh button:

 Y.one('#refresh').on('click', function(e) {        e.preventDefault();        var contentcell = Y.one("#contentCell");        if (contentcell) {            var currentTime = new Date();            Y.one('#refresh').set('src','webchat.nsf/ajax-loader-150.gif'); var args = &refresh=true&datetime=" + currentTime.getTime();            contentcell.load("webchat.nsf/SendText?OpenAgent" + args,"", function()  {                Y.one('#refresh').set('src','webchat.nsf/refresh.png');            } );        }    });

This code gets a reference to the first element with the id "refresh" using Y.one(), then bind a function to the "click" event. The function is defined right there, and it will do a couple of things. First it get a reference to the element (in this case a DIV) with the id  "contentCall". I check if it was found, and if so I get the current time (get a unique number). I then change the image of the refresh element to a spinning "loading" icon.

The next line is the coolest one. In one line of code I perform an Ajax call to an agent on the Domino server, and put the returned data into the contentcell element. Finally, after the server returns teh data, another function is called, which restored the refresh button to the original image.

The agent is written in Lotusscript, and it just read the existing chat entries from a database and output it using the print statement as HTML. I add the times in seconds as a second argument, just to get each call to be unique. Otherwise the returned data might be cached on the server and the user would not get the latest data.

The submit action is similar, the difference is that it read the values from the different fields on the form and submit them to the same agent as name-value pairs. The agent will detect that data is being passed to it, and will store the values in a new Notes document, then return HTML for all entries just like the refresh.

As you can see, a complete Ajax call (calling the server, waiting for data, gettingthe data back, replacing the content of an element on a page to perform a partial refresh and triggering additional code when the data has been returned) is just one line of code. Could not be much easier!

The actual application got more functionality, I check for certain required fields already in the web client, using javascript, I load up the content when the page is first opened (so the user does not have to press refresh to see anything), etc. The webchat is also just open specific times, when it is closed a message is displayed about when it will be open next, etc. The open/close is set by a Notes configuration document. Note: Do not use profile documents to store items for a web application, they get cached on the server and you will probably not get the latest data…

I am impressed with how easy and quick it was to build this application, using a compbiantion of classic Notes and a powerful javascript framework.

 

Notes/Domino future roadmap survey results

Posted on May 9, 2012 by Karl-Henry Martinsson Posted in Old Blog Post, Technology Leave a comment

Yesterday I created a simple survey to see what people wanted in a future version of Notes/Domino. It was based onEd Brill's post, where he summarized the result of the comments to his request for suggestions on what areas to focus future development of Notes/Domino.

I think the results speak for themselves. But with 74 survey takers, more than two in three want the client performance to be improved, and almost as many want the limitations (32K/64K) removed and teh Notes cleint UI modernized. Rewriting all templates using Xpages and match the templates delivered with Sharepoint was another popular feature, as well as better documenattion and a more stable Domino Designer.
I think the 52% who voted on improving Domino NSF performance mainly were thinking about faster indexing, and moving view index to separate drives, outside the NSF file itself.

The "other" answers were:
* Make Connections free
* Create an AppStore for Domino applications
* Make Deployment easier, as easy as outlook
* Solve the known bugs
* Enhance Linux support

 

Survey Results

Update: There are still responses coming in, I will update the result as more results come in.

 

Ed Brill: Notes/Domino future roadmap workshop

Posted on May 7, 2012 by Karl-Henry Martinsson Posted in Old Blog Post Leave a comment

The other day, Ed Brill invited comments on what IBM should focus on in regard to improvements for upcoming versions of Notes and Domino.
Today he posted a chart showing the result: image

I used that chart as a base for a simple survey using SurveyMonkey.
Feel free to fill it out. Let's see what that survey will show…

 

[Code] – Mail Merge/Form Letters in Lotuscript

Posted on May 4, 2012 by Karl-Henry Martinsson Posted in Old Blog Post Leave a comment

Back in 2003 or so, I wrote some code to take a form letter (stored in a Notes document) and merge that with data stored in another Notes document in order to create a personalized letter that could be printed or emailed. Back then we were still on Notes 5, so very limited rich text functionality and no budget to purchase Ben’s excellent Midas LSX. The end result worked, but any formatting in the form letter template was lost.

Eventually we upgraded to Notes 7 and later to Notes 8.5. Now I had much more rich text functionality to play with, so I rewrote the code as a class. I added some additional functionality, like formatting values using a mask, and some lookup functionality. The class support all kind of formatting in the form letter template, including fonts, colors, tables, graphics, etc.

This is what a typical form letter look like:

Form Letter Template

As you can see, the placeholders are using curly brackets to hold either a field name or a command. The commands are indicated by the percent sign (%). There can also be different arguments, for formatting, lookup into the NAB/Domino Directory, etc. I even have functionality to present a nice dialog box where the user can pick recipient from a list of everyone associated with the claim (as this is from a claim system used by an insurance company).

Here is a description of the syntax for the placeholders:

{fieldname}
Displays the content of the specified field from the selected source document. Additional (optional) formatting arguments can be used, for example to format values to desired format.
By using the argument LOSSNOTICE or SOURCE=”LOSSNOTICE” the value of the field is retrieved from the Loss Notice instead of the current source document, e.g. {adjuster LOSSNOTICE}.
Use the argument SELECTED to get the fields name, address, city, state, zip, email, SSN and DoB for the recipient selected in the separate dialog box.
{email SELECTED} will return the email address for the recipient selected, either producer, insured or one of the claimants.
The optional argument NABFIELD will retrieve the value of the specified field from the NAB for the user specified in the field (field must be spelled exactly as in the NAB design):
{Adjuster NABFIELD=”JobTitle”} will return the title of the person in the ‘Adjuster’ field.

{%DATE}
Displayes the current date. Default format is mm/dd/yyyy but the FORMAT argument can be used to change the value into desired format. The old {%DUS}, {%DUT}, etc have been removed and must be replaced with the new format, as they don’t work.
Examples of date formats:
FORMAT=”mmmm d, yyyy” -> March 3, 2010
FORMAT=”yyyy-mm-dd” -> 2010-03-01
FORMAT=”mmmm yyyy” -> March 2010

{%TIME}
Displayes the current time. Default format is hh:nn:ss (24h universal format) but like with the date, the FORMAT argument can be used to change the value into desired format. Note that minutes use the letter N, not M (which is used for month)! The old {%TUS}, {%TUT}, etc have been removed and must be replaced with the new format, as they don’t work.
Examples of time formats:
FORMAT=”h.nn ampm” -> 2.34 pm
FORMAT=”hh.nn ampm” -> 02.34 pm
FORMAT=”hh:nn” -> 14:34

{%INPUT PROMPT=”Please enter the amount” FORMAT=”$#,##0.00″ REQUIRED SETVAR=”variablename”}
Asks the user to enter a value. The optional arguemnt REQUIRED is used to force the user to enter a value (blank values will not be accepted). FORMAT can be used to format the value entered, for example into correct currency format (as shown above) or desired date format.
Additionally, SETVAR=”variablename” can be used to store the value entered for re-use later in the document, where {%GETVAR NAME=”variablename”} is used to retrieve/display it.

{%GETVAR NAME=”variablename”}
Get the value previously stored in an {%INPUT} command using the SETVAR argument.

{%USER} or {%USR}
Displayes the current user’s name. It will be the name of the user creating the form letter. {%USR} have been deprecated, it is just available for backwards compatibility. The optional argument NABFIELD will retrieve the value of the specified field from the NAB for the current user (field must be spelled exactly as in the NAB design):
{%USER NABFIELD=”JobTitle”}

{%PICKLIST SERVER=”servername” DB=”database” VIEW=”viewname” FIELD=”fieldname” PROMPT=”text}
This command let the user select a document from a list, and returns the value in the
specified field. SERVER and DB are optional, and defaults to current server and current database. VIEW, FIELD and PROMPT are required. Optionally CLEARCACHE can be used for multiple lookups to the same view where different documents are to be selected.

By using the FILTER argument, the document collection will be filtered to only those where the category (in a categorized view) matches the value in the specified field in the source document. E.g: VIEW=”(ClaimantList)” FILTER=”ParentUNID” will only show documents in the (categorized) lookup view with the same ParentUNID as the document being processed (merged).
By specifying the optional keyword/argument CLAIMANT, the VIEW, PROMPT and FILTER argumenst are set automatically as follows: VIEW=”(SysLookupClaimantsCatByParentUNID)” PROMPT=”Select Claimant:” FILTER=”ParentUNID”.

{%PICKLIST VIEW=”viewname” FIELD=”fieldname” CACHED}
This command is used after the initial picklist command. It will retrieve additional fields from the same (cached) document, so the user only have to select the document once but can retrieve multiple field values from it. If another {%PICKLIST} command is encountered with the CLEARCACHE argument, the cached document will not be available anymore.

And now the code, from a script library called Class.MailMerge.
Right now I don’t have the time to move the code out of my application and build a working sample database (the form letters are actually stored in a separate database), but I hope that this code can still help someone.

Option Public
Option Declare

'*** Script Library for MailMerge, preserving formatting in Rich Text field
'*** Requires Notes 6.5 or higher (tested in 7.0, 8.0 and 8.5)
'*** Copyright (c) Karl-Henry Martinsson 2003-2012
'*** Email: texasswede@gmail.com
'*** Websites: www.texasswede.com & blog.texasswede.com
'*** This code can be user in any application, as long as this notice
'*** is left intact. Also, the copyright information must be published in
'*** any documentation and on the About page, or similar location visible
'*** to the users, if they can not easily view/access the source code.
'*** If this code saves you time and helps you, consider a donation.

Const TYPE_FIELD = 1
Const TYPE_CMD = 2
Dim picklist List As NotesDocument 
Dim variable List As String

Class PlaceHolderData
    Public placeholderstring As String
    Public placeholdertype As Integer
    Public fieldname As String
    Public fieldtype As Long
    Public command As String
    Public argument List As String
    Public text As String 

    Public Sub New(Byval placeholder As String)
        ' Store the original placeholder
        placeholderstring = placeholder        
        ' Strip out curly brackets before and after
        placeholder = Mid$(placeholder,2,Len(placeholder)-2)
        If Left$(placeholder,1) = "%" Then    ' Check if it is a command
            Me.placeholdertype = TYPE_CMD
            ' Remove the % in front of the command
            placeholder = Right$(placeholder,Len(placeholder)-1)    
        Else
            Me.placeholdertype = TYPE_FIELD
        End If
        Call ParsePlaceHolder(placeholder)
    End Sub

    Private Sub ParsePlaceHolder(Byval placeholder As String)
        Dim startpos As Integer 
        Dim midpos As Integer 
        Dim endpos As Integer 
        Dim args As Integer                            ' Boolean to indicate argements present or not
        Dim argstring As String
        Dim qt As Integer 
        Dim eq As Integer
        Dim char As String
        Dim argname As String
        Dim argvalue As String
        Dim i As Integer

        ' First we need to find the end of the command or field.
        ' It is either at the end of the placeholder or when we encounter a space
        endpos = Instr(placeholder," ")            ' Search for space
        If endpos = 0 Then                                ' No space, e.g. no arguments
            endpos = Len(placeholder)                
            args = False
        Else                                                    ' We have some arguments
            endpos = endpos -1                        ' Reduce by one to get rid of trailing space
            args = True
        End If
        If Me.placeholdertype = TYPE_CMD Then
            Me.command = Ucase(Left$(placeholder,endpos))
        Else
            Me.fieldname = Left$(placeholder,endpos)            
        End If
        If args = True Then 
        ' Add code here to get arguments
            argstring = Fulltrim(Right$(placeholder,Len(placeholder)-endpos)    )    ' Get arguments only
            qt = False
            eq = False
            For i = 1 To Len(argstring)
                char = Mid$(argstring,i,1)    ' Get character
                If eq = True Then
                    argvalue=argvalue & char
                Else
                    argname=argname & char
                End If

                If char = |"| Then                    ' We found a quote
                    If qt = False Then
                        qt = True                        
                    Else
                        qt = False
                    End If
                Elseif char="=" Then             ' Found a equal, e.g. now we are getting to a value
                    If eq = False Then
                        eq = True                        
                    Else
                        eq = False
                    End If
                End If
                If i = Len(argstring) Then        ' We are at the end
                    char = " "                        ' Fake a space
                End If
                If char = " " Then                    ' Found a space
                    If qt = False Then            ' Make sure it is not within quotes
                        eq = False                    ' Now we are back at argument name again
                        If Right$(argname,1) = "=" Then                    
                            argname = Left$(argname,Len(argname)-1)    ' Remove trainling equal sign
                        End If
                        Me.argument(Ucase(argname)) = Fulltrim(Replace(argvalue,|"|,""))    ' Create list item, remove quotes
                        argname = ""
                        argvalue = ""
                    End If
                End If
            Next
        End If
    End Sub

    Public Sub ProcessPlaceHolder(sourcedoc As NotesDocument, lossnotice As NotesDocument)
        Dim session As New NotesSession                
        Dim thisdb As NotesDatabase
        Dim ws As New NotesUIWorkspace
        Dim pickcollection As NotesDocumentCollection
        Dim pickdoc As NotesDocument
        Dim servername As String
        Dim dbname As String
        Dim viewname As String        
        Dim fieldvalue As String
        Dim formatstring As String
        Dim inputstr As String
        Dim prompt As String
        Dim title As String
        Dim default As String
        Dim filterfield As String
        Dim filtervalue As String
        Dim nabdoc As NotesDocument

        ' Read any formatting specified in arguments
        If Iselement(Me.argument("FORMAT")) Then
            formatstring = Me.argument("FORMAT")
        Elseif Iselement(Me.argument("FMT")) Then
            formatstring = Me.argument("FMT")
        Else 
            formatstring = ""
        End If

        If placeholdertype = TYPE_FIELD Then
            If sourcedoc Is Nothing Then
                Msgbox "Error: sourcedoc not defined, unable to retrieve data from field '" & Me.fieldname & "'.",,"MailMerge::PlaceHolder.ProcessPlaceHolder()"
                fieldvalue = "*** ERROR ***"                
                Exit Sub
            Else
                If Iselement(Me.Argument("LOSSNOTICE")) Then
                    fieldvalue = lossnotice.GetItemValue(Me.fieldname)(0)
                    Me.FieldType = lossnotice.GetFirstItem(Me.fieldname).Type
                Elseif Iselement(Me.Argument("SOURCE")) Then
                    If Ucase(Me.Argument("SOURCE")) = "LOSSNOTICE" Then
                        fieldvalue = lossnotice.GetItemValue(Me.fieldname)(0)
                        Me.FieldType = lossnotice.GetFirstItem(Me.fieldname).Type
                    End If
                Else
                    fieldvalue = sourcedoc.GetItemValue(Me.fieldname)(0)
                    Me.FieldType = sourcedoc.GetFirstItem(Me.fieldname).Type
                End If
                If formatstring <> "" Then
                    If Isdate(fieldvalue) Then                    ' Check if it might be a date/time value
                        fieldvalue = Format$(Cdat(fieldvalue),formatstring)
                    Elseif Isnumeric(fieldvalue) Then    ' Check if it might be a numeric value
                        fieldvalue = Format$(Cdbl(fieldvalue),formatstring)
                    End If
                End If
            End If
            Me.text = fieldvalue
        Else
            ' *** Fix legacy commands
            If Ucase(Me.Command) = "USR" Then    
                Me.Command = "USER"
            End If
            ' *** Process placeholder commands
            Select Case Ucase(Me.Command)
            Case "USER" :
                If Iselement(Me.Argument("NABFIELD")) Then
                    Me.Text = GetNABField(session.CommonUserName, Me.Argument("NABFIELD")) 
                Else
                    Me.Text = session.CommonUserName 
                End If
            Case "INPUT"        :        ' *** Ask the user to enter information
                prompt = Me.Argument("PROMPT")
                If Iselement(Me.Argument("TITLE")) Then
                    title = Me.Argument("TITLE")
                Else
                    title = "FormLetter Mail Merge"
                End If
                If Iselement(Me.Argument("DEFAULT")) Then
                    default = Me.Argument("DEFAULT")
                Else
                    default = ""
                End If
                If Iselement(Me.Argument("REQUIRED")) Then
                    ' Repeat until user enter a value
                    Do                
                        inputstr = Inputbox$(prompt, title, default)                        
                    Loop While Fulltrim(inputstr)=""
                Else
                    inputstr = Inputbox$(prompt, title, default)                        
                End If
                If formatstring <> "" Then
                    If Isdate(inputstr) Then                    ' Check if it might be a date/time value
                        inputstr = Format$(Cdat(inputstr),formatstring)
                    Elseif Isnumeric(inputstr) Then    ' Check if it might be a numeric value
                        inputstr = Format$(Cdbl(inputstr),formatstring)
                    End If
                End If
                Me.Text = inputstr
                ' *** Check for SETVAR argument
                If Iselement(Me.argument("SETVAR")) Then
                    variable(Ucase(Me.argument("SETVAR")))=Me.Text
                End If

            Case "PICKLIST"    :        ' Present the user with a list of documents to choose from
                Set thisdb = session.CurrentDatabase
                Set pickdoc = Nothing        ' Clear pickdoc
                ' *** We need to get the view argument to perform a lookup into the list...
                If Iselement(Me.Argument("VIEW")) Then
                    viewname = Ucase(Me.Argument("VIEW"))
                End If
                ' *** If CLAIMANT argument is specified, set arguments to predefined values
                If Iselement(Me.Argument("CLAIMANT")) Then
                    Me.Argument("VIEW") = "(SysLookupClaimantsCatByParentUNID)"
                    Me.Argument("FILTER") = "ParentUNID"
                    Me.Argument("PROMPT") = "Select Claimant:"
                End If
                ' *** Check if user requested to clear cached data
                If Iselement(Me.Argument("CLEARCACHE")) Then
                    If Iselement(picklist(viewname)) Then
                        Erase picklist(viewname)    ' Delete this cached item (document)
                    End If
                End If
                ' *** If user want to use cached data, load pickdoc with cached data
                If Iselement(Me.Argument("CACHED")) Then
                    If Iselement(picklist(viewname)) Then
                        Set pickdoc = picklist(viewname)
                    End If
                End If
                If pickdoc Is Nothing Then    ' No cached document for this view 
                    If Iselement(Me.Argument("SERVER")) Then
                        servername = Me.Argument("SERVER")
                    Else
                        servername = thisdb.Server
                    End If
                    If Iselement(Me.Argument("DB")) Then
                        dbname = Me.Argument("DB")
                    Else
                        dbname = thisdb.FilePath 
                    End If
                    If Iselement(Me.Argument("VIEW")) Then
                        viewname = Me.Argument("VIEW")    
                    Else
                        Msgbox "Missing Required Argument - VIEW" & Chr$(13) & Me.PlaceHolderString,,"Missing Argument"
                        Exit Sub
                    End If
                    If Iselement(Me.Argument("PROMPT")) Then
                        prompt = Me.Argument("PROMPT")
                    Else
                        Msgbox "Missing Required Argument - PROMPT" & Chr$(13) & Me.PlaceHolderString,,"Missing Argument"
                        Exit Sub
                    End If
                    If Iselement(Me.Argument("TITLE")) Then
                        title = Me.Argument("TITLE")
                    Else
                        title = "FormLetter Mail Merge"
                    End If
onemoretime:                
                    If Iselement(Me.Argument("FILTER")) Then
                        filterfield = Me.Argument("FILTER")                            ' Get field to filter on
                        filtervalue = sourcedoc.GetItemValue(filterfield)(0)        ' Get value of field on source document
                        Set pickcollection = ws.PicklistCollection(3, False, servername, dbname, viewname, title, prompt, filtervalue)
                    Else
                        Set pickcollection = ws.PicklistCollection(3, False, servername, dbname, viewname, title, prompt)
                    End If
                    If Isempty(pickcollection) Then
                        If Iselement(Me.Argument("REQUIRED")) Then
                            If Ucase(Me.Argument("REQUIRED")) <> "NO" Then
                                Msgbox "You need to select one item/document in the list.", , title
                                Goto onemoretime
                            End If
                        End If
                    Else
                        Set pickdoc = pickcollection.GetFirstDocument        
                    End If
                    If pickdoc Is Nothing Then
                        Msgbox "Error: No document returned.",,"MailMerge::PlaceHolder.ProcessPlaceHolder()"
                        Exit Sub
                    End If
                    Set picklist(Ucase(viewname)) = pickdoc
                End If
                If Iselement(Me.Argument("FIELD")) Then
                    fieldname = Me.Argument("FIELD")
                Else
                    Msgbox "Missing Required Argument - FIELD" & Chr$(13) & Me.PlaceHolderString,,"Missing Argument"                        
                    Exit Sub
                End If
                inputstr = pickdoc.GetItemValue(fieldname)(0)
                If formatstring <> "" Then
                    If Isdate(inputstr) Then                    ' Check if it might be a date/time value
                        inputstr = Format$(Cdat(inputstr),formatstring)
                    Elseif Isnumeric(inputstr) Then    ' Check if it might be a numeric value
                        inputstr = Format$(Cdbl(inputstr),formatstring)
                    End If
                End If
                Me.Text = inputstr
                ' *** Check for SETVAR argument
                If Iselement(Me.argument("SETVAR")) Then
                    variable(Ucase(Me.argument("SETVAR")))=Me.Text
                End If

            Case "DATE"            :         ' *** Current Date
                If formatstring = "" Then 
                    Me.Text = Format$(Now(),"mm/dd/yyyy")
                Else
                    Me.Text = Format$(Now(),formatstring)
                End If

            Case "TIME"            :         ' *** Current Time
                If formatstring = "" Then 
                    Me.Text = Format$(Now(),"hh:nn:ss")
                Else
                    Me.Text = Format$(Now(),formatstring)
                End If

            Case "GETVAR"    :    ' *** Get variable previously stored
                If Iselement(variable(Ucase(Me.argument("NAME")))) Then
                    Me.Text = variable(Ucase(Me.argument("NAME")))
                End If

            Case Else                :
                Me.Text = "**** undefined command ***"

            End Select
        End If

    End Sub

    ' *** Private supporting functions/subs

    Private Function GetNABField(user As String, fieldname As String) As String
        Dim session As New NotesSession
        Dim curdb As NotesDatabase    
        Dim nabdb As NotesDatabase
        Dim view As NotesView
        Dim col As NotesDocumentCollection
        Dim userdoc As NotesDocument

        Set curdb = session.CurrentDatabase
        Set nabdb = New Notesdatabase(curdb.Server, "names.nsf")
        Set view = nabdb.GetView("PeopleByFirstname")
        Set col = view.GetAllDocumentsByKey(user)
        If col Is Nothing Then
            GetNABField = ""
            Exit Function
        End If
        Set userdoc = col.GetFirstDocument
        If userdoc Is Nothing Then
            GetNABField = ""
            Exit Function
        End If
        GetNABField = userdoc.GetItemValue(fieldname)(0)
    End Function

End Class

Class MailMergeObject
    Public templatedoc As NotesDocument    ' Where to get layout from
    Public sourcefield As NotesRichTextItem    
    Public targetfield As NotesRichTextItem    ' Where to put the merged text
    Public placeholder List As PlaceHolderData
    Private sourcedoc As NotesDocument     ' The document containing data to be merged
    Private maindoc As NotesDocument        ' The main document for the processed document
    Private tempbody As NotesRichTextItem        ' Temporary copy of body field for this class/instance

    Public Sub New()

    End Sub

    Public Sub SetSourceDoc(doc As NotesDocument)
        Set sourcedoc = doc                
    End Sub

    Public Sub SetMainDoc(doc As NotesDocument)
        Set maindoc = doc
    End Sub

    Public Function LoadTemplate() As Integer
        Dim body As NotesRichTextItem
        Dim temp As String            
        Dim bodytext As String
        Dim startpos As Long
        Dim endpos As Long
        Set sourcefield = templatedoc.GetFirstItem("Body")    ' Put template body field (rich text) into global object
        Set body = sourcefield                                ' Put rich text into temporary body object
        bodytext = body.GetUnformattedText()
        startpos = Instr(bodytext,"{")
        Do While startpos > 0
            endpos = Instr(startpos,bodytext,"}")
            If endpos>0 Then
                temp = Mid$(bodytext,startpos,endpos-startpos+1)
                Set placeholder(temp & "~" & startpos) = New PlaceHolderData(temp)    ' Add to list of placeholder objects        
            End If
            startpos = Instr(endpos,bodytext,"{")
        Loop
    End Function

    Public Function MergedRichText() As NotesRichTextItem
        Dim range As NotesRichTextRange         
        Dim cnt As Integer
        Set tempbody = sourcefield
        Set range = tempbody.CreateRange 
        Forall p In placeholder
            Call p.ProcessPlaceHolder(sourcedoc, maindoc)
            If p.text = "" Then
                p.text = " -- "
            End If
            cnt =  range.FindAndReplace(p.placeholderstring, p.text, 1+4+8+16)            
        End Forall
        Call tempbody.Compact 
        Call tempbody.Update 
        Set targetfield = tempbody
        Set MergedRichText = tempbody
    End Function    

    Public Function Content() As NotesRichTextItem
        Set Content = targetfield
    End Function

End Class

I will try to post some sample code later, using this script library.

HCL Ambassador 2020

HCL Ambassador 2020

IBM Champion 2014-2020

Stack Exchange

profile for Karl-Henry Martinsson on Stack Exchange, a network of free, community-driven Q&A sites

Notes/Domino Links

  • Planet Lotus Planet Lotus
  • IBM dW Forums IBM dW Forums
  • StackOverflow StackOverflow

Recent Posts

  • Domino 14 Early Access Program
  • Announced: Engage 2024
  • Integrate Node-RED with Notes and Domino
  • Notes and Domino v12 is here!
  • NTF Needs Your Help

Recent Comments

  • Theo Heselmans on Announced: Engage 2024
  • Lotus Script Multi-thread Message Box [SOLVED] – Wanted Solution on ProgressBar class for Lotusscript
  • Viet Nguyen on Keep up with COVID-19 though Domino!
  • Viet Nguyen on Keep up with COVID-19 though Domino!
  • Mark Sullivan on Looking for a HP calculator? Look no further!

My Pages

  • How to write better code in Notes

Archives

  • October 2023 (2)
  • September 2023 (1)
  • June 2021 (1)
  • April 2021 (2)
  • March 2021 (1)
  • August 2020 (3)
  • July 2020 (2)
  • April 2020 (2)
  • March 2020 (1)
  • December 2019 (2)
  • September 2019 (1)
  • August 2019 (2)
  • July 2019 (2)
  • June 2019 (3)
  • April 2019 (2)
  • December 2018 (1)
  • November 2018 (1)
  • October 2018 (5)
  • August 2018 (2)
  • July 2018 (3)
  • June 2018 (2)
  • May 2018 (1)
  • April 2018 (2)
  • March 2018 (1)
  • February 2018 (2)
  • January 2018 (4)
  • December 2017 (3)
  • November 2017 (2)
  • October 2017 (2)
  • September 2017 (1)
  • August 2017 (2)
  • July 2017 (6)
  • May 2017 (4)
  • February 2017 (1)
  • January 2017 (2)
  • December 2016 (2)
  • October 2016 (3)
  • September 2016 (4)
  • August 2016 (1)
  • July 2016 (2)
  • June 2016 (2)
  • May 2016 (3)
  • April 2016 (1)
  • March 2016 (4)
  • February 2016 (2)
  • January 2016 (4)
  • December 2015 (3)
  • November 2015 (2)
  • October 2015 (1)
  • September 2015 (2)
  • August 2015 (1)
  • July 2015 (5)
  • June 2015 (2)
  • April 2015 (2)
  • March 2015 (3)
  • February 2015 (2)
  • January 2015 (10)
  • December 2014 (1)
  • November 2014 (3)
  • October 2014 (3)
  • September 2014 (13)
  • August 2014 (6)
  • July 2014 (5)
  • May 2014 (3)
  • March 2014 (2)
  • January 2014 (10)
  • December 2013 (5)
  • November 2013 (2)
  • October 2013 (5)
  • September 2013 (4)
  • August 2013 (7)
  • July 2013 (3)
  • June 2013 (1)
  • May 2013 (4)
  • April 2013 (7)
  • March 2013 (8)
  • February 2013 (9)
  • January 2013 (5)
  • December 2012 (7)
  • November 2012 (13)
  • October 2012 (10)
  • September 2012 (2)
  • August 2012 (1)
  • July 2012 (1)
  • June 2012 (3)
  • May 2012 (11)
  • April 2012 (3)
  • March 2012 (2)
  • February 2012 (5)
  • January 2012 (14)
  • December 2011 (4)
  • November 2011 (7)
  • October 2011 (8)
  • August 2011 (4)
  • July 2011 (1)
  • June 2011 (2)
  • May 2011 (4)
  • April 2011 (4)
  • March 2011 (7)
  • February 2011 (5)
  • January 2011 (17)
  • December 2010 (9)
  • November 2010 (21)
  • October 2010 (4)
  • September 2010 (2)
  • July 2010 (3)
  • June 2010 (2)
  • May 2010 (3)
  • April 2010 (8)
  • March 2010 (3)
  • January 2010 (5)
  • November 2009 (4)
  • October 2009 (7)
  • September 2009 (1)
  • August 2009 (7)
  • July 2009 (1)
  • June 2009 (4)
  • May 2009 (1)
  • April 2009 (1)
  • February 2009 (1)
  • January 2009 (3)
  • December 2008 (1)
  • November 2008 (1)
  • October 2008 (7)
  • September 2008 (7)
  • August 2008 (6)
  • July 2008 (5)
  • June 2008 (2)
  • May 2008 (5)
  • April 2008 (4)
  • March 2008 (11)
  • February 2008 (10)
  • January 2008 (8)

Categories

  • AppDev (10)
  • Blogging (11)
    • WordPress (5)
  • Design (5)
    • Graphics (1)
    • UI/UX (2)
  • Featured (5)
  • Financial (2)
  • Food (5)
    • Baking (3)
    • Cooking (3)
  • Generic (11)
  • History (5)
  • Hobbies (10)
    • LEGO (4)
    • Photography (4)
  • Humor (1)
  • IBM/Lotus (178)
    • #Domino2025 (14)
    • #DominoForever (8)
    • #IBMChampion (46)
    • Administration (7)
    • Cloud (7)
    • CollabSphere (9)
    • Community (49)
    • Connect (33)
    • ConnectED (12)
    • Connections (3)
    • HCL (15)
    • HCL Master (1)
    • IBM Think (1)
    • Lotusphere (46)
    • MWLUG (25)
    • Notes/Domino (99)
      • Domino 11 (7)
    • Sametime (8)
    • Verse (14)
    • Volt (3)
    • Watson (6)
  • Life (8)
  • Microsoft (7)
    • .NET (2)
    • C# (1)
    • Visual Studio (1)
  • Movies (3)
  • Old Blog Post (259)
  • Personal (23)
  • Programming (84)
    • App Modernization (11)
    • Formula (4)
    • Lotusscript (47)
    • NetSuite (4)
      • SuiteScript (3)
    • node.js (4)
    • XPages (4)
  • Reviews (9)
  • Sci-Fi (4)
  • Software (24)
    • Flight Simulator (2)
    • Games (4)
    • Open Source (2)
    • Utilities (6)
  • Technology (37)
    • Aviation (3)
    • Calculators (2)
    • Computers (6)
    • Gadgets (7)
    • Mobile Phones (7)
    • Science (3)
    • Tablets (2)
  • Travel (7)
    • Europe (1)
    • Texas (2)
    • United States (1)
  • Uncategorized (15)
  • Web Development (50)
    • Frameworks (23)
      • Bootstrap (14)
    • HTML/CSS (12)
    • Javascript (32)
      • jQuery (23)
  • 1
  • 2
  • Next

Administration

  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org

Tracking

Creeper
MediaCreeper
  • Family Pictures
© TexasSwede 2008-2014