fhg
Volume 9, Number 35 -- November 4, 2009

Enhancing CGIDEV2

Published: November 4, 2009

by Paul Tuohy

Maybe "enhancing" is too strong a word, but "Add-Ons for CGIDEV2" doesn't have the same ring to it. I have always been (and still am) a big fan of CGIDEV2. A tool, such as CGIDDEV2, must be flexible enough to cater for all tastes. But when you have nailed down your own standards and working methods it is sometimes easier to have add-on procedures to implement those standards and working methods.

With that in mind, I want to share a few of the subprocedures I have written that make CGIDEV2 a little easier to use in my development environment. All of these subprocedures are coded in a single module: UTILCGI. Although this article deals specifically with CGIDEV2, it also contains examples of how you can wrap functionality around existing subprocedures.

Loading HTML Documents

When it comes to the HTML documents that I use in a Web application, there are a number of points worth noting:

  • Each document must have the content type text/html entry at the start of the document.
  • The header and footer section of each Web page is the same.
  • The use of buttons (add, change, delete, etc.) is the same throughout my application.
  • I prefer not to use the default identifiers for section names and variable names. Instead I use <!-- $section$ --> instead of /$section and <!-- %variable% --> instead of %variable%.
  • I maintain the identity of the directory containing the CGIDEV2 template documents in a data area.

CGIDEV2 provides two main subprocedures for loading HTML documents: getHTMLIFS() and getHTMLIFSMult(). The getHTMLIFSMult() subprocedure allows an easy means of loading multiple HTML documents to be processed as one. This is the equivalent of having copy members in DDS. Example Code 1 below shows the content of the template document StdMaintHead.html. This document contains a standard header that is common to all Web pages created interactively by an RPG program in my application. The main points to note are:

  • The content type text/html entry is at the start of the document. This means that the content type is defined in only one template document in my application.
  • There are two sections in the document, in case a program needs to insert additional heading information.
  • There are entries to include a standard CSS document and a standard Javascript document.
  • Documents make copious use of divisions and CSS classes. I leave it up to you to decide on your own style.

Code 1: The StdMaintHead.html template document

<!-- $top$ -->
Content-type: text/html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
   <meta http-equiv="Content-Type" content="text/html; 
    charset=ISO-8859-1">
   <title>My Application</title>

   <script language="javascript" src="/js/entryRoutines.js"
     type="text/javascript" />
   <link rel="stylesheet" href="/css/main.css" type="text/css" >

<!-- $top2$ -->
</head>
<body">
<div id="container">


   <div class="logo">My Logo
   </div>

   <div class="pageHeading"> My Common Headings
   </div>

Code 2 shows the content of the template document StdMaintFoot.html. This document simply contains a section that completes the Web page.


Code 2: The StdMaintFoot.html template document

<!-- $end$ -->
  
</div>

</body>
</html>

Code 3 shows the content of the template document StdButtons.html. This document contains sections for each permutation and combination of submit buttons used throughout an application.


Code 3: The StdButtons.html template document

<!-- $changebutton$ -->
<div class="buttons">
<input type="submit" name="cgioption" id="CheckButton" value="Change">
<input type="submit" name="cgioption" value="Delete" onClick=
"return confirmDelete()">
<input type="submit" name="cgioption" value="Cancel">
</div>

<!-- $addbutton$ -->
<div class="buttons">
<input type="submit" name="cgioption" id="CheckButton" value="Add">
<input type="submit" name="cgioption" value="Cancel">
</div>
</pre>

<!-- $changeCancelButton$ -->
<div class="buttons">
<input type="submit" name="cgioption" id="CheckButton" value="Change">
<input type="submit" name="cgioption" value="Cancel">
</div>

Finally, Code 4 shows the content of the template document StdCGI.html. This is a very simple template containing a standard section name and variable name that is used in the generation of standard drop-down boxes, radio buttons, and check boxes. But more about that later in the article.


Code 4: The StdCGI.html template document

<!-- $SIDCGISection$ -->
	  <!-- %SIDCGIVar% -->

Assuming that all of these templates are stored in a directory named MyTemplates in the IFS, I will have a 512-byte data area named CGIROOT, in the library containing my CGIDEV2 programs, with a value of '/MyTemplates/'.

I have wrapped the getHTMLIFSMult() subprocedure in another subprocedure, loadHTMLDocs(), which allows for less coding required in the template document being processed. Code 5 shows the relevant portion of the global D specs in UTILCGI along with the subprocedure loadHTMLDocs(). The main points to note are:

  • The subprocedure accepts up to five document names. Only the first is required.
  • If the list of standard templates has not been set, the identity of the template directory is retrieved from the data area and the variable HTMLDocs is set to identify the list of standard documents. Note that each standard document has the template directory appended and that HTMLDocs is a static variable so it does not need to be reset ob each call.
  • The variable HTMLDocsIn is set to identify the list of documents passed as parameters. Again, each document has the template directory appended.
  • Finally, the getHTMLIFS() subprocedure is used to retrieve the documents.

Code 5: The subprocedure loadHTMLDocs()

D CGIRoot         s            512a   DtaAra(CGIROOT)
D CGIRootDone     s               n
D thisRoot        s            512a   Varying
      
P loadHTMLDocs    B                   Export
D                 PI
D  doc01                        50a   Varying Const
D  doc02                        50a   Varying Const
D                                     Options(*NoPass)
D  doc03                        50a   Varying Const 
D                                     Options(*NoPass)
D  doc04                        50a   Varying Const 
D                                     Options(*NoPass)
D  doc05                        50a   Varying Const
D                                     Options(*NoPass)

D HTMLDocs        s          32767a   Varying Static
D HTMLDocsIn      s           1000a   Varying

 /free
  if not CGIRootDone;
     in(E) CGIRoot;
     thisRoot = %Trim(CGIRoot);
     HTMLDocs = thisRoot + 'StdMaintHead.html '  +
                thisRoot + 'StdButtons.html '    +
                thisRoot + 'stdCGI.html '        +
                thisRoot + 'StdMaintFoot.html ';
     CGIRootDone = *On;
  endIf;

  HTMLDOcsIn = thisRoot + doc01;
  if %Parms()> 1;
     HTMLDOcsIn = HTMLDOcsIn + thisRoot + doc02 + ' ';
  endIf;
  if %Parms()> 2;
     HTMLDOcsIn = HTMLDOcsIn + thisRoot + doc03 + ' ';
  endIf;
  if %Parms()> 3;
     HTMLDOcsIn = HTMLDOcsIn + thisRoot + doc04 + ' ';
  endIf;
  if %Parms()> 4;
     HTMLDOcsIn = HTMLDOcsIn + thisRoot + doc05 + ' ';
  endIf;

  getHTMLIFSMult(HTMLDocs + HTMLDocsIn :
                 '<!-- $':'$ -->':'<!-- %':'% -->');
  return;

 /end-Free
P                 E

The existing ability in CGIDEV2 to load multiple documents eases the requirement to repeat standard definitions in multiple HTML documents. Encapsulating the loading of these standard documents, along with the processing of an externally defined template directory, further eases the processing requirements in a CGI program.

Selection Lists, Radio Buttons, and Check Boxes

Some of the other items that can be tricky to handle with CGIDEV2 are selection lists, radio buttons, and check boxes. Of course CGIDEV2 has the crtTagOpt() subprocedure, which makes the generation of selection lists much easier and which I make use of in the following subprocedures: setCGIMultiple(), writeCGIMultiple(), and endCGIMultiple().

Let's have a look at these subprocedures at work. These subprocedures make use of the standard document shown back in Code 4. Code 6 shows the relevant portion of a programs template document and Code 7 shows the corresponding program code that uses the template.


Code 6: Template code

<span class="entryQuestion">In List? </span>

<!-- $afterInList$ -->
</p>

<p>
<span class="entryQuestion">Check These</span>

<!-- $afterCheckThese$ -->
</p>

<p>
<span class="entryQuestion">Size</span>

<!-- $afterSize$ -->
</p>

Code 7: Corresponding program code for Template code in Code 6

setCGIMultiple('R': 'InList' : inList :
               *Omit : *Omit : 2);
writeCGIMultiple('Y' : 'Yes');
writeCGIMultiple('N' : 'No');

wrtsection('afterInList');

setCGIMultiple('C': 'CheckThis');
writeCGIMultiple('W' : 'Watch' : checkW);
writeCGIMultiple('L' : 'Wallet' : checkL);
writeCGIMultiple('G' : 'Glasses' : checkG);

wrtsection('afterCheckThese');

setCGIMultiple('S': 'Size' : size);
writeCGIMultiple('S' : 'Small');
writeCGIMultiple('M' : 'Medium');
writeCGIMultiple('L' : 'Large');
endCGIMultiple();

wrtsection('afterAllowRpt');

Assuming that program fields have the following values, inList='Y', checkW='W', checkL=' ', checkG='G', and size='M', the above bit of jiggery-pokery will result in the html shown in Code 8.


Code 8: HTML generated from code in Figure 6 and Figure 7

< span class="entryQuestion">In List?</span>

   <input type="radio" name="InList"  
    class="entry" value="Y" checked> Yes
      
   <input type="radio" name="InList" 
    class="entry" value="N"  > No

</p>

<p>
<span class="entryQuestion">Check These</span>

   <input type="checkbox" name="CheckThis" 
    class="entry" value="W" checked> Watch
   <br />
   <input type="checkbox" name="CheckThis" 
    class="entry" value="L" > Wallet
   <br />
   <input type="checkbox" name="CheckThis" 
    class="entry" value="G" checked> Glasses
 
</p>

<p>
<span class="entryQuestion">Size</span>

   <select name="size" class="entry" >
   <option value="S">Small</option>
   <option value="M" SELECTED>Medium</option>
   <option value="L">Large</option>
   </selected>

</p>

I know that one of the major benefits of CGIDEV2 is that HTML is externally defined in a template and that these subprocedures are diverting from that by generating the HTML internally. But remember that the generation of the HTML is to a standard and it is still external to the program that is generating the page.

The subprocedures act as follows:

  • setCGIMultiple() constructs the required element.
  • writeCGIMultiple() places an individual entry.
  • endCGIMultiple() finishes the element (only required for selection lists).

Code 9 shows the base data structure and work fields (defined in the global D specs in UTILCGI) used by the subprocedures.


Code 9: Work fields used by the subprocedures

D base            Ds                  Qualified Inz
D  type                          1a
D  currValue                    50a   Varying
D  tabIndex                     10i 0
D  accross                      10i 0 Inz(1)
D  i                            10i 0

D data            s           1000a   Varying
D dataOut         s           1000a   Varying

D VARNAME         C                   'SIDCGIVar'
D SECTIONNAME     C                   'SIDCGISection'

Let's have a look at the subprocedures, starting with setCGIMultiple(), shown in Code 10. The main points to note are:

  • The first parameter identifies the required element as a radio button (R), check box (C), or selection list (S).
  • The second parameter identifies the name of the variable.
  • The third optional parameter identifies the current value for the variable. This is used to set the checked or selected option for the element.
  • The fourth optional parameter may be used to set a tab index.
  • The fifth optional parameter may be used to set a CSS class attribute--if not specified this defaults to a value of "entry."
  • The sixth optional parameter identifies how many elements should be on a line.
  • The final option parameter identifies any other attributes that should be assigned to an element, e.g., to call a JavaScript function.
  • The subprocedure constructs an element tag based on the value of the first parameter.
  • The name attribute is assigned and other attributes are stored or assigned based on whether or not relevant parameters were passed.
  • Finally, if the element is a selection list the element is written. If the element is for a radio button or check box, the element is completed with the value and checked options being identified by entries of %vl% and %ch% (these will be replaced in the writeCGIMultiple() subprocedure).

Code 10: The setCGIMultiple() subprocedure

p setCGIMultiple  B                   Export
D                 PI
D  type                          1a   Const
D  variable                     50a   Varying Const
D  currValue                    50a   Varying Const
D                                     Options(*NoPass : *Omit)
D  tabIndex                     10i 0 Const Options(*NoPass : *Omit)
D  class                        50a   Varying Const
D                                     Options(*NoPass : *Omit)
D  accross                      10i 0 Const Options(*NoPass : *Omit)
D  other                       500a   Varying Const Options(*NoPass)

D classDft        s             50a   Varying
D                                     Inz('class="entry" ')
 /free
  reset Base;
  base.type = type;

  select;
     when base.type = 'S';
        data = '<select ';
     when base.type = 'R';
        data = '<input type="radio" ';
     when base.type = 'C';
        data = '<input type="checkbox" ';
     other;
        return;
  endSl;

  data = data + 'name="' + %trim(Variable) + '" ';

  if %Parms() > 2;
     if (%Addr(currValue) <> *null);
        base.currValue = %Trim(currValue);
     endIf;
  endIf;

  if %Parms() > 3;
     if (%Addr(tabIndex) <> *null);
        base.tabIndex = tabIndex;
        data = data+'tabIndex="' + %char(tabIndex) + '" ';
     endIf;
  endIf;

  if (%Parms() > 4);
     if (%Addr(class) <> *null);
        classDft = %Trim(class);
     endIf;
  endIf;
  data = data + classDft;

  if %Parms() > 5;
     if (%Addr(Accross) <>  *null);
        base.accross = accross;
     endIf;
  endIf;

  if (%Parms() > 6);
     data = data + %Trim(other);
  endIf;

  if base.type = 'S';
     data = data + '>';
     updHTMLVar(VARNAME : data);
     wrtSection(SECTIONNAME);
  else;
     data = data + 'value="%vl%" %ch%>';
  endIf;

  return;
 /end-Free
P                 E

Code 11 shows the writeCGIMultiple() subprocedure. The main points to note are:

  • The first parameter identifies the value to be assigned to the element.
  • The second parameter identifies the descriptive text for the element.
  • The third optional parameter identifies the current value for the element (this should only be required for check boxes).
  • If the element is a selection list then the crtTagOpt() subprocedure is used to create the <option> element otherwise.
  • The number of entries per line is calculated and either spacing or a line break is placed on the page. Then, the %Replace BIF is used to replace %vl% and %ch% entries with the required values and the element is written.

Code 11: The writeCGIMultiple() subprocedure

P writeCGIMultiple...
P                 B                   Export
D                 PI
D  value                        50a   Varying Const
D  desc                        100a   Varying Const
D  currValue                    50a   Varying Const Options(*Nopass)

D workValue       s                   Like(Value)
D workDesc        s                   Like(Desc)
D workCurrValue   s                   Like(currValue)

 /free
  workValue = %trim(value);
  workDesc = %trim(desc);
  if (base.type = 'S');
     updHTMLvar(VARNAME:CrtTagopt(workValue :
                                  workDesc :
                                  base.currValue));
     wrtsection(SECTIONNAME);
  else;
     base.i += 1;
     if (base.i > 1);
        if %Rem( base.i - 1 : base.accross) = 0;
           updHTMLVar(VARNAME : '<br/>');
        else;
           updHTMLVar(VARNAME : '   ');
        endIf;
        wrtSection(SECTIONNAME);
     endIf;

     dataOut = %Replace(workValue:data:%Scan('%vl%':data):4);
     workCurrValue = base.currValue;
     if (base.type = 'C' and %Parms() > 2);
        workCurrValue = currValue;
     endIf;
     if (workValue = workCurrValue);
        dataOut = %Replace('checked':dataOut:%Scan('%ch%':dataOut):4);
     else;
        dataOut = %Replace(' ':dataOut:%Scan('%ch%':dataOut):4);
     EndIf;
     dataOut = dataOut + ' ' + workDesc;
     updHTMLVar(VARNAME : dataOut);
     wrtSection(SECTIONNAME);

  endIf;
 /end-Free
P                 E

Finally, Code 12 shows the endCGIMultiple() subprocedure. This subprocedure only needs to be called to complete a selection list (but no harm is done if called for any of the other elements). The subprocedure simply writes the required ending </select> element.


Code 12: The endCGIMultiple() subprocedure

P endCGIMultiple  B                   Export
D                 PI

 /free
  if (base.Type = 'S');
     updHTMLVar(VARNAME : '</select>');
     wrtSection(SECTIONNAME);
  endIf;
 /end-Free
P                 E

There You Have It

Hopefully this has gotten your creative juices floating and, even if the code is of no direct or immediate use, it might give you some idea of how you can go about adding functionality to existing subprocedures without having to re-write or change them.

If you like this approach to CGIDEV2, you might want to go the full hog and have a look at Rennaisance, which is an open source (i.e., free) framework built around CGIDEV2.


Paul Tuohy is CEO of ComCon, an iSeries consulting company, and is one of the co-founders of System i Developer, which hosts the RPG & DB2 Summit conferences. He is an award-winning speaker who also speaks regularly at COMMON conferences, and is the author of "Re-engineering RPG Legacy Applications," "The Programmers Guide to iSeries Navigator," and the self-study course called "iSeries Navigator for Programmers." Send your questions or comments for Paul to Ted Holt via the IT Jungle Contact page.




                     Post this story to del.icio.us
               Post this story to Digg
    Post this story to Slashdot


Sponsored By
HELP/SYSTEMS

SEQUEL ViewPoint®--Data Access & Analysis
for Power Systems™ Servers

                                               · Easy to use by IT and end users
                                               · Automated data access and display
                                               · Complete BI package: reports, tables,key
                                                  performance indicators, and dashboards
                                               · IBM i-centric for real-time data analysis
                                               · Expert support and training
                                               · Secure data access
                                               · Green screen, Web, browser

SEQUEL--Fast, efficient & cost-effective data analysis

Click here for a FREE Information Kit!


Senior Technical Editor: Ted Holt
Technical Editor: Joe Hertvik
Contributing Technical Editors: Erwin Earley, Brian Kelly, Michael Sansoterra
Publisher and Advertising Director: Jenny Thomas
Advertising Sales Representative: Kim Reed
Contact the Editors: To contact anyone on the IT Jungle Team
Go to our contacts page and send us a message.

Sponsored Links

looksoftware:  Get your FREE copy of the hottest product of the year!
Computer Keyes:  KeyesOverlay rapidly converts standard *SCS printer files into PDF documents
Manta Technologies:  Your complete source for IBM i training


 

IT Jungle Store Top Book Picks

Easy Steps to Internet Programming for AS/400, iSeries, and System i: List Price, $49.95
The iSeries Express Web Implementer's Guide: List Price, $49.95
The System i RPG & RPG IV Tutorial and Lab Exercises: List Price, $59.95
The System i Pocket RPG & RPG IV Guide: List Price, $69.95
The iSeries Pocket Database Guide: List Price, $59.00
The iSeries Pocket SQL Guide: List Price, $59.00
The iSeries Pocket Query Guide: List Price, $49.00
The iSeries Pocket WebFacing Primer: List Price, $39.00
Migrating to WebSphere Express for iSeries: List Price, $49.00
Getting Started With WebSphere Development Studio Client for iSeries: List Price, $89.00
Getting Started with WebSphere Express for iSeries: List Price, $49.00
Can the AS/400 Survive IBM?: List Price, $49.00
Chip Wars: List Price, $29.95


 
The Four Hundred
A Chat with Ross Mauri, Power Systems GM

IBM Slashes Prices on Power Core Activations

JDE EnterpriseOne Costs Less on i OS Than Windows or Linux, ITG Says

Mad Dog 21/21: Can Mashups Save the Advanced Economies?

Soltis Says iManifest Needed to Promote IBM i

Four Hundred Stuff
Open Text to Support new Windows 7 Features in Host Emulators

Halcyon Delivers ERP-Specific Monitoring in Systems Operations Suite 3.0

Healy Launches iPDF Server to Ease Spool File Distribution

mrc Goes Fully Graphical with Development Tool Interface

Inovis Boosts Productivity for Green-Screen Customers

Four Hundred Monitor
Four Hundred Monitor's
Full iSeries Events Calendar

System i PTF Guide
October 31, 2009: Volume 11, Number 44

October 24, 2009: Volume 11, Number 43

October 17, 2009: Volume 11, Number 42

October 10, 2009: Volume 11, Number 41

October 3, 2009: Volume 11, Number 40

September 26, 2009: Volume 11, Number 39

September 19, 2009: Volume 11, Number 38

TPM at The Register
Unisys takes Secure Cloud private

Ruiz out as Global Foundries chairman

Quanta opens servers to 100-core Tilera

IBM facelifts i/OS for midrange gear

Cisco and EMC in joint venture blitz

Moffat leaves IBM after insider trading arrest

Cray has ups and downs in Q3

Sun aims for sky, shoots self in foot

VMware Workstation plays lucky 7

Super Micro serves up not-bad quarter

Unisys squeezes profits from revenue decline in Q3

Asustek opens curtain on desktop 'supercomputer'

THIS ISSUE SPONSORED BY:

Help/Systems
WorksRight Software
Halcyon Software


Printer Friendly Version


TABLE OF CONTENTS
Enhancing CGIDEV2

A Quick-and-Easy Way to Convert Case in RPG Programs

Admin Alert: Keeping i5/OS Ethernet Lines Connected

Four Hundred Guru




 
Subscription Information:
You can unsubscribe, change your email address, or sign up for any of IT Jungle's free e-newsletters through our Web site at http://www.itjungle.com/sub/subscribe.html.

Copyright © 1996-2009 Guild Companies, Inc. All Rights Reserved.
Guild Companies, Inc., 50 Park Terrace East, Suite 8F, New York, NY 10034

Privacy Statement