From GUI to Hand Coding 101
By Alan Bell

The Information Builders WebFOCUS toolset can do amazing things in a simple way.  Just sometimes, though, there comes a point where what you want to do is create something a little different, overcome a restriction or just break out to do your own thing.

I come from a background of totally hand coding applications and in this article I will try and show how simple it can be to step outside the GUI tool box.

Coding by hand, from scratch, can be daunting, but many who do, really just cut and paste existing code parts to create a new piece of an application. Changing the code behind a report focexec is easy, it is there for all to see. Grabbing the code for an HTML page and reusing it is also very straightforward.  What happens when a button or link is pressed is the area where you can make a big difference.

The “magic” behind much of the WebFOCUS GUI products is the JavaScript interaction with WebFOCUS. The JavaScript is code that determines how a page is presented and/or processed. Much of the JavaScript supplied by IB though, has to operate on many different types of request, over thousands of options.  In reality, much can be accomplished with a small amount of simple JavaScript.

The simple triumvirate of HTML, JavaScript and CSS that makes a standard web page can be greatly enhanced by adding the dynamics of WebFOCUS.  CSS is used to create the style of your page, the HTML describes what is on a page and JavaScript how it is processed. This article focuses on the HTML, specifically form elements, and JavaScript, enough to get you started and maybe even interested:

Because the sites I create for one company I work for are used by the public, I have to ensure that the web pages work on all browsers and on all platforms. The code I show here is to W3C web standards and will work with all browsers.  Debugging a web page, particularly with javascript can be tricky; the messages for javascript errors can be highly uninformative. For this reason I develop web pages using Firefox with the Web Developer, HTML validator and Fangs extensions, available from the Mozilla Firefox site.  This gives me a comprehensive set of tools to help me develop web pages quickly and accurately. However beware that some IB GUI tools will not yet, and I am always hopeful, work with Firefox cleanly. The example the images in this article were taken from Firefox on an Apple Mac, my test environment, hence the different look from Internet Explorer.

For this article the movies sample file will be used.  The following is an example of a table request put out onto your web page with some JavaScript code added.  Points to note are that the report output is held as HTMTABLE, which holds the output as a table ready to insert onto a web page, then, following the report the -HTMLFORM BEGIN/END code is used, and in between the whole web page is created together with the table output from the report, brought in as !IBI.FIL.HOLD; . This example can be called the “High and Low” of your first bit of code. The report was created in the report painter, and a drill down applied to the moviecode BY field.  The drill down type is JavaScript to a function called showDetail and 2 parameters are given, TITLE and DIRECTOR, fields that have a NOPRINT (visible deselected in the options general tab) option on the report. In the web page declaration there is the open/close tags to declare the html, the report table and a small piece of JavaScript. The JavaScript function showDetail is coded to accept 2 parameters (TITLE and DIRECTOR) and then create an alert box to the user.  When the user clicks on the movie code, an alert pops up and shows the film name and the film’s director.

DEFINE FILE MOVIES
NEWMC/A120='<a href= || '''' || 'javascript:showDetail("' || TITLE || '","' || DIRECTOR || '");' ||
'''' ||  ' > ' || MOVIECODE || '</a>';
END
TABLE FILE MOVIES
PRINT NEWMC
TITLE      NOPRINT
DIRECTOR   NOPRINT
BY    MOVIECODE
HEADING
"Simple drill to JavaScript"
ON TABLE NOTOTAL
ON TABLE HOLD FORMAT HTMTABLE
ON TABLE SET HTMLCSS ON
ON TABLE SET STYLE *
.
.
TYPE=DATA,
COLUMN=N1,
JAVASCRIPT=showDetail(TITLE DIRECTOR),
$
.
.
ENDSTYLE
END
-RUN
-HTMLFORM BEGIN
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>The first page</title>
<script type="text/javascript">
function showDetail(a,b) {
alert("Movie is " + a +", directed by " + b)
}
</script>
</head>
<body>
!IBI.FIL.HOLD;
</body>
</html>
-HTMLFORM END

Just to focus on the JavaScript for a minute. This is an inline JavaScript and HTML knows it is JavaScript because it is between SCRIPT tags and declared as such. JavaScript consists of blocks of code and functions that are called by a reference to that function. The first { and final } declare the start and end of the block of code that is run.  JavaScript can also be held in a separate file and can be referenced using:

<script src="/mypath/myJavaScript.js" type=text/javascript>
</script>

Run this program and then view the source (right click on the page and select view source) of the output page.  You will see a line:
<A HREF= “javascript:showDetail(‘JAWS’,SPIELBERG S.’);”>001MCA</A>

WebFOCUS has kindly populated the call for us on each value of MOVIECODE. The <A refers to an anchor tag which has a link to a process via the HREF=, often the HREF is a URL to another web page, here it calls the JavaScript function showDetail. Between the close of the opening A tag (>) and the closing of the A tag (</A) is the text that is displayed on the page, usually in the well known form of blue underlined text, which is the browser standard for showing a link. The piece of JavaScript starting function showDetail(a,b) { , and ending with }, is the code that will be run when the text on the page is clicked. The a,b refers to the JavaScript function accepting parameters passed to it in the call e.g. showDetail(‘JAWS’,SPIELBERG S.’), so the variable ‘a’ in the JavaScript function will have a value of JAWS and the variable ‘b’ in the function will have a value of SPIELBERG S. The alert is the pop up box and is the text in the alert is the piece in the parenthesis. The + is the concatenation symbol in JavaScript.

image So when the user clicks a movie code an alert box pops up, that is the high, a real working piece of JavaScript. Then you come to the low, click on the last item in the list, 963CBS, what happens, depending on your browser settings, you will see an error or nothing. Try the one above, it works okay.  So what has gone wrong.  Look at the view source again and go down to the bottom, the last link has in it - javascript:showDetail(“MICKEY MANTLE’S BASEBALL TIPS2”,’””). The extra single quote in MANTLE’S has upset HTML and JavaScript. This is the sort of thing that can happen, and JavaScript is very unforgiving.

One issue with this is that you normally have to “break out” of the basic TABLE request to achieve a result, as you cannot directly link JavaScript with a TABLE request. One way to get around this is to have a reference to a JavaScript file in the TABLE request itself.

DEFINE FILE MOVIES
.
.
MYJS/A123 = '<script src="pathToFile/myJSFile.js" type="text/javascript"></script>'
END
TABLE FILE MOVIES
PRINT NEWMC
TITLE      NOPRINT
DIRECTOR   NOPRINT
BY    MOVIECODE
HEADING
“<MYJS”
"Simple drill to JavaScript"
.
.
ENDSTYLE
END

 

with the file myJSFile.js containing:
function showDetail(a,b) {
alert("Movie is " + a +", directed by " + b)
}

 

As a point of reference, an html document consists of a series of tags. The first tag in an html document is the <html> tag. Tags are opened and closed. So the <html> has a close tag of </html>, with the slash indicating that this is a closing tag. Most, but not all, tags follow this rule. The next area in a page is enclosed in the <head> tag. This area basically defines items that are not directly shown on the page. The <title> tag is one of these, giving a title to the page, but not in the page. CSS style sheet file references are to be found in the head using a <link> tag, no closing tag. as well as in-line <style> tags. After the <head> is closed, the document itself begins with the <body> tag. JavaScript, within a <script> tag as inline code or as a file reference, can be anywhere in a <head> or <body> tag, whilst CSS style sheets should only be in the <head> area. There are only about 20 basic tags, and most documents use a much smaller subset of that. WebFOCUS report output uses tables, using the <table> tag, with <tr> to define table rows and <td> to define the datacells in a row. Tables can be nested by creating another <table> within a <td> tag. For each of these opening tags there must be a matching close, </td>, </tr> and </table>. Tables are the correct way to show data within a web page, just as you would use a table in a document. The other major tags that are used are <form>, to create an area of data that can be submitted for processing, with various types of <input>.  The input tag is one that does not have an equivalent closing tag, the input is defined totally within the <input> tag itself, <input type=......>.  Many input types are covered in this document. There is the <span> tag for inline text, the <p> tag for a paragraph of text, the <div> tag to declare a page division, splitting the page into sections. There are a series of heading tags, <h1> to <h6> that define different levels of heading within a document. Lists are declared using a <ol>, ordered list, or <ul>, unordered list, with items inside being declared with a <li> tag. All list tags should be closed. The <fieldset> and associated <legend> create a grouping box, the <br>, line break and <hr>, horizontal rule, tags do not having a closing equivalent. Some tags are available to add style to a page, such as <font> and <strong>, these should not be used if possible, the CSS style sheet should be used to style the content of a page.

Often you need the user to enter parameters for a report, this next example shows how to create a web page with the ability to select a value, from a datafile, that can be used for screening in a report request.  The select box is always very popular because it gives the user the ability to select items from a prepared list, ensuring that bad data entry cannot affect the outcome of a report. This also demonstrates the dynamic cohesion between WebFOCUS and HTML.

SET LINES = 99999
DEFINE FILE MOVIES
selectLine/A120='<option value="' || MOVIECODE || '">' || TITLE || '</option>';
END
TABLE FILE MOVIES
WRITE selectLine
BY    selectLine  NOPRINT
ON TABLE SAVE
END
-RUN
-HTMLFORM BEGIN
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>My selection</title>
<link rel=”stylesheet” href=”blue.css type=”text/css”>
</head>
<body>
<div>
<form method="post" name="runForm" id="runForm" action="WFServlet">
<p>
<input type="hidden" name="IBIF_focexec" id="IBIF_focexec" value="myReport">
<label for="movieCode">Select Movie </label>
<select name="movieCode" id="movieCode">
!IBI.FIL.SAVE;
</select>
<input type="submit" name="send" id="send" value="run report">
</p>
</form>
</div>
</body>
</html>
-HTMLFORM END

image 

The TABLE request creates the OPTIONs’ for the SELECT tag. MOVIECODE will be used for screening, but the user sees TITLE.  In the HTML code there is a FORM tag. When the form is submitted, in this case by pressing the submit button, the data in the form is sent to the URL declared in the action. The inputs of type hidden are used to pass information to the server without the user seeing it. In this case the WebFOCUS Servlet gets the data and will run the myReport focexec. That focexec can reference the variable &movieCode, which is the name given to the SELECT on the form (mixed case is carried through), and run a report based on screening of MOVIECODE against &movieCode:
WHERE MOVIECODE EQ ‘&movieCode’;

If the user does not select a value from the list, the first value in the list is used.  If you want a default value then you can insert selected=”selected” within the OPTION at the desired value within the DEFINE, so the end result looks like:
<option value="123CUS" selected=”selected”>USER TEXT</option>

by changing the DEFINE to be:

DEFINE FILE MOVIES
CNTR/I4 WITH MOVIECODE = CNTR + 1;
selectLine/A120= IF CNTR EQ 1 THEN
'<option value="' || MOVIECODE || 'selected=”selected”">' || TITLE || '</option>'
ELSE
'<option value="' || MOVIECODE || '">' || TITLE || '</option>';
END

 

You could of course screen against a known value instead of a counter and have that being the selected item instead.

Rather than using HREF within an A tag to make the call to run a focexec, a FORM is used. The FORM has a method of POST and an action of WFServlet, change this if you use CGI or ISAPI. When the form is submitted, only the items within the form are sent for processing.  Within the page and form are the user input items that are the interface between the program and the user. The POST option allows far greater amounts of data to be sent than the other method, GET, or via an HREF in an A tag.

If you want the user to be able to select more than one value then:

.
.
<select name="movieCode" id="movieCode" size="3" multiple="multiple">
!IBI.FIL.SAVE;
</select>
.
.

image
One or multiple items can be pre-selected for the user using the selected=”selected” parameter.

The size parameter is the number of lines visible in the select, the multiple option allows more than 1 item to be selected. BUT, now a number of &movieCode variables may need to be dealt with, and if only 1 item is selected or no item is selected there are subtle differences. With more than 1 item selected, the variables can be referred to in a focexec as &movieCodenn, where nn is a numeric suffix starting at 1. You can create a loop in DM to read these in to create your screening condition.  However if only one item is selected, then the variable available in the focexec is &movieCode, no numeric suffix. And worse, if no selection is made &movieCode does not exist at all.  So if you are using auto-prompt then you can get the auto-prompt screen when you don’t want one. This uncertainty can make processing in the focexec unwieldy. This is how the process can be handled with JavaScript before the focexec is called (Lines starting // are JavaScript comments):

.
.
-HTMLFORM BEGIN
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>My selection</title>
<link rel=”stylesheet” href=”blue.css type=”text/css”>
<script type="text/javascript">
// After the page has loaded, run setForm to ensure that one item is selected
// This is the same as <body onload=.., but this is my preferred method of processing.
// Not necessary if you set a default in your TABLE request
window.onload = setForm;

function setForm() {
// Called from the window.onload statement.
// Set the first item (referred to as 0) on the list to be the default selected item
// the getElementById method is the way of accessing objects by their unique ids’.
document.getElementById("movieCode").selectedIndex=0;
}

// Called from the button on the form
function processForm() {
// Set up the variables used in the function
var t='';
var s='';
var i=0;
var z=0;

// Get the number of option items in the select.
var numItems = document.getElementById("movieCode").options.length;

// loop through the options, in javascript numbering starts at 0, not 1.
  for (i=0; i<numItems;++i){

// Is this item selected? The item in the list is references with i as the index
// A multiple line IF..THEN..ELSE approach.
    if(document.getElementById("movieCode").options[i].selected == true) {

// Get the value of the selected item
            s = document.getElementById("movieCode").options[i].value;

// Replace single quotes in the value with 2 single quotes, as QUOTEDSTRING would do
            s = s.replace(/'/,"''");

// If this is the first item selected (based on the counter variable z), no OR is necessary,
// and wrap each value in single quotes. If the value is for numeric screening
// do not use the replace or wrap in single quotes. A single line IF..THEN..ELSE approach.
            if (z == 0)
            t= "'" + s + "'";
           else

// not the first item so put an 'OR' in to seperate multiple values.
            t= t + ' OR ' + "'" + s + "'";
      ++z;
    }
  }

// Put the screening condition into repScreen on the form with trailing semicolon
document.getElementById("repScreen").value = t + ‘;’;

// If there are no values selected, tell the user and return to the form without submitting it
// If the window.onload is used to select a value, this is not required.
  if (t == '') {
  alert("An item must be selected to continue");
  return false;
  }

// finally submit the form, runForm is the name of the form.
document.getElementById("runForm").submit();
}

</script>
</head>

<body>
  <div>
    <p>
      <label for="movieCode">Select Movie</label>
    </p>
    <p>
      <select name="movieCode" id="movieCode" size="3" multiple="multiple">
!IBI.FIL.SAVE;
      </select>
    </p>
    <form method="post" name="runForm" id="runForm" action="WFServlet">
      <input type="button" name="send" id="send" value="run report" onclick="processForm()">
      <input type="hidden" name="IBIF_focexec" id="IBIF_focexec" value="myReport">
      <input type="hidden" name="repScreen" id="repScreen" value="">
    </form>
  </div>
</body>
</html>
-HTMLFORM END

 

This example uses JavaScript to process the data from the form before submission.  Now initially you may think that this is complex, but the logic of the processing is exactly the same as the logic you would have in a focexec, the language is just a little different. And there are no issues with &variables existing or not. The parameter &repScreen will be available in the focexec, from the input on the HTML form called repScreen, complete with acceptable quotes and an OR between values. In the HTML you can see that the SELECT is not within the FORM tags and will not be sent when the FORM is submitted; the JavaScript takes the values from the SELECT and places them into a hidden INPUT field, the actual SELECT values are not now required within the focexec being processed.

In JavaScript IF...THEN...ELSE processing can be handled in 2 different ways.

if(condition) {
 code here when condition has passed, true. Single or multiple lines.
} ELSE {
 code here when condition has failed, false. Single or multiple lines.
}

if(condition)
 code here when condition has passed, true. Single line only.
  ELSE
 code here when condition has failed, false. Single line only.

 

The ELSE is optional, not necessary if you don’t need it, and these conditions can be nested. There is also a Boolean approach not covered here.

 

The correct way to reference an item, with an id attribute, on a web page is:
document.getElementById("itemID")

 

The often used approach
document.id.

is only supported by Internet Explorer and is not a W3C standard approach. There are other ways to correctly get hold of an item, but that is too great a task for this article.

From that, I hope you can see that there is nothing to be afraid of in JavaScript. The following examples show how to deal with the different types of user input available on a web page.

.
.
function setForm() {
document.getElementById("movieCode").selectedIndex=0;
}

function processForm() {
var t='';
var i=0;
var z=0;

var numItems = document.getElementById("movieCode").options.length;

  for (i=0; i<numItems;++i){
if(document.getElementById("movieCode").options[i].selected == true) {
s = document.getElementById("movieCode").options[i].value;
s = s.replace(/'/,"''");
if (z == 0)
t= t + "'" + s + "'";
else
t= t + ' OR ' + "'" + s + "'";
++z;
}
}

document.getElementById("repScreen").value = t;

  if (t == '') {
alert("An item must be selected to continue");
return false;
}

// The check box only sends an item if it is checked, to overcome this, a hidden field
// is used to pass to the focexec - checkBoxOut, this has a value of COPIES or ' ', but
// will always exist.

if (document.getElementById("incCopies").checked == true)
  document.getElementById("checkBoxOut").value = document.getElementById("incCopies").value;
    else
  document.getElementById("checkBoxOut").value = ' ';

document.getElementById("runForm").submit();
}
</script>
</head>
<body>
<div>
<p>
<label for="movieCode">Select Movie</label>
</p>
<p>
<select name="movieCode" id="movieCode" size="3" multiple="multiple" tabindex="1">
!IBI.FIL.SAVE;
</select>
</p>
<label for="checkOption">Include stock level? </label>
    <input name="incCopies" id="incCopies" type="checkbox" value="COPIES" tabindex="2">
<br>
<form method="post" name="runForm" id="runForm" action="WFServlet">
<input type="hidden" name="IBIF_focexec" id="IBIF_focexec" value="myReport">
<input type="hidden" name="repScreen" id="repScreen" value="">
<input type="hidden" name="checkBoxOut" id="checkBoxOut" value="">
<fieldset id="myGroup">
     <legend>Report Output</legend>
     <input name="repOutput" id="htmlOut" type="radio" value="HTML" checked="checked" tabindex="3">
       <label for="htmlOut">As Web Page</label><br>
     <input name="repOutput" id="pdfOut" type="radio" value="PDF" tabindex="4">
       <label for="pdfOut">As PDF document</label><br>
     <input name="repOutput" id="excelOut" type="radio" value="EXCEL" tabindex="5">
       <label for="excelOut">As Excel Spreadsheet</label>
    </fieldset><br>
    <label for="textInput">Enter a report Heading</label>
    <input type="text" name="textIn" id="textIn" size="12" maxlength="56" value="" tabindex="6">
    <br>
<input type="button" name="send" id="send" value="run" onclick="processForm()" tabindex="7">
</form>
</div>
</body>
</html>
-HTMLFORM END

 

This example adds the use of the other major inputs onto a form. Radio buttons, check box and plain entry box. Like the multi-select item, radio buttons and check boxes will not automatically send data if there has been no user action and nothing is selected.  Another hidden field, checkBoxOut, is used to pass over the values from the checkbox to the focexec via the JavaScript, and is set to the value of the check box if it is clicked, or blank if not. Here, the &variable in the focexec, &checkBoxOut, will have a value of ‘COPIES’ in it if the box is checked, and could be used directly in the report code as COPIES is a field name in the movies datafile, i.e. PRINT MOVIECODE &checkBoxOut

Radio buttons would also have no value if one was not selected, however in this example one button is checked so a value will be passed to the focexec. It is normal practice to have a default radio button checked. Normally the name of an item and the id are the same, on the radio buttons, there is a difference.  Radio buttons themselves are individual items, to group them together, they are given the same name to make them act together, and this is the name passed to the focexec. The id on each though is different, to enable the label text for each radio button to be linked to the correct button. Additionally, and having no effect on their action, a fieldset tag has been used to surround the buttons with a box, with the text on it provided by the legend tag. Here again the value of the checked radio button is passed across to the focexec and can be used directly in a report request, e.g. ON TABLE PCHOLD FORMAT &repOutput.

A plain text input is used also, <input type ="text" .. with the size parameter, being the width of the input on the page, and the maxlength parameter to restrict the length of the item entered.

The tabindex parameter has been added, this ensures a logical flow from one item to another when the keyboard tab button is pressed.

This is what the last example will look like, using this CSS:
body {
font: normal 8.2pt/7pt  helvetica,arial,sans-serif;
color: #444;
image

margin:110px 0 0 30px;
padding:0;
top:0;
background: #cdeeff url(sky_back.jpg) no-repeat top left;
}
label {
vertical-align:.5ex;
}
fieldset {
width:22em;
margin:2ex 0 0 0;
}
select {
font: normal 8.2pt/9pt  helvetica,arial,sans-serif;
}
#textInput {
margin:2ex 0 0 0;
}
#send {
font-size:98%;
width:10em;
margin:2ex 0 0 10em;
}

A little used, but very useful, approach to select boxes is to separate the items into groups or categories:
image

This can be achieved with the OPTGROUP tag:
.
.
TABLE FILE MOVIES
WRITE MOVIECODE NOPRINT
COMPUTE CNTR/I4 = CNTR + 1;
COMPUTE selectLine/A120=IF LAST CATEGORY EQ CATEGORY THEN
          '<option value="' || MOVIECODE || '">' || TITLE || '</option>'
           ELSE
           IF CNTR EQ 1 THEN
          '<optgroup label="' || CATEGORY || '">' | 
          '<option value="' || MOVIECODE || '">' || TITLE || '</option>';
           ELSE
          '</OPTGROUP>' ||
          '<optgroup label="' || CATEGORY || '">' | 
          '<option value="' || MOVIECODE || '">' || TITLE || '</option>';
BY CATEGORY NOPRINT
BY MOVIECODE NOPRINT
ON TABLE SAVE
END
.
.
<select name="movieCode" id="movieCode" size="3" multiple="multiple" tabindex="1">
!IBI.FIL.SAVE;
 </optgroup>
</select>
.
.

The CATEGORY from the movies file is used to separate the film TITLES into groupings. As you can see from the TABLE request, OPTGROUP cannot be nested so needs to be closed before the next OPTGROUP. The category declared by OPTGROUP cannot be selected by the user.

As a taster to what you could do, the following examples give a more dynamic approach to building your web pages using WebFOCUS code.

TABLE FILE MOVIES
WRITE TITLE
COMPUTE CATCHANGE/A1 = IF CATEGORY EQ LAST CATEGORY THEN 'N' ELSE 'Y';
BY CATEGORY
BY MOVIECODE
ON TABLE SAVE
END
-SET &LOOP = &LINES;
.
.
<select name="movieCode" id="movieCode" size="15" multiple="multiple" tabindex="1">
-SET CNTR = 1;
-REPEAT :SEL_LOOP &LOOP TIMES
-READ SAVE &GRP.8 &CODE.6 &NAME.39 &CHG.1
-SET &htmlLine = IF &CNTR EQ 1 THEN
-          '<optgroup label="' || &GRP || '">' || 
-          '<option value="' || &CODE || '">' || &NAME || '</option>'
-  ELSE
-            IF &CNTR EQ &LOOP THEN
-          '<option value="' || &CODE || '">' || &NAME || '</option>' ||
-          '</optgroup>'
-  ELSE
-            IF &CHG EQ 'Y' THEN
-          '</optgroup>' |
-          '<optgroup label="' || &GRP || '">' || 
-          '<option value="' || &CODE || '">' || &NAME || '</option>'
-  ELSE
-          '<option value="' || &CODE || '">' || &NAME || '</option>';
-SET &CNTR = &CNTR + 1;
&htmlLine

-:SEL_LOOP
      </select>
.

Here we are using Dialogue Manager to loop within the -HTMLFORM labels, building up the web page on the fly.  I know that this is still doing the same thing, creating a select box, but it is the approach I want to demonstrate.  (One system I have holds the data about ALL web pages in a database, and these are built dynamically via a TABLE request and Dialogue Manager, it is a simple way to easily maintain hundreds of different web pages that can be built depending on many factors about the user.) Just be slightly careful with this approach though, as there is no feedback with an ECHO after a -HTMLFORM BEGIN, so if there is an error in your Dialogue Manager, you get no clues as to what went wrong. The previous JavaScript can be used here to prepare the screening &variable.

Sometime there is a requirement for an alternative Drill Down using JavaScript. A successful auto-prompt runs, with the user able to select, from multi-selects, many different values. The report following the auto-prompt screen runs successfully, but a drill down on that report, which uses the same parameters as the auto-prompt, fails. The issue is one of browser limitations. Auto-prompt uses a FORM with a POST method, drill down uses and HREF in an A tag.  The HREF, and the GET method on a form, are limited in the size of the data they can handle.  So auto-prompt, which uses a form POST method works, and the HREF with the same data can fail. To overcome this, the drill down can use JavaScript to call a form.

The first focexec, a summary report using auto-prompt:

-<description>This procedure reports on </description>
-<description>inventory for a movie. </description>
-<heading> Please specify a movie title: </heading>

TABLE FILE MOVIES
SUM COPIES AS ‘Copies’
WHOLESALEPR AS 'Wholesale'
LISTPR/F8.2 AS 'Retail'
ON TABLE SUBHEAD
"Summary Inventory Report"
WHERE TITLE EQ &movieTitle.(OR(FIND TITLE IN MOVIES)).Movie Title.

-* Hold as HTMTABLE, this will then be displayed in myHtmFile.htm
ON TABLE HOLD FORMAT HTMTABLE
ON TABLE SET STYLE *
.
.
TYPE=DATA,
COLUMN=N1,
JAVASCRIPT=runReport,
$
.
.
ENDSTYLE
END
-RUN

-* Set &movieTitle to be passed, properly quoted, to an html form
-SET &VTQ = &movieTitle.QUOTEDSTRING;

-* You cannot use inline html, as this upsets auto-prompt
-HTMLFORM myHtmFile

 

Create a program, myHtmFile.htm. The function runReport in the JavaScript is called from the drill down in the TABLE request.

<html>
<head>
<title>My report</title>
<script>
function runReport(){
document.getElementById("runForm").submit();
}
</script>
</head>
<body>
<form method="post" name="runForm" id="runForm" action="WFServlet">
<input type="hidden" name="IBIF_focexec" id="IBIF_focexec" value="myDetailReport">
<input type="hidden" name="myVar1" id="myVar1" value="!IBI.AMP.VTQ;">
</form>
!IBI.FIL.HOLD;
</body>
</html>

 

And finally, the drill down report - myDetailReport:

TABLE FILE MOVIES
SUM COPIES AS ‘Copies’
WHOLESALEPR AS 'Wholesale'
LISTPR/F8.2 AS 'Retail'
BY CATEGORY AS ‘Category’
BY MOVIECODE AS ‘SKU’
BY TITLE AS ‘Movie Title’
ON TABLE SUBHEAD
"Detail Inventory Report"
WHERE TITLE EQ &myVar1
ON TABLE PCHOLD FORMAT HTML
ON TABLE SET STYLE *
.
.
ENDSTYLE
END

 

You should see here, that the drill down from the first summary report needs to have the same TITLE values passed onto the second, detail report. And if you think that this simple example would work without this technique, of course, you would be right.  But if I tell you that this simple example can use over half the limit of an HREF call, you will see the possible issues, easily overcome with a small bit of hand coding.

This type of method can also be used even if there is no need for a drill down. However normally, instead of using:

 -HTMLFORM filename

use the following allows you to enter your own JavaScript or HTML before or after the main body of the report:
:
TABLE FILE MOVIES
.
.
-HTMLFORM BEGIN
<html>
<head>
<title>My report</title>
<script>
function runReport(){
document.getElementById("runForm").submit();
}
</script>
</head>
<body>
.
.
!IBI.FIL.HOLD;
.
.
</body>
</html>
-HTMLFORM END

 

Now here is the area that can be a real pain: date entry.  There is nothing particularly great in standard HTML and JavaScript to help you, but the kind people at IB provide help here. Many of you may have come across the pop-in calendar in the HTML painter and in Maintain Update Assist, and probably elsewhere.  Here is the simplest way I have found, so far, to integrate it onto your own web pages, this is code lifted from Information Builders, with a complete set of the code for the form examples so far:

SET LINES = 99999
SET HOLDLIST=PRINTONLY
TABLE FILE MOVIES
WRITE TITLE
COMPUTE CATCHANGE/A1 = IF CATEGORY EQ LAST CATEGORY THEN 'N' ELSE 'Y';
BY CATEGORY
BY MOVIECODE
ON TABLE SAVE
END
-SET &LOOP = &LINES;
-RUN
-HTMLFORM BEGIN
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>My selection</title>

<script type="text/javascript">
// Define variable and array for processing calendar
var dyncalendar = "dyncalendar";
var ibiOptions = new Array("cgipath","ibirls","ibilangtrans","dyncalendar");
</script>

// Bring in other required scripts
<script src="/ibi_html/javaassist/nls.js" type=text/javascript>
</script>
<script src="/ibi_html/javaassist/ibi/html/js/ibigbl.js" type=text/javascript>
</script>

// Run, immediately, to set up the style file for the calendar.
<script type=text/javascript>
ibigblloadCss(null);
</script>

<script type="text/javascript">

window.onload=setForm;

function setForm() {
document.getElementById("movieCode").selectedIndex=0;
}

function processForm() {
var t='';
var i=0;
var z=0;

var numItems = document.getElementById("movieCode").options.length;

  for (i=0; i<numItems;++i){

    if(document.getElementById("movieCode").options[i].selected == true) {
s = document.getElementById("movieCode").options[i].value;
s = s.replace(/'/,"''");

            if (z == 0)
t= t + "'" + s + "'";
else
t= t + ' OR ' + "'" + s + "'";
++z;
}
}

document.getElementById("repScreen").value = t;

  if (t == '') {
alert("An item must be selected to continue");
return false;
}

if (document.getElementById("incCopies").checked == true)
document.getElementById("checkBoxOut").value = document.getElementById("incCopies").value;
else
document.getElementById("checkBoxOut").value = ' ';
document.getElementById("runForm").submit();
}
</script>

<link  rel="stylesheet" href="blue.css" type="text/css">
</head>

<body>
<div>
<p>
<label for="movieCode">Select Movie</label>
</p>
<p>
<select name="movieCode" id="movieCode" size="10" multiple="multiple" tabindex="1">
!IBI.FIL.SAVE;
</select>
</p>
<label for="checkOption">Include stock level? </label>
<input name="incCopies" id="incCopies" type="checkbox" value="COPIES" tabindex="2"><br>
<form method="post" name="runForm" id="runForm" action="../../ibi_apps/WFServlet">
<input type="hidden" name="IBIF_focexec" id="IBIF_focexec" value="test14">
<input type="hidden" name="repScreen" id="repScreen" value="">
<input type="hidden" name="checkBoxOut" id="checkBoxOut" value="">
<fieldset id="myGroup">
<legend>Report Output</legend>
<input name="repOutput" id="htmlOut" type="radio" value="HTML" checked="checked" tabindex="3">
<label for="htmlOut">As Web Page</label><br>
<input name="repOutput" id="pdfOut" type="radio" value="PDF" tabindex="4">
<label for="pdfOut">As PDF document</label><br>
<input name="repOutput" id="excelOut" type="radio" value="EXCEL" tabindex="5">
<label for="excelOut">As Excel Spreadsheet</label>
</fieldset><br>
<label for="textInput">Enter a report Heading</label>
<input type="text" name="textIn" id="textIn" size="12" maxlength="56" value="" tabindex="6">
<br><br>
<label for="calendarInput">Enter date (dd/mm/yyyy)</label>
<input id=calendarInput tabIndex=1 name=calendarInput size="9"  maxlength="10">
<script type=text/javascript>
// Set up new attributes for the input and run functions to set up and position calendar.
// This script MUST come right after the input box for the date, to position the icon correctly.           
document.getElementById("calendarInput").setAttribute("ibiformat","DMYY");
document.getElementById("calendarInput").setAttribute("calendardatatype","0");
document.getElementById("calendarInput").setAttribute("calendardata","0/0/-1;0/30/0");
if(ibigblInitInfo.testOptions(dyncalendar)){
setDateRange();
setupDocCalendars();
}
</script>
<br>
<input type="button" name="myBut" id="myBut" value="run report" onclick="processForm()"
tabindex="7">
</form>
</div>
</body>
</html>
-HTMLFORM END

 

This extra code will provide a data entry input box, a small icon will be placed alongside by the JavaScript. When the user clicks the icon a pop-in calendar appears, allowing the user to select a date which, when clicked, populates the input box with that date.

First, the order of the scripts and where they appear on the page is essential. Any change, I’m afraid, can be fatal. However, the order is simple.  The first parts at the top, straight after the title, then the second JavaScript straight after the date input field.

The date format you want can be set in the line:
document.getElementById("calendarInput").setAttribute("ibiformat","DMYY");
changing the DMYY to MDYY or whichever valid WebFocus format you need.

The period shown by the pop-in calendar can be changed on the line:
document.getElementById("calendarInput").setAttribute("calendardata","1/1/2007;12/31/2007");

in MDYY format only, from date as the first part, to date as the second. This could also be set using start and end dates from &variables.
document.getElementById("calendarInput").setAttribute("calendardata","!IBI.AMP.sDT;!IBI.AMP.eDT");

 

The attribute calendardatatype affects the calendardata attribute. Set to 0, then the calendardata dates are absolute. Set to 1 and the date is relative, so 0/0/-1 as the first parameter in calendardata would refer to the number of months/days/years for the calendar to show from, in this case back one year, and 0/30/0 as the second parameter would refer to the months/days/years for the calendar to show ahead, in this case ahead 30 days.

If you don’t want to allow users to enter a date, but only choose from the calendar, place a disabled=”disabled” attribute on the text input.

And this is how the final example will look, after the user has pressed the calendar icon:

image

That’s it. This is a simple introduction to help you get the most from your applications. Further reading about HTML and JavaScript is always available on the internet.
image
imageAbout the author: Alan Bell started with computers in 1971 on an Elliot 903, progressing through an ICL 1900 with George 2, IBM 4341 with DOS/VSE, CP/M, MP/M and MSDOS, teaching COBOL, Basic and Assembler until he joined Information Builders in the UK in 1985. He stayed with Information Builders for almost 10 years before becoming a free-lance consultant and trainer for the IB product set, working on all the major hardware platforms, though now primarily Windows. He has lived in the Portuguese Algarve since 2002, enjoying views of the ocean and mountains from his office, which is why he spends so much time in there.
Contact : AlanInPortugal@btinternet.com