Skip to main content

Manipulating data in Domino Web Access

Vinod Seraphin (seraphin@us.ibm.com), Senior Technical Staff Member, IBM
Vinod Seraphin is a Senior Technical Staff Member and lead architect for Lotus iNotes, which was "born" from Vinod's prototyping efforts to develop a compelling personal information manager (PIM) within a browser. He has been with IBM since 1991. Prior to working with Lotus Domino Web Access, Vinod was the Software Architect for Lotus Organizer®.
Shu Sia Lukito, Advisory I/T Specialist, IBM
Shu Sia Lukito is an Advisory I/T Specialist for IBM Software Services for Lotus, and has worked with Lotus Notes and Domino since 1996. She is currently working with Lotus and WebSphere Portal products. In her spare time, she enjoys cross stitching, crafting, and spending time with her family.
David DeJean (ddejean@dejean.com), Partner, DeJean & Clements
David DeJean has been working with and writing about Lotus Notes and Domino for as long as they've existed. He was co-author of the very first book about Notes, "Lotus Notes at Work," and has been an editor and writer for a variety of computer publications. He is a Lotus CLP and a partner in DeJean & Clemens, a firm that does Notes and Internet application development and technical and marketing communications.

Summary:  Read this article to learn how you can customize Lotus Domino Web Access to adapt to the specific requirements of your Notes/Domino data. We describe how Domino Web Access determines the appropriate scene to play for a form type, how data is reflected within the scene, and how updated data is validated.

Date:  17 Jan 2006
Level:  Intermediate
Activity:  2352 views

Lotus Domino Web Access has evolved to become more customizable. In its earliest versions, customization was limited mostly to changes in the user interface -- replacing graphics or hiding program elements. A previous developerWorks Lotus article looked at these basic interface modifications and explored how Domino Web Access pages are generated using the Domino Web Access template and associated forms file. The article discussed how to customize user-interface elements (such as the welcome, login, and redirection pages), and how to add actions to the action bar. It also discussed how skins and skin components are used to build the UI from multiple subforms, and how to use the skin editor to modify the skins that determine the look and feel of the application.

This article picks up where the first one left off. After a brief recap of the basic elements of Domino Web Access page construction, we discuss how Domino Web Access determines which scene to play for a particular form type, how data within a document is reflected within the scene, and how updated data might be validated before being sent back to the server. We also outline how additional fields can be added to a particular form type. We assume you've read the first article, and have some basic familiarity with Domino Web Access.

Domino Web Access page construction

Domino Web Access provides users who access Notes mail accounts through a browser with most of the functionality of the Notes email client. It does this in a way different from traditional Domino Web applications. Where Domino Web applications rely on design elements within the primary application database, Domino Web Access predominantly uses design elements within the forms file.

Domino Web Access, like QuickPlace, uses some alternate Web page construction techniques that allow much greater control of the coding that's sent to the browser. Rather than relying on the default Domino Web rendering of a particular field or full form, these products rely on pass-thru HTML to allow full control of the Web rendering. In addition, some special tags within the pass-thru HTML are interpreted by the server, and contribute to the HTML emitted. The previous article discussed the special tags used to evaluate Notes formulas, insert another subform, and insert the contents of a skin, which in turn includes various “skin components,” including the special PageContent skin component into which a “scene” is rendered.

Scenes, subscenes and the Forms Map Table

In Notes applications and traditional Domino Web applications, the form is the key design element. Forms govern the look and feel of a particular Notes document. A mail message looks the way it does because the mail message document has a form value of “Memo,” and so the Memo form is used to govern the layout of the document within the Notes client or within WebMail (a traditional Domino Web application). With Domino Web Access, in contrast, all the main pages use the same form, named h_PageUI, as the starting point. Figure 1 shows a graphic top-level summary of a Domino Web Access page as defined by the h_PageUI form.


Figure 1. h_PageUI form
h_PageUI form

Different content must be rendered within the <Scene>_Init and <Scene> areas. This content is determined by the value of a special computed variable: h_SetReadScene for read scenes (when a document is opened via ?OpenDocument), and h_SetEditScene for edit scenes (when a document is opened via ?EditDocument). These values are set by the Forms Map Table.

Forms Map Table
The Forms Map Table is a special view within the Domino Web Access forms file that determines which scene to play when a document of a particular type is encountered. If you open the forms file using the Notes client, you will be able to find a view named System\Forms. Figure 2 shows a section of the view:


Figure 2. System\Forms view
System\Forms view

This view is used as a special lookup table to determine which scene to play when a particular document type is encountered. The left-most column, titled s_NotesForm, identifies the specific Notes form value, and is the column used to look up details for a particular form type. The h_SetReadScene column identifies what scene to play when a document of this type is opened for reading, and the h_SetEditScene column identifies what scene to play when a document of this type is opened for editing. So, if a mail message is opened for reading, the value of h_SetReadScene is s_StdPageRead, so the subform by this name will be emitted within the “<Scene>” portion of the h_PageUI diagram (see figure 1), and the subform with the name s_StdPageRead_Init will be used for the <Scene>_Init area.

When the h_SetReadScene value is s_StdPageRead, or the h_SetEditScene value is s_StdPageEdit, then the s_SubFormPrefix column value is significant and is used as the special prefix for a sequence of subforms used within the s_StdPageRead scene or s_StdPageEdit scene to generate the visual content. This usage of standard scenes for most document types allows Domino Web Access to have a place to share common initialization and functional JavaScript logic, which is similar for several document types.

The general layout of the s_StdPageRead_Init subform is shown in figure 3.


Figure 3. s_StdPageRead_Init subform
s_StdPageRead_Init subform

The script tag brings in an external script page, which is defined by a form named s_StdPageReadCode. Domino Web Access tries to move most static script to external script pages so that they can be efficiently cached and reused as subsequent pages are displayed.

Figure 4 illustrates the general layout of the s_StdPageRead subform.


Figure 4. s_StdPageRead subform
s_StdPageRead subform

The s_StdPageEdit scene is very similar to the s_StdPageRead scene, but uses subforms with “edit” within the subform names rather than “read."

Subscenes
The s_StdPageRead and s_StdPageEdit scenes contain very little visible content, but instead bring in most of the content from "subscenes.” Each subscene has a unique prefix, and is composed of two subforms for the read representation of the document (utilized by s_StdPageRead), two subforms for the edit representation of the document (utilized by s_StdPageEdit), and a dictionary subform that defines the schema of the document and is used by both s_StdPageRead and s_StdPageEdit. These subforms are:

  • <subscene prefix>+”Dictionary” defines the schema. It includes NotesDictionary and NotesField tags. This subform is used in both the read and edit scenes. (We’ll discuss these tags later in this article.)
  • <subscene prefix>+”Read_Init” is the HTML code to be included in the head area of the document when the read scene is played.
  • <subscene prefix>+”Read” is the HTML code to be included in the body area of the document when the read scene is played.
  • <subscene_prefix>+”Edit_Init” is the HTML code to be included in the head area of the document when the edit scene is played.
  • <subscene_prefix>+”Edit” is the HTML code to be included in the body area of the document when the edit scene is played.

So, when a document of form type Memo is opened for reading, the scene subforms s_StdPageRead_Init and s_StdPageRead are used, and the subscene subforms s_MailMemoDictionary, s_MailMemoRead_Init, and s_MailMemoRead are used.

Persisted and computed fields

In Notes and traditional Domino Web applications, fields represent the data associated with an application, and each Notes document type typically has a different set of data items. Some fields are also not "persisted" (saved), but are simply computed for display (or computed and hidden), and used to help generate the rest of the user interface for the form. Domino Web Access does not use the forms and subforms stored within the user’s mail file, and therefore doesn’t use the fields defined within these forms. Instead, Domino Web Access uses some special server-interpreted tags to define such persisted and computed-only fields. The NotesField tag is used to define a field that may be persisted to the document, and a NotesVar tag is used to define a computed-only field (or variable). Any occurrences of these tags must occur within a special container tag named NotesDictionary.

These tags support the same attributes. The more significant attributes are:

  • Name identifies the name of the “in memory” item, which might also be persisted to the document.
  • Type identifies the data type of the item. The ones presently supported by this mechanism are Text, TextList, RichText, Mime, Number, NumberList, Time, and TimeList.
  • InitialValue defines an optional formula to calculate if the named item does not already exist within the document.
  • Value defines a formula to calculate whenever the document is opened or saved.

Braces are the best delimiters for the various attribute values. Here's an example of a NotesDictionary block:

<NotesDictionary>
<NOTESFIELD NAME={RETENTION_START_DATE}>
<NOTESFIELD NAME={RETENTION_PERIOD}>
<NOTESFIELD NAME={RETENTION_APPROVER}>
<NOTESFIELD NAME={RETENTION_JUSTIFICATION}>
<NOTESVAR NAME={$$QuerySaveAgent} TYPE={Text} INITIALVALUE={"QSMailRtAgent"}>
</NotesDictionary>

As a response page is being generated or an HTTP post is being processed, the form and subform design elements that comprise the page are first scanned to build a cumulative dictionary of NotesFields and NotesVars. When you create a new document (or modify one), if a posted item value does not have a corresponding NotesField entry, the value is not persisted to the document.

By convention, the data schema for a particular form type that employs the s_StdPageRead and s_StdPageEdit scenes is expressed in the <SubScenePrefix>+”Dictionary” subform. So, to allow new fields to be persisted for a particular form type, additional NotesField entries would need to be added to the corresponding subscene dictionary subform. However, this is not the only thing that needs to be done to add support for a new field. The visual representation of the field needs to be coded within the appropriate read subscene subform, and the edit mode representation needs to be coded within the edit subscene subform. In addition, the HTML representation of the field needs a way to obtain the value of the field. Also, for edit scenes, the field many need to be initialized before display, and validated prior to form submission.

Computed text blocks and filters

As mentioned in the earlier article, Domino Web Access forms and subforms employ a special syntax for computed text. Any @formula that is valid in a Web page can be specified within a @{…} block. The formula is compiled and then executed. In addition, Domino Web Access supports two useful filters that allow validating the result of any such computation as a string that is either HTML or JavaScript compliant. A filter is specified by adding another set of braces within the computed text delimiters and specifying the filter name(s), making the syntax either @{{...};html} or @{{...};jsdata}. The HTML filter produces valid HTML data (special HTML characters are properly escaped). The JavaScript (jsdata) filter adds a backslash immediately before any single-quote (apostrophe) characters, in effect escaping the character, so it doesn't prematurely terminate the string.

The value of a field named "subject” might be incorporated into the page this way if it is within a JavaScript block:

var subject=’@{{subject};jsdata}’;

Within normal HTML flow (not within a script block), it would look like this:

<input type=”text” value=”@{{subject};html}”>

In addition to normal Web formulas, Domino Web Access uses some special formulas that it accesses by extending the @DbCommand @formula. These formulas are identified by the use of the word "Haiku" as the first argument in the formula. (Haiku was the original code name for the QuickPlace project.) The second argument references the actual special formula name, and any subsequent arguments are specific to the special formula being invoked. Domino Web Access employs many of these special formulas, but we'll discuss just two in this article: h_Vars and h_RunAgent.

Data item values and the h_Vars special formula

Traditional Domino Web applications define a field using Domino Designer and at the same time specify where in the HTML page it should be rendered and how it should be initialized. In Domino Web Access, however, all the item (field) values for a document are available on the page as JavaScript vars. Domino Web Access employs a special formula named h_Vars to produce this information. It is specified this way:

@{@DbCommand(“Haiku”;”h_Vars”[;<DocumentUnid>])}

The <DocumentUnid> argument is optional and allows retrieving of item values for a document other than the current one being processed by the current URL. The default value is the current document specified by the current URL.

This h_Vars special formula produces not only the non-system fields (ones that don’t begin with a “$”) present in the document, but also those specified by NotesVar and NotesField definitions. JavaScript variables are case-sensitive and Domino item names are not, so the items will be emitted using the same case as specified within the NotesDictionary definition. If an item is encountered that is not present within the NotesDictionary, then it will be uppercased. All values are also automatically run through the jsdata filter and formatted as JavaScript statements within a HTML script block, so you should never specify the jsdata filter when invoking this formula.

Domino Web Access makes extensive use of the Domino compute engine by evaluating formulas within computed text blocks or within NotesField or NotesVar attribute values. In Notes/Domino 6, all of these formulas are compiled and the binary results are encoded in base64 before they are stored in the form or subform, which makes them unreadable as plain text. For example:

<NOTESFIELD NAME={MailSort} TYPE={Text}
INITIALVALUE={#B64#NAAAACYAAQANAGlOb3Rlc1Byb2ZpbGUAAQAIAE1haWx
Tb3J09wIDAAcADAAFAAkwUzBFAA==}>

However, uncompiled formulas can also be placed between the computed text tags or within the NotesField and NotesVar attribute values that take formulas. In Domino 7, such formulas are no longer compiled, so it is much easier to see and modify various formula sequences that might be used within Domino Web Access. In Forms7.nsf, the preceding NotesVar definition would be:

<NOTESFIELD NAME=MailSort TYPE=Text
INITIALVALUE={@GetProfileField("iNotesProfile";"MailSort")}>

The h_RunAgent special formula

Another powerful special formula, h_RunAgent, allows invoking an agent to add custom content to a page. This formula supports invoking an agent (located within the forms file or the mail file) and allowing it to contribute to the page output. This special formula has the following syntax:

@DbCommand(“Haiku”; “h_RunAgent”; <AgentName> [;<AgentLocation>])

<AgentName> is a required argument containing a string value specifying the name of the agent. <AgentLocation> is an optional string argument, and should contain either 0 to indicate that the agent is in the mail file (the default), or 1 to indicate that the agent is in the forms file. If a 1 is specified for the <AgentLocation> argument, the agent is also given the current document context (determined by the document portion of the current URL).

The forms file also contains a simple s_RunAgent form that contains the preceding @DbCommand, and allows the agent name to be passed in via a URL argument. This way, an agent can be invoked on a particular document using a URL such as:

filename.nsf/($Inbox)/<documentunid>?OpenDocument&Form=
s_RunAgent&PresetFields=AgentName;<AgentName>

Extensible tags

As part of the Domino Web Access performance and scalability improvements in Domino 7, an additional page generation enhancement supports the specification of namespace qualified tags. This allows for replacing stand-alone invocations of special Haiku @DbCommands such as the h_RunAgent formula. This results in the compiled version of:

@{@DbCommand("Haiku"; "h_RunAgent"; AgentName; "1")}

...being replaced with the following:

<dwa:runagent agentname="AgentName" commonagent="1" />

The first is what is found in Forms6.nsf, and the second is what is found in Forms7. The first occurrence of a “dwa:” tag actually results in the Web server looking for and processing a special dwa_tags form. This form contains a special XML syntax that defines the various dwa: tags. If you search the dwa_tags form for runagent, you will find this XML stream (some line breaks added for legibility):

<tagdefinition name="runagent">
   <description> Haiku::RunAgent 
      @DbCommand("Haiku", "h_RunAgent", "<Agent name>" [, "<CommonAgent? 1:0"])
   ---------------------The last parameter was changed to a boolean flag since 
   the code threw away the arguments anyway. Run a named database agent.
   </description>
   <argument type="fieldname" name="agentname" />
   <argument type="text" optional="yes" name="commonagent" />
   <bodyfunction namespace="haiku" builtin="h_RunAgent" />
</tagdefinition>

This allows for the replacement of various compute blocks that were calling the special Haiku @DbCommands with special dwa namespace tags that are easier to read, self-documenting, and avoid having to initialize and utilize the compute engine, which is a relatively expensive operation.

Special URL arguments

Domino Web Access also uses some special URL arguments that can modify the execution of the application by changing values such as form names, field values, and caching behaviors.

&Form=
&Form= can be used to override the form specified for the document being manipulated. In addition to cases such as the s_RunAgent form mentioned previously, this is also used by Domino Web Access when loading the external script pages referenced within the product, as well as for the various modal dialog box pages that don't use the h_PageUI form. If you do a "view source" on any Domino Web Access page, you will find references such as this:

<script language="Javascript" 
src="/iNotes/Forms6.nsf/iNotes/Proxy/?OpenDocument&Form=
   s_MinUtils&l=en&CacheResults&MaxExpires&TimeStamp=
   20050818T215757,93Z&charset=ISO-8859-1&PresetFields=
   UA;IE"></script>

&Form=s_MinUtils will result in this form being used as the starting point rather than the default h_PageUI.

&PresetFields=
&PresetFields= provides a way to override NotesDictionary items by specifying multiple name/value pairs. Each name and value are separated by a semicolon character, and each pair is separated by a comma. The mail page uses this argument to identify the view or folder to display and what label to give it:

filename.nsf/iNotes/Mail/?OpenDocument&PresetFields= s_ViewLabel;Inbox,s_ViewName;(%24Inbox)&...

(The %24 is the URL encoding of the $ character.) URL arguments can also be used to control the caching of the pages to maximize performance, while insuring that the user is working with the latest data. &CacheResults (shortened to &CR in Domino 7) causes the Web server to return a Last-Modified response header value set to the last-modified value of the forms file. &MaxExpires (shortened to &MX in Domino 7) returns an Expires response header set to nearly one year from the current day, the maximum recommended value for this response header.

Making sure that the page returns a proper Last-Modified response header allows for more efficient processing if the user invokes the browser’s Refresh action, or traverses to the same page again. The browser sends the server an If-Modified-Since GET request in such scenarios, and the server can very efficiently return Not-Modified if nothing more recent is available. A user can hold down the Ctrl key and click the browser’s Refresh action to prevent the browser from sending a conditional GET. This is a good debugging technique to make sure a problem isn’t resulting from stale data in the browser cache.

&TimeStamp
Setting the Expires header to a value in the future results in the browser not even asking the server for a more recent version if this response is already in the browser cache. Reusing static content from the cache greatly improves client performance, reducing both bandwidth consumed and server CPU cycles. However, you need to be careful to avoid using stale information. For this reason, Domino Web Access typically adds a &TimeStamp (shortened to &TS in Domino 7) to avoid this problem. If the resource changes (for example, a newer forms file is installed on the server), this argument value would be different, and the application would no longer use the stale information in the cache.

The Custom_JS form

The Custom_JS form is the key to customizing Domino Web Access. This form serves as a container for a collection of customization entry point functions that are included in almost every Domino Web Access page. These functions include:

  • Scene_Actions will be called just before the action buttons are added to the action bar. Some possible customizations include adding a new item, removing an item, or changing the position of an action item.
  • Scene_PostLoad will be called after the body is loaded.
  • Scene_PreSubmit will be called just before a form is submitted, but after Domino Web Access has done its own validation.

By including code on the Custom_JS form, you can do things such as add custom action buttons to any view screen or read/edit screen, or change the display of the page.

A customization example: mail retention dialog

Here's a sample customization that adds a new feature to Domino Web Access: a mail retention dialog designed to enforce a company's policy on aging messages out of the mail system. This example assumes a default retention period of 30 days, and allows longer periods. The user can select a 60-day retention period without approval, or a 90-day period, which generates a request that is routed to an approver who must authorize it. (You can download the code required to create this example from the Download section at the end of this article.)

This example demonstrates how you can create the dialog box that allows mailbox owners to mark emails to be retained longer than the default period so that they are not deleted by the agent that enforces the rule. (Note that only the coding steps to customize Domino Web Access are presented here. The example does not cover the mailbox agent, nor the agent that processes the marked emails.)

The example adds or modifies several design elements in the Domino Web Access forms file, Forms6.nsf, and on the mail template, Mail6.ntf. The following two tables list these elements. The first table shows changes to Forms6.nsf.

Element name Element type Modification type Description
Custom_ApproverLookup | ApproverLookupFormNewExternal script page containing lookups.
Custom_MailRetention | MailRetentionFormNew (Copy/Modify existing)Dialog box layout.
Custom_MailRetentionFieldsSubformNewMail retention fields to be inserted into Notes Dictionary.
Custom_MailRetentionHTMLFieldsSubformNewMail retention HTML fields for JavaScript manipulation.
Custom_IndicatorEditSubformNewMail retention indicator for edit mode.
Custom_IndicatorReadSubformNewMail retention indicator for read mode.
Custom_JSFormModifiedNone
s_MailMemoDictionarySubformModifiedNone
s_MailMemoEditSubformModifiedNone
s_MailMemoReadSubformModifiedNone

The second table lists changes to Mail6.ntf:

Element name Element type Modification type Description
QOMailRtAgentAgentAddQueryOpen agent
QSMailRtAgentAgentAddQuerySave agent

Our example uses a database named Apprv.nsf to hold the names of approvers, who are assigned by department. In a real-world implementation, you would probably refer to approvers by some other method.

The example modifies the Domino Web Access UI to add buttons labeled Mail Retention to the action bar in the Mail Message read and edit scenes. While these buttons appear identical, they launch different actions. In the edit scene, the Mail Retention button launches a modal dialog box that allows the user to set a retention period and an approver (if required). The modal dialog actually updates hidden input fields within the main edit page, and the information isn’t acted upon by the server until the form is submitted when the user invokes some additional action, such as Save As Draft or Send. At that time, the information is processed by a QuerySave agent (a new feature in Domino Web Access version 6.5.5 and 7, and available in the latest cumulative Domino Web Access hotfix for 6.5.4). The retention value is added to the Notes document, and workflow launched if an approver is specified.

In the read scene, the Mail Retention button uses a hidden iFrame to invoke a custom agent called ReadMailRtAgent in Forms6.nsf. In this scenario, the dialog information is immediately sent to the server when it is completed, and this is facilitated by using the hidden iFrame. Our example leverages the s_RunAgent form mentioned earlier to invoke the agent.

Customizing the edit scene

The custom Mail Retention button within the Memo Edit scene appears in the toolbar (see figure 5).


Figure 5. Mail Retention button
Mail Retention button

When the user clicks the button, it will prompt the user to enter the required mail retention request information within a modal dialog box. This information includes start date, retention period, and business justification. The dialog box is shown in figure 6.


Figure 6. Mail Retention dialog
Mail Retention dialog

To create the Mail Retention button, the following code is added to the Scene_Actions function in the Custom_JS form:

if ('s_mailmemo' == s_SceneName.toLowerCase() && uw)
a_Actions[a_Actions.length] = {pos:331, title:'Mail Retention',
href:'javascript:MailRetention()'};

Note that "uw" is the obfuscated variable h_isBeingEdited, which would be true if the current document is being displayed as part of a ?EditDocument request.

The MailRetention function resides in the Custom_JS form. It uses Internet Explorer's window.showModalDialog DOM method (Domino Web Access implements something comparable for Gecko, so this will work on Firefox and Mozilla as well) to display the custom dialog box. Using this function, the dialog box automatically behaves as a modal dialog:

var shref = lT(self) + '/iNotes/Proxy/?OpenDocument&
   Form=MailRetention&l=   en@{@If(s_Charset="";"";"&charset=" + s_Charset)}';
var lI = window.showModalDialog(shref, ID, "dialogWidth:400px;dialogHeight:300px;
  dialogTop:200px;
|   dialogLeft:200px;help:no;status:no;center:no;");

Creating a new modal dialog box
The best way to create a new modal dialog box for Domino Web Access is to start with a form that implements an existing modal dialog box. A good one to use is s_DeliveryOptions, which implements the UI for the Delivery Options dialog. The reason for doing so is that these dialogs bring in certain common external script files that may change from release to release of Domino Web Access, and are typically brought in via some server-side evaluated @formulas. Also, various releases emit the script tags in different ways. Earlier releases emitted them via specific <script …></script> tags on the page. Newer releases have started emitting these via script as well, further reducing the size of the various pages. But they rely on various other JavaScript globals as well, located within the <head>…</head> section of the page. Starting with a copy, and retaining the majority of the head portion and gutting the body portion will allow you to leverage the same modal dialog box foundation used within other modal dialog boxes within Domino Web Access.

The code that builds the dialog box resides in a form named Custom_MailRetention. This form includes an external script page, ApproverLookup, that performs the lookup in the Mail Retention Approvers database. This script page is included in Custom_MailRetention form as follows:

<script language="Javascript" src="../../iNotes/Proxy/?OpenDocument&Form=
   ApproverLookup&l=en@{@If(s_Charset="";"";"&charset=" + 
      s_Charset)}&PresetFields=DEPT;Accounting">
</script>

It's worth noting that this page includes a NotesDictionary tag, and several special NotesVar tags:

  • The $Expires NotesVar controls the caching of the lookup data by setting the page to expire from the cache after one day: <NOTESVAR NAME={$Expires} VALUE={@Tomorrow}>
  • The $ContentType NotesVar tells the Domino server that this page is a script page: <NOTESVAR NAME={$ContentType} VALUE=
    {“application/x-javascript”}>
  • The $LastModified NotesVar allows a way to set the Last-Modified response header sent back with the page: <NOTESVAR NAME={$LastModified} VALUE={@Today}>

The dialog box built by the pass-through HTML and JavaScript code in the Custom_MailRetention form is displayed in figure 6. If the user selects a retention period longer than 60 days in the drop-down, an additional field will be displayed for the user to select an approver (see figure 7).


Figure 7. Mail Retention dialog with Approver field
Mail Retention dialog with Approver field

The question mark in the upper right corner of the dialog is a link to a page for context-sensitive help. This context-sensitive help is built by the following script:

<td align="right"><a onclick="javascript:OE(IF)"><img src=
   "/iNotes/Forms6.nsf/h_ResourcesByName/
   help.gif/$FILE/help.gif?OpenElement&MaxExpires" 
   border="0"></a></td>

The content for this help page is added as a file resource to the Help65_iwa_en.nsf database (located in the iNotes directory). An HTML file named MAIL_RETENTION.html contains HTML that can be customized with the appropriate help text and formatting. Figure 8 displays the help page.


Figure 8. Help page
Help page

Returning data to Notes
After entering the required mail retention information, the user will click the OK button, which calls a JavaScript function as described in the following:

<input class="s-form-button" type="button" id="ClientDataBtnOK"
onclick="BDA('OK')" value="OK" style="width:100%">

This function passes the values back to the ID object, which will be used by the MailRetention function (in Custom_JS) to populate the mail retention fields in the memo document:

function BDA(yX){
   if (yX == "OK") {
      var ID = window.dialogArguments;
      ID.RetStartDt = theForm.RETENTION_START_DATE.value;
      var field = theForm.RETENTION_PERIOD;
      ID.RetPeriod = field.options[field.selectedIndex].text;
      var field = theForm.RETENTION_APPROVER;
      ID.RetApprover = field.options[field.selectedIndex].value;
      if (ID.RetApprover == '<----- Select One ----->')
         ID.RetApprover = '';
      if (parseInt(ID.RetPeriod) > 60 && ID.RetApprover == '') {
         alert('You must specify approver for retention period > 60 days!');
         return;
      }
      ID.RetJustification = theForm.RETENTION_JUSTIFICATION.value;
      self.returnValue=true;
   } 
   else 
      self.returnValue=false;
   self.close();
}

The MailRetention function residing in the Custom_JS form processes the ID object to populate the fields, based on the scene type (edit or read):

//User response to dialogbox
if (lI == true) { //User clicks on the OK button
   if (uw) { //uw=true indicates the form is in Edit mode
      theForm.RETENTION_START_DATE.value = ID.RetStartDt;
      theForm.RETENTION_PERIOD.value = ID.RetPeriod;
      theForm.RETENTION_APPROVER.value = ID.RetApprover;
      theForm.RETENTION_JUSTIFICATION.value = ID.RetJustification;
   }
   else {
      CreateRunAgentHTML();
      var agentForm = document.forms["agentcmd"];
      agentForm.StartDate.value = ID.RetStartDt;
      agentForm.Period.value = ID.RetPeriod;
      agentForm.Approver.value = ID.RetApprover;
      agentForm.Justification.value = ID.RetJustification;
      setTimeout('document.forms["agentcmd"].submit()', 0);
   }
}

The NotesField that holds the value for the mail retention period is inserted into s_MailMemoDictionary as a subform. A line is added to the subform after the closing tag </NotesDictionary> that references the subform that carries additional data elements to be defined:

<InsertNotesSubform NAME={Custom_MailRetentionFields}>

In addition to NotesField, this form also defines the QuerySaveAgent and QueryOpenAgent that run on the memo form:

<NotesDictionary>
<NOTESFIELD NAME={RETENTION_START_DATE}>
<NOTESFIELD NAME={RETENTION_PERIOD}>
<NOTESFIELD NAME={RETENTION_APPROVER}>
<NOTESFIELD NAME={RETENTION_JUSTIFICATION}>
<NOTESFIELD NAME={RETENTION_ERRMSG}>
<NOTESVAR NAME={$$QuerySaveAgent} TYPE={Text} INITIALVALUE={"QSMailRtAgent"}>
<NOTESVAR NAME={$$QueryOpenAgent} TYPE={Text} INITIALVALUE={"QOMailRtAgent"}>
</NotesDictionary>

As noted previously, the NotesField tags define persistent data values that are written back to the underlying Notes document. The NotesVar tags initialize variables used in the creation of the Web page. For the NotesField entries, the corresponding HTML input fields that are required to write back the value from the dialog box are inserted into s_MailMemoEdit as another referenced subform:

<InsertNotesSubForm NAME={Custom_MailRetentionHTMLFields}>

This subform adds four hidden fields to the form that is eventually submitted to the server:

<INPUT TYPE=hidden NAME=RETENTION_START_DATE
   VALUE="@{RETENTION_START_DATE}">
<INPUT TYPE=hidden NAME=RETENTION_PERIOD
   VALUE="@{RETENTION_PERIOD}">
<INPUT TYPE=hidden NAME=RETENTION_APPROVER
   VALUE="@{{RETENTION_APPROVER};html}">
<INPUT TYPE=hidden NAME=RETENTION_JUSTIFICATION
   VALUE="@{{RETENTION_JUSTIFICATION};html}}">

QueryOpen and QuerySave agents
In Domino Web Access, as in traditional Domino Web applications, developers can use QueryOpen and QuerySave events to run agents before Web users open or save documents. In Domino Web Access, these agents must reside in the mail template, and can be written in any of the supported agent languages (Notes formula, LotusScript, or Java).

To enable Domino Web Access QueryOpen and QuerySave functionality, first add the following line to the Notes.ini file:

iNotes_WA_QueryAgents=1

Create a NotesVar, either $$QueryOpenAgent or $$QuerySaveAgent, and set its value to the name of the agent in the mail file you wish to run. For example:

<NOTESVAR NAME={$$QuerySaveAgent} TYPE=
   {Text} INITIALVALUE={"YOUR_AGENT"}>
<NOTESVAR NAME={$$QueryOpenAgent} TYPE={Text} INITIALVALUE=
   {"YOUR_AGENT"}> 

These NotesVars can be added to the s_MailMemoDictionary subform, where YOUR_AGENT is the name of your agent.

In our mail retention example, the QueryOpen agent will make sure the approver set in the memo exists in the approver database. If the approver is no longer found in the approver database, a warning message will be displayed. The following LotusScript code fragment of the QueryOpen agent performs a lookup to the approver database. It populates the RETENTION_ERRMSG field if the approver is no longer found:

apprvName = doc.RETENTION_APPROVER(0)
If apprvName = "" Then Exit Sub
Set apprvdoc = apprview.GetDocumentByKey(apprvName, True)
If apprvdoc Is Nothing Then
   errMsg = "Approver " & apprvName & " is no longer in the database. "
   errMsg = errMsg & "Please select a valid approver!"
   doc.RETENTION_ERRMSG = errMsg
Else
   doc.RETENTION_ERRMSG = ""
End If

The Scene_PostLoad function in the Custom_JS form will check for the RETENTION_ERRMSG value. It will display an error message to the users if that field has been previously populated by the QueryOpen agent:

function Scene_PostLoad( s_SceneName, o_Window ){
// This function will be called after the body is loaded
   if ('s_mailmemo' == s_SceneName.toLowerCase() && 
      RETENTION_ERRMSG != '') alert(RETENTION_ERRMSG);
}

The QuerySave agent in this example checks to see whether or not the specified retention period is greater than 60 days. If so, the agent will send an email to the specified approver:

If Cint(doc.Retention_Period(0)) > 60 Then
   Set memo = New NotesDocument(db)
   memo.SendTo = doc.Retention_Approver(0)
   memo.Subject = "Request for Mail Retention Approval"
   Set rtitem = New NotesRichTextItem( memo, "Body" )
   Call rtitem.AppendText("Retention Period: 
      " & doc.Retention_Period(0) & " days")
   Call rtitem.AddNewline(1)
   Call rtitem.AppendText("Business Justification: 
      " & doc.Retention_Justification(0))
   Call memo.Send(False)
   Messagebox "Sent message to " & memo.SendTo(0)
End If

Customizing the read scene

In the Memo Read scene, the button utilizes a hidden iFrame to invoke a custom agent called ReadMailRtAgent. Unlike the QuerySave agent, this agent can be stored either in the mail template or in Forms6.nsf. However, storing this in the forms file allows you to pass the document context, and avoids needing to have the agent in every user’s mail database.

The iFrame is generated by the CreateRunAgentHTML function as follows:

function CreateRunAgentHTML() {
   if (document.forms["agentcmd"]){ return; }
      var aUnids = API_GetSelectedDocs();
   if (!aUnids){ alert("Unable to get the UNID of 
      the Document Context!"); return; }'

   var sAgentName = "ReadMailRtAgent";'

   var sCmd = API_GetMailfilePath() + '/0/' + aUnids.join(';') + 
      '?EditDocument&Form=s_RunAgent&
         PresetFields=AgentName;' + 
         sAgentName;

   var s = '<iframe name="myAgentFrame" id="myAgentFrame" 
      class="s-hidden-iframe" src="about:blank"></iframe>'
      + '<form name="agentcmd" target="myAgentFrame" 
         method="post" action="' + 
         sCmd + '">'
      + '<input name="StartDate" type="hidden">'
      + '<input name="Period" type="hidden">'
      + '<input name="Approver" type="hidden">'
      + '<input name="Justification" type="hidden">'
      + '</form>';

   // (DWA extends the Element class for Gecko to support 
      this method)
   document.body.insertAdjacentHTML("beforeEnd", s);
}

The MailRetention function in Custom_JS triggers ReadMailRtAgent by using the following JavaScript submit function. The script first populates HTML fields defined in the form of the iframe with the values selected from the dialog box. These values will be posted during the submit, and are available for the agent to manipulate:

CreateRunAgentHTML();
var agentForm = document.forms["agentcmd"];
agentForm.StartDate.value = ID.RetStartDt;
agentForm.Period.value = ID.RetPeriod;
agentForm.Approver.value = ID.RetApprover;
agentForm.Justification.value = ID.RetJustification;
document.forms["agentcmd"].submit();

In case of an error, the ReadMailRtAgent utilizes a callback function, MemoCallback, that is defined in Custom_JS:

function MemoCallback(agent_result, err_string) {
   if (agent_result == 0) {
   alert(err_string);
      return;
   }
   alert ("This email has been flagged for Mail Retention!");
   self.close();
}

This callback function is called from the ReadMailRtAgent as follows:

ErrHandler:
   errMsg = agent.Name & " Error " & Err() & 
      " - " & Error$ & " on line " & Erl()
   Messagebox errMsg
   If jscript = "" Then
      jscript = "<script>"
      jscript = jscript + "window.parent.setTimeout('MemoCallback(0, \'" + 
         errMsg + "\')', 0);"
      jscript = jscript + "</script>"
      Messagebox jscript
      Print jscript
   End If
   Exit Sub

Mail Retention indicator

In our example, a visual indicator helps users to know when a memo has been marked for retention (see figure 9).


Figure 9. Mail Retention indicator
Mail Retention indicator

The HTML that builds the indicator is defined in the GetIndicatorFunction of Custom_JS. The code is similar to the Domino Web Access follow-up feature (although the action is much simpler):

function GetIndicatorHTML() {
   var a=[],n=0;
   a[n++]='<table border="0" cellspacing="" cellpadding="" 
      width=100% style="background-color:'
      + BXi(0) + '"><tr><td><table border="0" cellspacing="" 
         cellpadding="2" >'
      + '<tr><td class="s-form-label" valign="top" width="'
      + 100 + '"><table cellSpacing=0 cellPadding=0 border=0>'
      + '<tr><td class="s-form-label">
         Mail Retention:</td></tr></table></td>'
      + '<td><table cellSpacing=0 cellPadding=0 border=0>'
      + '<tr><td class="s-form-label" valign="top">';
   a[n++]='<img src="' + CbL + 'vwicn082.gif" border="0" width="'
      + 13 + '" height="' + 11
      + '">&nbsp;This document has been marked for retention!';
   a[n++]='</td></tr></table></td></tr>
      </table></td>
      </tr></table>';
   return a.join('');
}

For the indicator to work in both read and edit modes, you must create two subforms, Custom_IndicatorRead and Custom_IndicatorEdit, and insert them into s_MailMemoRead and s_MailMemoEdit respectively. Here is the content of the Custom_IndicatorEdit subform:

<script>
if (RETENTION_PERIOD != '') {
   var sMailRt ='<tr><td colspan="4"><
      div id="MCDDiv">'
   + GetIndicatorHTML()
   + '</div></td></tr>';
   SV(sMailRt);
}
</script>

Conclusion

The mail retention example in this article has been created specifically to explore the special techniques of Domino Web Access page construction, with an emphasis on the Forms Map Table and the structure of scenes and subscenes that build the displayed page. It also demonstrates the use of the NotesDictionary tags (NotesVars and NotesFields) to extend the data schema, and techniques for leveraging more powerful agents to assist with page construction, as well as contributing to objects as they are opened or saved. In addition, it also shows how additional “shared” routines might be defined within the Custom_JS form, so they can be accessed from any other main Domino Web Access page.

The mail retention example is only the beginning. Using this article as a guide, you can explore the forms and subforms in the Domino Web Access forms file, and develop your own customizations of the browser experience provided by the Domino Web Access template. Many organizations have developed powerful extensions to the standard Notes mail template. It should be possible to build comparable extensions for Domino Web Access.

Acknowledgement
The authors would like to thank Samir J. Patel for his assistance testing and revising the customization example directions that accompany this article.



Download

DescriptionNameSizeDownload method
Sample codedwa-data/dwacustsample.zip92KB HTTP

Information about download methods


Resources

Learn

Discuss

About the authors

Vinod Seraphin is a Senior Technical Staff Member and lead architect for Lotus iNotes, which was "born" from Vinod's prototyping efforts to develop a compelling personal information manager (PIM) within a browser. He has been with IBM since 1991. Prior to working with Lotus Domino Web Access, Vinod was the Software Architect for Lotus Organizer®.

Shu Sia Lukito is an Advisory I/T Specialist for IBM Software Services for Lotus, and has worked with Lotus Notes and Domino since 1996. She is currently working with Lotus and WebSphere Portal products. In her spare time, she enjoys cross stitching, crafting, and spending time with her family.

David DeJean has been working with and writing about Lotus Notes and Domino for as long as they've existed. He was co-author of the very first book about Notes, "Lotus Notes at Work," and has been an editor and writer for a variety of computer publications. He is a Lotus CLP and a partner in DeJean & Clemens, a firm that does Notes and Internet application development and technical and marketing communications.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Lotus
ArticleID=101936
ArticleTitle=Manipulating data in Domino Web Access
publish-date=01172006
author1-email=seraphin@us.ibm.com
author1-email-cc=
author2-email=shu_lukito@us.ibm.com
author2-email-cc=
author3-email=ddejean@dejean.com
author3-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers