Digital Media

Moshell - Spring 99

Lecture 8: Advanced  Form Techniques; Dynamic Graphics

This lecture covers two topics: Advanced Form Techniques, and Dynamic Graphics. Dynamic Graphics concerns software which draws pictures as you need them. We normally think of this as a Java-ish kind of thing to do, but CGI can do it too. You'll learn how, later in the lesson. First, however, the forms!

We use Castro's book, Chapter 12, in this lecture.

Advanced Forms: The Master Form Technique

The advanced form technique in which I'm most interested, is the one which I described earlier in class: how do you build a server which can read files containing special HTML (e. g. to provide a "catalog" of products), mix this information with a current price table, and emit a working form? I call this the Master Form technique.

Commercial products such as Cold Fusion can be used to realize this result. Cold Fusion is "middleware", which is to say, software that does more than canned programs can do, but supposedly requires less effort than programming would require. Since you're mostly computer science majors rather than Management Information Science canned- program- majors, I'm going to teach you the Macho Way to Program It Yourself.

Unfortunately, I have found no way to use CGI.pm to support the Master Form technique. CGI.pm presumes that you are going to represent your form directly in Perl, with CGI.pm function calls being used to construct the strings that you print out to make the HTML. CGI.pm is best used for those portions of one's on-line commerce system that concern getting the user's name, address and payment information - the parts that don't change much from one month to another. You can use Master Forms alongside CGI.pm, as we will see.

If we want to be able to read a master form, insert prices into it and then emit it, there are great advantages to being able to have the master form itself be in HTML - or close to it. You can use tools like Netscape Composer or even Microsoft Word (shudder)  to lay out nice-looking forms - or at least the tables, captions and graphics which make the forms look nice. You will then have to hand-edit the HTML to insert the input fields, pulldown menus, etc. that you need. Finally you will insert the control markers that show your script where to stick in pricing and inventory information.

 Master Forms

This section involves a script which dynamically modifies a master document, converting non-HTML into legitimate HTML. The two choices are
 

I personally prefer the second technique, because it makes life simpler when using the "split" command.

A warmup exercise. To begin with, we need some practice with hash tables and search patterns. Let's assume that you have code (I gave it to you last week) which can read key=value pairs from a text file and put them into a hash named %salary. So, for instance, if you executed

print $salary{"Smith,John"};

you should see printed

24000

In another array named @employees, you have a list of the employees' names, in the form shown above, without spaces, like this:

Lastname,Firstname

Write a simple code loop which would produce a HTML table displaying all your employees and their salaries.

A second exercise. Write code which goes through an array @text, each element of which is a string. Your routine prints out these lines, after modifying them as follows. Any time a phrase of the following form is encountered, the stuff between the double tildes is replaced by HONK HONK.

This is a ~~sample phrase~~ embedded in a line of text.

After your routine runs, this line is printed out as

This is a HONK HONK embedded in a line of text.

If you get stuck here, there is a hint below, titled HINT FOR SECOND EXERCISE.

Main Design Exercise.

If you understood what you did in the above two exercises, you're now ready for the design problem of the day.

The Widget Company wants to develop a server which can put up any catalog page, and insert into the page the current price and inventory information. It is also desired to be able to put up "special notices", such as flagging an item as being on closeout.

Therefore, we will have three associative arrays pre-loaded with data:

$PRICE{$item}, $INVENTORY{$item} and $SPECIAL{$item}.

The $item selector will consist of a product code, which is of form ‘C4324-5’, so we have to treat it as a string.

We want three kinds of tags that we can embed in our master form. Since the 'tilde' character ~ has no business occurring twice in normal HTML, we use it to define some special flags, as follows:

~~pC4324-5~~p will cause the price of that product to be displayed.

~~iC4324-5~~i will cause the inventory of that product to be displayed, and

~~sC4324-5~~s will cause that product’s special information – including any imbedded HTML-to be displayed.

Your code simply reads through the master form (using a while loop or a foreach loop), performs the necessary substitutions, and emits the resulting code. It's up to you to decide how you want to read the master form file into the program- one line at a time, or the whole thing into an array.

Here's an example of a very small Master Form for use with the above technique. It uses only the price insertion system.
You should probably develop the code for one tag first (like price), and then after your group agrees that this is the way to go, modify it to handle three tags. The easiest way to do three tags is just to take three passes through each line of the data.

***********************************************
<html>
<head><title>The Widget Company Online Catalog</title>
</head>
<body>
<form METHOD=POST ACTION="http://www.creat.cas.ucf.edu/~schmoe/cgi-bin/cgiwrap/exercise1.pl">
<h1>Please Tell Us About Yourself</h1>
<p>
Your last name? <input size=25 maxlength=25 name="lastname">
<! put all kinds of address fields here.>
<p>
<h1>Today We Sell Two Things Proudly</h1>
Please type the desired quantity of each item in the space next to its description.
<p>
<table>
<tr>
<td>Acme Widgets, One Size Fits All: ~~pwidget~~p </td><td>
<input size=5 maxlength=5 name="widgets" > </td></tr>
<tr>
<td> Widget Cleaner: ~~pcleaner~~p</td><td>
<input size=5 maxlength=5 name="cleaners" > </td></tr>
</table>
<input TYPE="submit" NAME=SubmitAction VALUE="Submit Your Order">
</body>
</html>
**************************************************

***********************
***********************
HINT FOR SECOND EXERCISE: Use the split operator on your working variable ($textline, perhaps) to split it into three pieces: head, middle and tail. Then print out head, HONK HONK and tail.
***********************
***********************

The Problem of Persistence. (Chapter 12 of Castro's book.)

You will (if thoroughly sober and awake) perhaps remember that one of the main reasons for introducing the CGI.pm library was to make it easy to have forms which 'return from the dead' - that is, when you run your server to error check the forms, and re-emit the form, its previous values are automatically in place. This technique only works if you are always re-displaying every field in your form, however. Let's review WHERE the data is, at any given time.

CLIENT: REQUEST THE FORM. Your browser accesses a URL which might contain the source document itself, or might access a server that makes up the form. The form may come to you with default values in some fields.

CLIENT: INITIAL FORM-FILLING. You type in values, or click buttons or pull down menus, to specify values for each variable. These are transmitted in the output url-encoded stream as key-value pairs, like

lastname=Moshell&firstname=J.+Michael

with + replacing spaces, as we mentioned before.

SERVER:INITIAL CHECKING. The server first reads the form into a key-value hash. If you're using CGI.pm in functional form, it's a hidden hash which we refer to via its accessor function param(). Or maybe you wrote your own code to read it into %FORM. This is a good idea, if you're going to use the Master Form technique.

Now the server checks what your user did. If they did everything right, you can proceed to the next step, using the information from %FORM. But let's assume that you find a problem with one of the forms, and want to send the user an error screen. You need to stash everything in %FORM somewhere. You decide to send it back to the client, in hidden variables, so it'll come back in again when they acknowledge their error.

Here's a code loop stolen and modified from Castro's page 164:

foreach $key (keys %FORM)
{
    print "<INPUT TYPE=hidden NAME=$key VALUE=$FORM{$key}>\n";
}

You include this along with the various Print commands which tell the user what is wrong. Perhaps that screen says

*******************

Sorry, customer. You ordered more widgets than we have.
We only have 12 widgets in stock. Please select one of the
following options:
(Partial order) We ship you 12 widgets now and the rest when we get them.
(Delay order) We wait until we have them all, and ship them to you later.
(Cancel order) We forget you ever contacted us.
********************
The phrases in parentheses appear inside buttons, which are actually SUBMIT buttons. You specify their captions with the VALUE tag. In the above example, I also provided NAME=SubmitAction, to show you the syntax. If you used three such buttons on this form,  the form would return

SubmitAction=Partial+order
or
SubmitAction=Delay+order
or
SubmitAction=Cancel+order

depending on which Cancel button is pushed.

Now, hidden inside the above form, we have stashed all the information about lastname, firstname, address, etc. because of the foreach $key loop. So, when your user hits any one of the Submit keys, the whole form pours back into the server.

SERVER: RECEIVING RESPONSE FROM BOOBOO SCREEN. When the server reads the response, it streams the whole thing into $FORM again. But since you had hidden variables, it gets not only the SubmitAction=something pair, but also lastname=Moshell&firstname=Michael& whatever else was in the original form.

Now if you are smart, you will set up your form so that if and when it is re-presented to the client, the user's lastname reappears! By now, with your familiarity with our double tilde imbedding technique, you can probably figure out exactly how that's done.

Exercise 3: How do we emit a form so that any existing values in $FORM are inserted as default values, just as though we were playing the role of CGI.pm? Write down a line of HTML which (if properly treated by your script) would restore the user's last name.

Now describe, in English or Perl, what you should be putting into the place where the tag is removed by your server. A hint is found below the section on graphics, which is coming right up.
 

Dynamic Graphics, Part 1

Special Printing Commands. The following example uses a Perl shorthand: Instead of having to type

print "line 1\n";
print "line 2\n"; etc, etc.,
you can do the following:

print <<EndMarker
    line 1
    line 2
    whatever you want to print
EndMarker

When the symbol that you declared right after << occurs, the input to the print statement terminates (without, obviously, printing EndMarker.)

Animation can be accomplished by Java or Javascript, with the advantage that you are not waiting on the Internet’s highly variable timing. However, if you are trying to animate something that depends on new data - such as a stock ticker tape - you have to ask the server for information anyhow. So Java has no special advantage in that case.

Animation can be controlled by the client or the server. If the client asks to run a script over and over, that would obviously produce animation - if the server sent up something different each time. Another way to (passively) produce animation is to use an animated GIF, which actually stores different information in each of several frames. But that would hardly work for a stock ticker tape, would it? So we have to establish a repetitive dialog of some kind, between the client and server.

Client Pull. To ask for a script-generated graphical image, one simply calls the script that's supposed to draw or supply the image,  inside an IMG tag, like this:

print <<End_of_HTML;

... various HTML details

... down to:

<IMG SRC="/cgi-bin/digital.pl">

....some more HTML

End_of_HTML

This will, however, only get ONE copy of the image. (We'll discuss in a later lecture,  how your script can actually create an image.) To get multiple copies, you have to tell the browser to repeatedly ask for the document, like this:

<META HTTP-EQUIV="Refresh" CONTENT=5>

This will generate a call every 5 seconds, by the brute force method of re-fetching and rendering the entire HTML document - including its dynamic call or calls. In fact, Refresh only works once. But in the new copy of the HTML that is fetched, there should be embedded another identical copy of the Refresh meta-command.

Server Push. If the browser is "warned" to stay open to continuous input, the server can be set up to send the animation information continuously. Here’s the setup command:

Content-type: multipart/x-mixed-replace; boundary=End

--End

Content-type: image/gif

Image #1

--End

Content-type: image/gif

Image #2

--End

...

--End--

The first line declares that each successive image will end with the characters "--End". This continues until the boundary symbol appears with two "-" characters on either side of it - like --End-- Everything else that came in, before --End, was interpreted as bytes of a GIF image.

The server push example code:
******************************************************************
#!usr/local/bin/perl
$|=1;
$webmaster="shishir/@bu\.edu";

$boundary_string="\n"."--End"."\n";
$end_of_data = "\n"."--End--"."\n";
$delay_time = 1;

@image_list = ("image_1.gif", image_2.gif","image_3.gif","image_4.gif","image_5.gif")

$browser = $ENV{‘HTTP_USER_AGENT’};

for ($loop=0; $loop<scalar(@image_list); $loop++)

{

    &open_and_display_GIF($image_list[$loop]);
    print $boundary_string;
    sleep($delay_time);

}

print $end_of_data;

exit (0);

####################

sub open_and_display_GIF

{

local ($file) = $_;
local ($content_length);
if ((open (FILE, "<". $file))

{

    $content_length = (stat (FILE) [7]); # The 7 denotes file length. See comments below for  other file stats.
    print "Content-type: image/gif", "\n";
    print "Content-length:",$content_length, "\n\n";
    print <FILE>;
    close (FILE);

}

else

{
    print  "File Access Error - Cannot open graphic file $file!\n";
}

}# End open_and_display_GIF
# End of server-push example code

******************************************************************
In our next CGI lecture, we'll explore "GhostScript" which is a tool whereby Perl can create GIF images from scratch. It's a kind of Postscript interpreter.

***********************
***********************

HINT FOR THIRD EXERCISE: [Heck, it's almost the ANSWER to Exercise 3.] Your tag for this purpose, which might look like ~~vlastname~~v, will be replaced (by your script) by this:

value="Moshell"

assuming that $FORM{"lastname"} was Moshell at that point. The main thing that ~~v does differently from ~~p or ~~i or any other tag, is that it must stick in both the value from %FORM and the keyword "value=" to make it all work.

Now of course this little snippet is going into an <input ....> field, so you still have some work to do, to get it right.

***********************
***********************
 

Back to previous lecture
Forward to next lecture
Back to the Index
Back to the Syllabus