views:

245

answers:

4

I want to have a cgi-script that does two things.

  1. Take the input from a form.
  2. Generate results base on the input values on a frame.

I also want the frame to exist only after the result is generated/printed.

Below is the simplified code of what I want to do. But somehow it doesn't work. What's the right way to do it?

    #!/usr/local/bin/perl

    use CGI ':standard';

    print header;
    print start_html('A Simple Example'),
        h1('A Simple Example'),
        start_form,
        "What's your name? ",textfield('name'),
        p,
        "What's the combination?",
        p,
        checkbox_group(-name=>'words',
               -values=>['eenie','meenie','minie','moe'],
               -defaults=>['eenie','minie']),
        p,
        "What's your favorite color? ",
        popup_menu(-name=>'color',
               -values=>['red','green','blue','chartreuse']),
        p,
        submit,
        end_form,
        hr;

    if (param()) {

        # begin create the frame

print <<EOF;
<html><head><title>$TITLE</title></head>
<frameset rows="10,90">
<frame src="$script_name/query" name="query">
<frame src="$script_name/response" name="response">
</frameset>
EOF

# Finish creating frame


        print 
        "Your name is: ",em(param('name')),
        p,
        "The keywords are: ",em(join(", ",param('words'))),
        p,
        "Your favorite color is: ",em(param('color')),
        hr;
    }
    print end_html;
+1  A: 

If you want to change the structure of the page displayed in the user's browser (i.e., creating a frame when a form is submitted which didn't previously exist), you're going to have to use client-side javascript to do it. This could be as simple as having the frame present but visible and showing it when the form is submitted, or it could involve DOM manipulation to actually create it.

Depending on your specific requirements, though, you'd probably be better off to use an empty <div> instead of a frame and populate it via AJAX; CGI::Ajax would be the easiest approach to doing this. Since you'll need to use javascript anyhow (to reveal or create the frame), an AJAX-based approach won't add any new requirements for users of your site.

Edit: Wow... Any explanation for the drive-by downvotes? Do you think I failed to answer the question? Am I just plain wrong? Enlighten me!

Dave Sherohman
This has been happening on SO lately. Just blame it on SO douchebaggery. I feel what you are saying and both your answer and brians would work imo. I +1'ed you but also notice this question also got a downvote. I think SO is full of a-holes lately.
DJTripleThreat
Thanks, @DJTripleThreat, but it's not about the points (I've got enough of 'em already). I just want to know about it if I'm wrong.
Dave Sherohman
Yeah I understand. For me it is about the points sometimes because it actually affects my usability and what I can and cannot do on SO because I'm only at 350+ So if somebody decided to downvote me to be a jerk then I can loose an option to create useful tags for example. You feel me? I think they need to make it a requirement to leave comment as to why you get downvoted on SO, because people are just doing it to piss others off. Look at this perl question for example. Its totally valid, so why downvote it? There's no reason to other then to be a dick.
DJTripleThreat
http://meta.stackoverflow.com/questions/22934/so-annoyed-with-no-comment-vindictive-downvoting
Kevin Panko
+3  A: 

An HTML frameset reference other documents. You don't create them all in one go and send them all to the user-agent in a single response. Print the frameset and frame references only, and the browser will do the extra work to fetch each frame individually.

Read up on how framesets work:

brian d foy
+1  A: 

Asker says:

I also want the frame to exist only after the result is generated/printed.

This makes it tricky, despite that CGI.pm does have support for frames. You didn't cite why you want to use a frameset, so you'll have to decide whether using a frameset approach is really worth the trouble.

You need to use conditionals and supplemental info to control what is output when: when the query form is printed, when the frameset is printed, and when the individual frames are printed. The trick is to output the frameset at the desired time with the frames pointed at back at the script with pathinfo to indicate which HTML/frame to output.

First, see about CGI.pm support for frames here:

Using frames effectively can be tricky. To create a proper frameset in which the query and response are displayed side-by-side requires you to divide the script into three functional sections. The first section should create the declaration and exit. The second section is responsible for creating the query form and directing it into the one frame. The third section is responsible for creating the response and directing it into a different frame.

I tried to modify http://stein.cshl.org/WWW/CGI/examples/frameset.txt to try to do what you want to do, but I haven't/can't test it (no CGI.pm server readily available). I seriously doubt it will work without some debugging. But hopefully, this gives you the basic idea to run with it. First study http://stein.cshl.org/WWW/CGI/examples/frameset.txt and then see my changes below:

#!/usr/local/bin/perl

### UNTESTED CODE ###

use CGI;
$query = new CGI;
print $query->header;
$TITLE="Frameset Example";

# We use the path information to distinguish between calls
# to the script to:
# (1) create the frameset
# (2) create the query form
# (3) create the query response

$path_info = $query->path_info;

# If no path information is provided, then we create 
# print query form            ###new####
# a side-by-side frame set    ###old###
if (!$path_info) {
    #&print_frameset;   ###old### 
    &print_html_header; ###new###
    &print_query        ###new###
    &print_end;         ###new###
    exit 0;
}

# If response path             ###new###
if ($path_info=~/response/) {  ###new###
    &print_frameset;           ###new###
    exit 0;                    ###new###
}                              ###new###

# If we get here, then we either create the query form
# or we create the response.
&print_html_header;
#&print_query if $path_info=~/query/;             ###old###
#&print_response if $path_info=~/response/;       ###old###
&print_query if $path_info=~/frame-query/;        ###new###
&print_response if $path_info=~/frame-response/;  ###new###
&print_end;


# Create the frameset
sub print_frameset {
    $script_name = $query->script_name;
    print <<EOF;
<html><head><title>$TITLE</title></head>
<frameset cols="50,50">
<!--frame src="$script_name/query" name="query"-->           <!--###old###-->
<!--frame src="$script_name/response" name="response"-->     <!--###old###-->
<frame src="$script_name/query" name="frame-query">          <!--###new###-->
<frame src="$script_name/response" name="frame-response">    <!--###new###-->
</frameset>
EOF
    ;
    exit 0;
}

sub print_html_header {
    print $query->start_html($TITLE);
}

sub print_end {
    print qq{<P><hr><A HREF="../index.html" TARGET="_top">More Examples</A>};
    print $query->end_html;
}

sub print_query {
    $script_name = $query->script_name;
    print "<H1>Frameset Query</H1>\n";
    #print $query->startform(-action=>"$script_name/response",-TARGET=>"response");   ###old###
    print $query->startform(-action=>"$script_name/response");  ###new###
    print "What's your name? ",$query->textfield('name');
    print "<P>What's the combination?<P>",
    $query->checkbox_group(-name=>'words',
          -values=>['eenie','meenie','minie','moe']);

    print "<P>What's your favorite color? ",
    $query->popup_menu(-name=>'color',
         -values=>['red','green','blue','chartreuse']),
    "<P>";
    print $query->submit;
    print $query->endform;
}

sub print_response {
    print "<H1>Frameset Result</H1>\n";
    unless ($query->param) {
 print "<b>No query submitted yet.</b>";
 return;
    }
    print "Your name is <EM>",$query->param(name),"</EM>\n";
    print "<P>The keywords are: <EM>",join(", ",$query->param(words)),"</EM>\n";
    print "<P>Your favorite color is <EM>",$query->param(color),"</EM>\n";
}
Bert F
+2  A: 

Asker says:

I also want the frame to exist only after the result is generated/printed.

This makes it tricky, despite that CGI.pm does have support for frames. You didn't cite why you want to use a frameset, so you'll have to decide whether using a frameset approach is really worth the trouble.

One option is to fake it with a hidden frame.

You may need to see:

  1. First, see about CGI.pm support for frames here
    Doc - http://stein.cshl.org/WWW/CGI/#frames
    Example - http://stein.cshl.org/WWW/CGI/examples/frameset.txt
    Try - http://stein.cshl.org/WWW/CGI/examples/frameset.pm

    Using frames effectively can be tricky. To create a proper frameset in which the query and response are displayed side-by-side requires you to divide the script into three functional sections. The first section should create the declaration and exit. The second section is responsible for creating the query form and directing it into the one frame. The third section is responsible for creating the response and directing it into a different frame.

  2. See this reference for modifying a frameset dynamically:

    One reference - http://www.codeguru.com/forum/archive/index.php/t-373259.html
    Other references - http://www.google.com/search?q=javascript+dynamically+resize+frameset+cols

    a. So first you'll create the frameset initially, but hide the response frame:

    <frameset rows="100%,*">`  
    

    b. Then later use javascript to dynamically resize the frames. Using the code from http://stein.cshl.org/WWW/CGI/examples/frameset.txt as an example, you'd have to modify print_response routine to output the javascript to modify the frameset to resize the frames (i.e. expose your hidden response frame):

    parent.document.getElementsByTagName("FRAMESET").item(1).cols = '10,90';
    
Bert F