4 use base qw(Class::Accessor);
 
   5 use overload '""' => 'show_javascript'; # for building web pages, so
 
   6                                         # you can just say: print $pjx
 
   8         use vars qw ($VERSION @ISA @METHODS);
 
   9         @METHODS = qw(url_list coderef_list DEBUG JSDEBUG html
 
  10                                                                 js_encode_function cgi_header_extra);
 
  12         CGI::Ajax->mk_accessors( @METHODS );
 
  17 ########################################### main pod documentation begin ##
 
  21 CGI::Ajax - a perl-specific system for writing Asynchronous web
 
  27   use CGI;      # or any other CGI:: form handler/decoder
 
  31   my $pjx = new CGI::Ajax( 'exported_func' => \&perl_func );
 
  33   print $pjx->build_html( $cgi, \&Show_HTML);
 
  37     # do something with $input
 
  38     my $output = $input . " was the input!";
 
  47         <input type="text" name="val1" id="val1"
 
  48          onkeyup="exported_func( ['val1'], ['resultdiv'] );">
 
  50       <div id="resultdiv"></div>
 
  57 I<There are several fully-functional examples in the 'scripts/'
 
  58 directory of the distribution.>
 
  62 CGI::Ajax is an object-oriented module that provides a unique
 
  63 mechanism for using perl code asynchronously from javascript-
 
  64 enhanced HTML pages.  CGI::Ajax unburdens the user from having to
 
  65 write extensive javascript, except for associating an exported
 
  66 method with a document-defined event (such as onClick, onKeyUp,
 
  67 etc).  CGI::Ajax also mixes well with HTML containing more complex
 
  70 CGI::Ajax supports methods that return single results or multiple
 
  71 results to the web page, and supports returning values to multiple
 
  72 DIV elements on the HTML page.
 
  74 Using CGI::Ajax, the URL for the HTTP GET/POST request is
 
  75 automatically generated based on HTML layout and events, and the
 
  76 page is then dynamically updated with the output from the perl
 
  77 function.  Additionally, CGI::Ajax supports mapping URL's to a
 
  78 CGI::Ajax function name, so you can separate your code processing
 
  79 over multiple scripts.
 
  81 Other than using the Class::Accessor module to generate CGI::Ajax'
 
  82 accessor methods, CGI::Ajax is completely self-contained - it
 
  83 does not require you to install a larger package or a full Content
 
  84 Management System, etc.
 
  86 We have added I<support> for other CGI handler/decoder modules,
 
  87 like L<CGI::Simple> or L<CGI::Minimal>, but we can't test these
 
  88 since we run mod_perl2 only here.  CGI::Ajax checks to see if a
 
  89 header() method is available to the CGI object, and then uses it.
 
  90 If method() isn't available, it creates it's own minimal header.
 
  92 A primary goal of CGI::Ajax is to keep the module streamlined and
 
  93 maximally flexible.  We are trying to keep the generated javascript
 
  94 code to a minimum, but still provide users with a variety of
 
  95 methods for deploying CGI::Ajax. And VERY little user javascript.
 
  99 The CGI::Ajax module allows a Perl subroutine to be called
 
 100 asynchronously, when triggered from a javascript event on the
 
 101 HTML page.  To do this, the subroutine must be I<registered>,
 
 104   my $pjx = new CGI::Ajax( 'JSFUNC' => \&PERLFUNC );
 
 106 This maps a perl subroutine (PERLFUNC) to an automatically
 
 107 generated Javascript function (JSFUNC).  Next you setup a trigger this
 
 108 function when an event occurs (e.g. "onClick"):
 
 110   onClick="JSFUNC(['source1','source2'], ['dest1','dest2']);"
 
 112 where 'source1', 'dest1', 'source2', 'dest2' are the DIV ids of
 
 113 HTML elements in your page...
 
 115   <input type=text id=source1>
 
 116   <input type=text id=source2>
 
 120 L<CGI::Ajax> sends the values from source1 and source2 to your
 
 121 Perl subroutine and returns the results to dest1 and dest2.
 
 123 =head2 4 Usage Methods
 
 127 =item 1 Standard CGI::Ajax example
 
 129 Start by defining a perl subroutine that you want available from
 
 130 javascript.  In this case we'll define a subrouting that determines
 
 131 whether or not an input is odd, even, or not a number (NaN):
 
 141     # see if input is defined
 
 142     if ( not defined $input ) {
 
 143       return("input not defined or NaN");
 
 146     # see if value is a number (*thanks Randall!*)
 
 147     if ( $input !~ /\A\d+\z/ ) {
 
 148       return("input is NaN");
 
 151     # got a number, so mod by 2
 
 152     $input % 2 == 0 ? return("EVEN") : return("ODD");
 
 155 Alternatively, we could have used coderefs to associate an
 
 158   my $evenodd_func = sub {
 
 159     # exactly the same as in the above subroutine
 
 162 Next we define a function to generate the web page - this can
 
 163 be done many different ways, and can also be defined as an
 
 164 anonymous sub.  The only requirement is that the sub send back
 
 165 the html of the page.  You can do this via a string containing the
 
 166 html, or from a coderef that returns the html, or from a function
 
 172   <HEAD><title>CGI::Ajax Example</title>
 
 175     Enter a number: 
 
 176     <input type="text" name="somename" id="val1" size="6"
 
 177        OnKeyUp="evenodd( ['val1'], ['resultdiv'] );">
 
 188 The exported Perl subrouting is triggered using the C<OnKeyUp>
 
 189 event handler of the input HTML element.  The subroutine takes one
 
 190 value from the form, the input element B<'val1'>, and returns the
 
 191 the result to an HTML div element with an id of B<'resultdiv'>.
 
 192 Sending in the input id in an array format is required to support
 
 193 multiple inputs, and similarly, to output multiple the results,
 
 194 you can use an array for the output divs, but this isn't mandatory -
 
 195 as will be explained in the B<Advanced> usage.
 
 197 Now create a CGI object and a CGI::Ajax object, associating a reference
 
 198 to our subroutine with the name we want available to javascript.
 
 201   my $pjx = new CGI::Ajax( 'evenodd' => \&evenodd_func );
 
 203 And if we used a coderef, it would look like this...
 
 205   my $pjx = new CGI::Ajax( 'evenodd' => $evenodd_func );
 
 207 Now we're ready to print the output page; we send in the cgi
 
 208 object and the HTML-generating function.
 
 210   print $pjx->build_html($cgi,\&Show_HTML);
 
 212 CGI::Ajax has support for passing in extra HTML header information
 
 213 to the CGI object.  This can be accomplished by adding a third
 
 214 argument to the build_html() call.  The argument needs to be a
 
 215 hashref containing Key=>value pairs that CGI objects understand:
 
 217   print $pjx->build_html($cgi,\&Show_HTML,
 
 218     {-charset=>'UTF-8, -expires=>'-1d'});
 
 220 See L<CGI> for more header() method options.
 
 222 That's it for the CGI::Ajax standard method.  Let's look at
 
 223 something more advanced.
 
 225 =item 2 Advanced CGI::Ajax example
 
 227 Let's say we wanted to have a perl subroutine process multiple
 
 228 values from the HTML page, and similarly return multiple values
 
 229 back to distinct divs on the page.  This is easy to do, and
 
 230 requires no changes to the perl code - you just create it as you
 
 231 would any perl subroutine that works with multiple input values
 
 232 and returns multiple values.  The significant change happens in
 
 233 the event handler javascript in the HTML...
 
 235   onClick="exported_func(['input1','input2'],['result1','result2']);"
 
 237 Here we associate our javascript function ("exported_func") with
 
 238 two HTML element ids ('input1','input2'), and also send in two
 
 239 HTML element ids to place the results in ('result1','result2').
 
 241 =item 3 Sending Perl Subroutine Output to a Javascript function
 
 243 Occassionally, you might want to have a custom javascript function
 
 244 process the returned information from your Perl subroutine.
 
 245 This is possible, and the only requierment is that you change
 
 246 your event handler code...
 
 248   onClick="exported_func(['input1'],[js_process_func]);"
 
 250 In this scenario, C<js_process_func> is a javascript function you
 
 251 write to take the returned value from your Perl subroutine and
 
 252 process the results.  I<Note that a javascript function is not
 
 253 quoted -- if it were, then CGI::Ajax would look for a HTML element
 
 254 with that id.>  Beware that with this usage, B<you are responsible
 
 255 for distributing the results to the appropriate place on the
 
 256 HTML page>.  If the exported Perl subroutine returns, e.g. 2
 
 257 values, then C<js_process_func> would need to process the input
 
 258 by working through an array, or using the javascript Function
 
 261   function js_process_func() {
 
 262     var input1 = arguments[0]
 
 263     var input2 = arguments[1];
 
 264     // do something and return results, or set HTML divs using
 
 266     document.getElementById('outputdiv').innerHTML = input1;
 
 269 =item 4 URL/Outside Script CGI::Ajax example
 
 271 There are times when you may want a different script to
 
 272 return content to your page.  This could be because you have
 
 273 an existing script already written to perform a particular
 
 274 task, or you want to distribute a part of your application to another
 
 275 script.  This can be accomplished in L<CGI::Ajax> by using a URL in
 
 276 place of a locally-defined Perl subroutine.  In this usage,
 
 277 you alter you creation of the L<CGI::Ajax> object to link an
 
 278 exported javascript function name to a local URL instead of
 
 279 a coderef or a subroutine.
 
 281   my $url = 'scripts/other_script.pl';
 
 282   my $pjx = new CGI::Ajax( 'external' => $url );
 
 284 This will work as before in terms of how it is called from you
 
 287   onClick="external(['input1','input2'],['resultdiv']);"
 
 289 The other_script.pl will get the values via a CGI object and
 
 290 accessing the 'args' key.  The values of the B<'args'> key will
 
 291 be an array of everything that was sent into the script.
 
 293   my @input = $cgi->params('args');
 
 294   $input[0]; # contains first argument
 
 295   $input[1]; # contains second argument, etc...
 
 297 This is good, but what if you need to send in arguments to the
 
 298 other script which are directly from the calling Perl script,
 
 299 i.e. you want a calling Perl script's variable to be sent, not
 
 300 the value from an HTML element on the page?  This is possible
 
 301 using the following syntax:
 
 303   onClick="exported_func(['args__$input1','args__$input2'],
 
 306 Similary, if the external script required a constant as input
 
 307 (e.g.  C<script.pl?args=42>, you would use this syntax:
 
 309   onClick="exported_func(['args__42'],['resultdiv']);"
 
 311 In both of the above examples, the result from the external
 
 312 script would get placed into the I<resultdiv> element on our
 
 313 (the calling script's) page.
 
 315 If you are sending more than one argument from an external perl
 
 316 script back to a javascript function, you will need to split the
 
 317 string (AJAX applications communicate in strings only) on something.
 
 318 Internally, we use '__pjx__', and this string is checked for.  If
 
 319 found, L<CGI::Ajax> will automatically split it.  However, if you
 
 320 don't want to use '__pjx__', you can do it yourself:
 
 322 For example, from your Perl script, you would...
 
 324         return("A|B"); # join with "|"
 
 326 and then in the javascript function you would have something like...
 
 329                 var arr = arguments[0].split("|");
 
 334 In order to rename parameters, in case the outside script needs
 
 335 specifically-named parameters and not CGI::Ajax' I<'args'> default
 
 336 parameter name, change your event handler associated with an HTML
 
 339   onClick="exported_func(['myname__$input1','myparam__$input2'],
 
 342 The URL generated would look like this...
 
 344 C<script.pl?myname=input1&myparam=input2>
 
 346 You would then retrieve the input in the outside script with this...
 
 348   my $p1 = $cgi->params('myname');
 
 349   my $p1 = $cgi->params('myparam');
 
 351 Finally, what if we need to get a value from our HTML page and we
 
 352 want to send that value to an outside script but the outside script
 
 353 requires a named parameter different from I<'args'>?  You can
 
 354 accomplish this with L<CGI::Ajax> using the getVal() javascript
 
 355 method (which returns an array, thus the C<getVal()[0]> notation):
 
 357   onClick="exported_func(['myparam__' + getVal('div_id')[0]],
 
 360 This will get the value of our HTML element with and
 
 361 I<id> of I<div_id>, and submit it to the url attached to
 
 362 I<myparam__>.  So if our exported handler referred to a URI
 
 363 called I<script/scr.pl>, and the element on our HTML page called
 
 364 I<div_id> contained the number '42', then the URL would look
 
 365 like this C<script/scr.pl?myparam=42>.  The result from this
 
 366 outside URL would get placed back into our HTML page in the
 
 367 element I<resultdiv>.  See the example script that comes with
 
 368 the distribution called I<pjx_url.pl> and its associated outside
 
 369 script I<convert_degrees.pl> for a working example.
 
 371 B<N.B.> These examples show the use of outside scripts which
 
 372 are other perl scripts - I<but you are not limited to Perl>!
 
 373 The outside script could just as easily have been PHP or any other
 
 374 CGI script, as long as the return from the other script is just
 
 375 the result, and not addition HTML code (like FORM elements, etc).
 
 379 =head2 GET versus POST
 
 381 Note that all the examples so far have used the following syntax:
 
 383   onClick="exported_func(['input1'],['result1']);"
 
 385 There is an optional third argument to a L<CGI::Ajax> exported
 
 386 function that allows change the submit method.  The above event could
 
 387 also have been coded like this...
 
 389   onClick="exported_func(['input1'],['result1'], 'GET');"
 
 391 By default, L<CGI::Ajax> sends a I<'GET'> request.  If you need it,
 
 392 for example your URL is getting way too long, you can easily switch
 
 393 to a I<'POST'> request with this syntax...
 
 395   onClick="exported_func(['input1'],['result1'], 'POST');"
 
 397 I<('POST' and 'post' are supported)>
 
 401 We have implemented a method to prevent page cacheing from undermining
 
 402 the AJAX methods in a page.  If you send in an input argument to a
 
 403 L<CGI::Ajax>-exported function called 'NO_CACHE', the a special
 
 404 parameter will get attached to the end or your url with a random
 
 405 number in it.  This will prevent a browser from caching your request.
 
 407   onClick="exported_func(['input1','NO_CACHE'],['result1']);"
 
 409 The extra param is called pjxrand, and won't interfere with the order
 
 410 of processing for the rest of your parameters.
 
 416 ################################### main pod documentation end ##
 
 418 ######################################################
 
 419 ## METHODS - public                                 ##
 
 420 ######################################################
 
 426     Purpose: Associates a cgi obj ($cgi) with pjx object, inserts
 
 427              javascript into <HEAD></HEAD> element and constructs
 
 428              the page, or part of the page.  AJAX applications
 
 429              are designed to update only the section of the
 
 430              page that needs it - the whole page doesn't have
 
 431              to be redrawn.  L<CGI::Ajax> applications use the
 
 432              build_html() method to take care of this: if the CGI
 
 433              parameter C<fname> exists, then the return from the
 
 434              L<CGI::Ajax>-exported function is sent to the page.
 
 435              Otherwise, the entire page is sent, since without
 
 436              an C<fname> param, this has to be the first time
 
 437              the page is being built.
 
 439   Arguments: The CGI object, and either a coderef, or a string
 
 440              containing html.  Optionally, you can send in a third
 
 441              parameter containing information that will get passed
 
 442              directly to the CGI object header() call.
 
 443     Returns: html or updated html (including the header)
 
 444   Called By: originating cgi script
 
 448   my ( $self, $cgi, $html_source, $cgi_header_extra ) = @_;
 
 450   if ( ref( $cgi ) =~ /CGI.*/ ) {
 
 451     if ( $self->DEBUG() ) {
 
 452       print STDERR "CGI::Ajax->build_html: CGI* object was received\n";
 
 454     $self->cgi( $cgi ); # associate the cgi obj with the CGI::Ajax object
 
 457   if ( defined $cgi_header_extra ) {
 
 458     if ( $self->DEBUG() ) {
 
 459       print STDERR "CGI::Ajax->build_html: got extra cgi header info\n";
 
 460       if ( ref($cgi_header_extra) eq "HASH" ) {
 
 461         foreach my $k ( keys %$cgi_header_extra ) {
 
 462           print STDERR "\t$k => ", $cgi_header_extra->{$k}, "\n";
 
 465         print STDERR "\t$cgi_header_extra\n";
 
 468     $self->cgi_header_extra( $cgi_header_extra ); 
 
 471   #check if "fname" was defined in the CGI object
 
 472   if ( defined $self->cgi()->param("fname") ) {
 
 473     # it was, so just return the html from the handled request
 
 474     return ( $self->handle_request() );
 
 477     # start with the minimum, a http header line and any extra cgi
 
 478     # header params sent in
 
 480     if ( $self->cgi()->can('header') ) {
 
 481       #$html .= $self->cgi()->header();
 
 482       $html .= $self->cgi()->header( $self->cgi_header_extra() );
 
 485       # don't have an object with a "header()" method, so just create
 
 487       $html .= "Content-Type: text/html;";
 
 488       $html .= $self->cgi_header_extra();
 
 492     # check if the user sent in a coderef for generating the html,
 
 494     if ( ref($html_source) eq "CODE" ) {
 
 495       if ( $self->DEBUG() ) {
 
 496         print STDERR "CGI::Ajax->build_html: html_source is a CODEREF\n";
 
 498       eval { $html .= &$html_source };
 
 500         # there was a problem evaluating the html-generating function
 
 501         # that was sent in, so generate an error page
 
 502         if ( $self->cgi()->can('header') ) {
 
 503           $html = $self->cgi()->header( $self->cgi_header_extra() );
 
 506           # don't have an object with a "header()" method, so just create
 
 508           $html = "Content-Type: text/html;";
 
 509           $html .= $self->cgi_header_extra();
 
 512         $html .= qq!<html><head><title></title></head><body><h2>Problems</h2> with
 
 513           the html-generating function sent to CGI::Ajax
 
 514           object</body></html>!;
 
 517       $self->html($html);    # no problems, so set html
 
 520       # user must have sent in raw html, so add it
 
 521       if ( $self->DEBUG() ) {
 
 522         print STDERR "CGI::Ajax->build_html: html_source is HTML\n";
 
 524       $self->html( $html . $html_source );
 
 527     # now modify the html to insert the javascript
 
 528     $self->insert_js_in_head();
 
 530   return $self->html();
 
 533 =item show_javascript()
 
 535     Purpose: builds the text of all the javascript that needs to be
 
 536              inserted into the calling scripts html <head> section
 
 538     Returns: javascript text
 
 539   Called By: originating web script
 
 540        Note: This method is also overridden so when you just print
 
 541              a CGI::Ajax object it will output all the javascript needed
 
 546 sub show_javascript {
 
 548   my $rv = $self->show_common_js();    # show the common js
 
 550   # build the js for each perl function you want exported to js
 
 551   foreach my $func ( keys %{ $self->coderef_list() }, keys %{ $self->url_list() } ) {
 
 552     $rv .= $self->make_function($func);
 
 554   # wrap up the return in a CDATA structure for XML compatibility
 
 555   # (thanks Thos Davis)
 
 556   $rv = "\n" . '//<![CDATA[' . "\n" . $rv . "\n" . '//]]>' . "\n";
 
 557   $rv = '<script type="text/javascript">' . $rv . '</script>';
 
 564   my $self = bless ({}, ref ($class) || $class);
 
 565 #  $self->SUPER::new();
 
 566   $self->JSDEBUG(0); # turn javascript debugging off (if on,
 
 567                      # extra info will be added to the web page output
 
 568                      # if set to 1, then the core js will get
 
 569                      # compressed, but the user-defined functions will
 
 570                      # not be compressed.  If set to 2 (or anything
 
 571                      # greater than 1 or 0), then none of the
 
 572                      # javascript will get compressed.
 
 574   $self->DEBUG(0);   # turn debugging off (if on, check web logs)
 
 576   #accessorized attributes
 
 577   $self->coderef_list({});
 
 581   #$self->cgi_header_extra(""); # set cgi_header_extra to an empty string
 
 583   # setup a default endcoding; if you need support for international
 
 584         # charsets, use 'escape' instead of encodeURIComponent.  Due to the
 
 585         # number of browser problems users report about scripts with a default of
 
 586         # encodeURIComponent, we are setting the default to 'escape'
 
 587   $self->js_encode_function('escape');
 
 590     die "incorrect usage: must have fn=>code pairs in new\n";
 
 594     my($function_name,$code) = splice( @_, 0, 2 );
 
 595     if ( ref( $code ) eq "CODE" ) {
 
 596       if ( $self->DEBUG() ) {
 
 597         print STDERR "name = $function_name, code = $code\n";
 
 599       # add the name/code to hash
 
 600       $self->coderef_list()->{ $function_name } = $code;
 
 601     } elsif ( ref($code) ) {
 
 602       die "Unsuported code block/url\n";
 
 604       if ( $self->DEBUG() ) {
 
 605         print STDERR "Setting function $function_name to url $code\n";
 
 607       # if it's a url, it is added here
 
 608       $self->url_list()->{ $function_name } = $code;
 
 614 ######################################################
 
 615 ## METHODS - private                                ##
 
 616 ######################################################
 
 618 # sub cgiobj(), cgi()
 
 620 #    Purpose: accessor method to associate a CGI object with our
 
 622 #  Arguments: a CGI object
 
 623 #    Returns: CGI::Ajax objects cgi object
 
 624 #  Called By: originating cgi script, or build_html()
 
 628   # see if any values were sent in...
 
 631     # add support for other CGI::* modules This requires that your web server
 
 632     # be configured properly.  I can't test anything but a mod_perl2
 
 633     # setup, so this prevents me from testing CGI::Lite,CGI::Simple, etc.
 
 634     if ( ref($cgi) =~ /CGI.*/ ) {
 
 635       if ( $self->DEBUG() ) {
 
 636                                 print STDERR "cgiobj() received a CGI-like object ($cgi)\n";
 
 638       $self->{'cgi'} = $cgi;
 
 640       die "CGI::Ajax -- Can't set internal CGI object to a non-CGI object ($cgi)\n";
 
 644   return( $self->{'cgi'} );
 
 650     return( $self->cgiobj( @_ ) );
 
 652     return( $self->cgiobj() );
 
 656 ## # sub cgi_header_extra
 
 658 ## #    Purpose: accessor method to associate CGI header information
 
 659 ## #             with the CGI::Ajax object
 
 660 ## #  Arguments: a hashref with key=>value pairs that get handed off to
 
 661 ## #             the CGI object's header() method
 
 662 ## #    Returns: hashref of extra cgi header params
 
 663 ## #  Called By: originating cgi script, or build_html()
 
 665 ## sub cgi_header_extra {
 
 668 ##     $self->{'cgi_header_extra'} = shift;
 
 670 ##   return( $self->{'cgi_header_extra'} );
 
 673 # sub create_js_setRequestHeader
 
 675 #    Purpose: create text of the header for the javascript side,
 
 676 #             xmlhttprequest call
 
 678 #    Returns: text of header to pass to xmlhttpreq call so it will
 
 679 #             match whatever was setup for the main web-page
 
 680 #  Called By: originating cgi script, or build_html()
 
 683 sub create_js_setRequestHeader {
 
 685   my $cgi_header_extra = $self->cgi_header_extra();
 
 686   my $js_header_string = q{r.setRequestHeader("};
 
 687         #$js_header_string .= $self->cgi()->header( $cgi_header_extra );
 
 688         $js_header_string .= $self->cgi()->header();
 
 689   $js_header_string .= q{");};
 
 690         #if ( ref $cgi_header_extra eq "HASH" ) {
 
 691         #       foreach my $k ( keys(%$cgi_header_extra) ) {
 
 692         #               $js_header_string .= $self->cgi()->header($cgi_headers) 
 
 695   #print STDERR  $self->cgi()->header($cgi_headers) ;
 
 697         if ( $self->DEBUG() ) {
 
 698                 print STDERR "js_header_string is (", $js_header_string, ")\n";
 
 701   return($js_header_string);
 
 704 # sub show_common_js()
 
 706 #    Purpose: create text of the javascript needed to interface with
 
 709 #    Returns: text of common javascript subroutine, 'do_http_request'
 
 710 #  Called By: originating cgi script, or build_html()
 
 715   my $encodefn = $self->js_encode_function();
 
 716   my $decodefn = $encodefn;
 
 717   $decodefn =~ s/^(en)/de/;
 
 718   $decodefn =~ s/^(esc)/unesc/;
 
 719   #my $request_header_str = $self->create_js_setRequestHeader();
 
 720   my $request_header_str = "";
 
 723 function pjx(args,fname,method) {
 
 726   method=(method)?method:'GET';
 
 727   if(method=='post'){method='POST';}
 
 728   this.method = method;
 
 730   this.url = this.getURL(fname);
 
 735   var fL = document.forms.length;
 
 736   for(var f = 0;f<fL;f++){
 
 737     var els = document.forms[f].elements;
 
 739       var tmp = (els[e].id != undefined)? els[e].id : els[e].name;
 
 740       if(typeof tmp != 'string'){continue;}
 
 741       if(tmp){ all[all.length]=tmp}
 
 746 function getVal(id) {
 
 747   if (id.constructor == Function ) { return id(); }
 
 748   if (typeof(id)!= 'string') { return id; }
 
 749   var element = document.getElementById(id) || document.forms[0].elements[id];
 
 751      alert('ERROR: Cant find HTML element with id or name: ' +
 
 752      id+'. Check that an element with name or id='+id+' exists');
 
 755    if(element.type == 'select-one') { 
 
 756       if(element.selectedIndex == -1) return;
 
 757       var item = element[element.selectedIndex]; 
 
 758       return  item.value || item.text
 
 760   if (element.type == 'select-multiple') {
 
 763     for (var i=0;i<element.length;i++) {
 
 764       if (element[i].selected || element[i].checked ) {
 
 765         ans[k++]= element[i].value || element[i].text;
 
 771   if(element.type == 'radio' || element.type == 'checkbox'){
 
 773     var elms = document.getElementsByTagName('input');
 
 774     var endk = elms.length;
 
 776     for(var k=0;k<endk;k++){
 
 777       if(elms[k].type== element.type && elms[k].checked && elms[k].id==id){
 
 778         ans[i++]=elms[k].value;
 
 783   if( element.value == undefined ){
 
 784     return element.innerHTML;
 
 786     return element.value;
 
 789 function fnsplit(arg) {
 
 791   if(arg=='NO_CACHE'){return '&pjxrand='+Math.random()}
 
 792   if((typeof(arg)).toLowerCase() == 'object'){
 
 794          url += '&' + k + '=' + arg[k];
 
 796   }else if (arg.indexOf('__') != -1) {
 
 797     arga = arg.split(/__/);
 
 798     url += '&' + arga[0] +'='+ $encodefn(arga[1]);
 
 800     var res = getVal(arg) || '';
 
 801     if(res.constructor != Array){ res = [res] }
 
 802     for(var i=0;i<res.length;i++) {
 
 803       url += '&args=' + $encodefn(res[i]) + '&' + arg + '=' + $encodefn(res[i]);
 
 810   send2perl : function(){
 
 812     var dt = this.target;
 
 813     this.pjxInitialized(dt);
 
 816     if(this.method=="POST"){
 
 817       var idx=url.indexOf('?');
 
 818       postdata = url.substr(idx+1);
 
 819       url = url.substr(0,idx);
 
 821     r.open(this.method,url,true);
 
 823     if(this.method=="POST"){
 
 824       r.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 
 827     if(this.method=="GET"){
 
 830     r.onreadystatechange = handleReturn;
 
 832  pjxInitialized : function(){},
 
 833  pjxCompleted : function(){},
 
 834  readyState4 : function(){
 
 835     var rsp = $decodefn(this.r.responseText);  /* the response from perl */
 
 836     var splitval = '__pjx__';  /* to split text */
 
 837     /* fix IE problems with undef values in an Array getting squashed*/
 
 838     rsp = rsp.replace(splitval+splitval+'g',splitval+" "+splitval);
 
 839     var data = rsp.split(splitval);  
 
 841     if (dt.constructor != Array) { dt=[dt]; }
 
 842     if (data.constructor != Array) { data=[data]; }
 
 843     if (typeof(dt[0])=='function') {
 
 844        dt[0].apply(this,data);
 
 846       for ( var i=0; i<dt.length; i++ ) {
 
 847         if (typeof(dt[i])=='function') {
 
 848           dt[i].apply(this,[data[i]]);
 
 850           var div = document.getElementById(dt[i]);
 
 851           if (div.type =='text' || div.type=='textarea' || div.type=='hidden' ) {
 
 854             div.innerHTML = data[i];
 
 859     this.pjxCompleted(dt);
 
 862   getURL : function(fname) {
 
 863       var args = this.args;
 
 864       var url= 'fname=' + fname;
 
 865       for (var i=0;i<args.length;i++) {
 
 872 handleReturn = function() {
 
 873   for( var k=0; k<ajax.length; k++ ) {
 
 874     if (ajax[k].r==null) { ajax.splice(k--,1); continue; }
 
 875     if ( ajax[k].r.readyState== 4) { 
 
 876       ajax[k].readyState4();
 
 885     if(typeof XMLHttpRequest != "undefined")
 
 887         return function(){return new XMLHttpRequest();}
 
 889     var msv= ["Msxml2.XMLHTTP.7.0", "Msxml2.XMLHTTP.6.0",
 
 890     "Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0",
 
 891     "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
 
 892     for(var j=0;j<=msv.length;j++){
 
 895             A = new ActiveXObject(msv[j]);
 
 897               return function(){return new ActiveXObject(msv[j]);}
 
 907     var tmp = document.getElementById('pjxdebugrequest').innerHTML = "<br><pre>";
 
 908     for( var i=0; i < ajax.length; i++ ) {
 
 909       tmp += '<a href= '+ ajax[i].url +' target=_blank>' +
 
 910       decodeURI(ajax[i].url) + ' </a><br>';
 
 912     document.getElementById('pjxdebugrequest').innerHTML = tmp + "</pre>";
 
 917   if ( $self->JSDEBUG() <= 1 ) {
 
 918     $rv = $self->compress_js($rv);
 
 926 #    Purpose: searches the javascript for newlines and spaces and
 
 927 #             removes them (if a newline) or shrinks them to a single (if
 
 929 #  Arguments: javascript to compress
 
 930 #    Returns: compressed js string
 
 931 #  Called By: show_common_js(),
 
 936   return if not defined $js;
 
 938   $js =~ s/\n//g;   # drop newlines
 
 939   $js =~ s/\s+/ /g; # replace 1+ spaces with just one space
 
 944 # sub insert_js_in_head()
 
 946 #    Purpose: searches the html value in the CGI::Ajax object and inserts
 
 947 #             the ajax javascript code in the <script></script> section,
 
 948 #             or if no such section exists, then it creates it.  If
 
 949 #             JSDEBUG is set, then an extra div will be added and the
 
 950 #             url wil be desplayed as a link
 
 953 #  Called By: build_html()
 
 956 sub insert_js_in_head{
 
 958   my $mhtml = $self->html();
 
 961   my $js = $self->show_javascript();
 
 963   if ( $self->JSDEBUG() ) {
 
 964     my $showurl=qq!<br/><div id='pjxdebugrequest'></div><br/>!;
 
 965     # find the terminal </body> so we can insert just before it
 
 966     my @splith = $mhtml =~ /(.*)(<\s*\/\s*body[^>]*>?)(.*)/is;
 
 967     $mhtml = $splith[0].$showurl.$splith[1].$splith[2];
 
 970   # see if we can match on <head>
 
 971   @shtml= $mhtml =~ /(.*)(<\s*head[^>]*>?)(.*)/is;
 
 973     # yes, there's already a <head></head>, so let's insert inside it,
 
 975     $newhtml = $shtml[0].$shtml[1].$js.$shtml[2];
 
 976   } elsif( @shtml= $mhtml =~ /(.*)(<\s*html[^>]*>?)(.*)/is){
 
 977     # there's no <head>, so look for the <html> tag, and insert out
 
 978     # javascript inside that tag
 
 979     $newhtml = $shtml[0].$shtml[1].$js.$shtml[2];
 
 981     $newhtml .= "<html><head>";
 
 983     $newhtml .= "</head><body>";
 
 984     $newhtml .= "No head/html tags, nowhere to insert.  Returning javascript anyway<br>";
 
 985     $newhtml .= "</body></html>";
 
 987   $self->html($newhtml);
 
 991 # sub handle_request()
 
 993 #    Purpose: makes sure a fname function name was set in the CGI
 
 994 #             object, and then tries to eval the function with
 
 995 #             parameters sent in on args
 
 997 #    Returns: the result of the perl subroutine, as text; if multiple
 
 998 #             arguments are sent back from the defined, exported perl
 
 999 #             method, then join then with a connector (__pjx__).
 
1000 #  Called By: build_html()
 
1003 sub handle_request {
 
1006   my $result; # $result takes the output of the function, if it's an
 
1007               # array split on __pjx__
 
1008   my @other = (); # array for catching extra parameters
 
1010   # we need to access "fname" in the form from the web page, so make
 
1011   # sure there is a CGI object defined
 
1012   return undef unless defined $self->cgi();
 
1015   if ( $self->cgi()->can('header') ) {
 
1016     $rv = $self->cgi()->header( $self->cgi_header_extra() );
 
1018     # don't have an object with a "header()" method, so just create
 
1020     $rv = "Content-Type: text/html;";
 
1022     $rv .= $self->cgi_header_extra();
 
1026   # get the name of the function
 
1027   my $func_name = $self->cgi()->param("fname");
 
1029   # check if the function name was created
 
1030   if ( defined $self->coderef_list()->{$func_name} ) {
 
1031     my $code = $self->coderef_list()->{$func_name};
 
1033     # eval the code from the coderef, and append the output to $rv
 
1034     if ( ref($code) eq "CODE" ) {
 
1035       eval { ($result, @other) = $code->( $self->cgi()->param("args") ) };
 
1038         # see if the eval caused and error and report it
 
1039         # Should we be more severe and die?
 
1040         if ( $self->DEBUG() ) {
 
1041           print STDERR "Problem with code: $@\n";
 
1046           $rv .= join( "__pjx__", ($result, @other) );
 
1047           if ( $self->DEBUG() ) {
 
1048             print STDERR "rv = $rv\n";
 
1051         if ( defined $result ) {
 
1056     } # end if ref = CODE
 
1058     # # problems with the URL, return a CGI rrror
 
1059     print STDERR "POSSIBLE SECURITY INCIDENT! Browser from ", $self->cgi()->remote_addr();
 
1060     print STDERR "\trequested URL: ", $self->cgi()->url();
 
1061     print STDERR "\tfname request: ", $self->cgi()->param('fname');
 
1062     print STDERR " -- returning Bad Request status 400\n";
 
1063     if ( $self->cgi()->can('header') ) {
 
1064       return($self->cgi()->header( -status=>'400' ));
 
1066       # don't have an object with a "header()" method, so just create
 
1067       # a mimimal one with 400 error
 
1068       $rv = "Status: 400\nContent-Type: text/html;\n\n";
 
1075 # sub make_function()
 
1077 #    Purpose: creates the javascript wrapper for the underlying perl
 
1079 #  Arguments: CGI object from web form, and the name of the perl
 
1080 #             function to export to javascript, or a url if the
 
1081 #             function name refers to another cgi script
 
1082 #    Returns: text of the javascript-wrapped perl subroutine
 
1083 #  Called By: show_javascript; called once for each registered perl
 
1088   my ($self, $func_name ) = @_;
 
1089   return("") if not defined $func_name;
 
1090   return("") if $func_name eq "";
 
1092   my $script = $0 || $ENV{SCRIPT_FILENAME};
 
1093   $script =~ s/.*[\/|\\](.+)$/$1/;
 
1094   my $outside_url = $self->url_list()->{ $func_name };
 
1095   my $url = defined $outside_url ? $outside_url : $script;
 
1096   if ($url =~ /\?/) { $url.='&'; } else {$url.='?'}
 
1099   if ( $self->JSDEBUG()) {
 
1100     $jsdebug = "jsdebug()";
 
1103   #create the javascript text
 
1105 function $func_name() {
 
1106   var args = $func_name.arguments;
 
1107   for( var i=0; i<args[0].length;i++ ) {
 
1108     args[0][i] = fnsplit(args[0][i]);
 
1110   var l = ajax.length;
 
1111   ajax[l]= new pjx(args,"$func_name",args[2]);
 
1112   ajax[l].url = $url + ajax[l].url;
 
1113   ajax[l].send2perl();
 
1118   if ( not $self->JSDEBUG() ) {
 
1119     $rv = $self->compress_js($rv);
 
1126     Purpose: adds a function name and a code ref to the global coderef
 
1127              hash, after the original object was created
 
1128   Arguments: function name, code reference
 
1130   Called By: originating web script
 
1135   my ( $self, $fn, $coderef ) = @_;
 
1136   # coderef_list() is a Class::Accessor function
 
1137   # url_list() is a Class::Accessor function
 
1138   if ( ref( $coderef ) eq "CODE" ) {
 
1139     $self->coderef_list()->{$fn} = $coderef;
 
1140   } elsif ( ref($coderef) ) {
 
1141     die "Unsupported code/url type - error\n";
 
1143     $self->url_list()->{$fn} = $coderef;
 
1149     Purpose: Show the AJAX URL that is being generated, and stop
 
1150              compression of the generated javascript, both of which can aid
 
1151              during debugging.  If set to 1, then the core js will get
 
1152              compressed, but the user-defined functions will not be
 
1153              compressed.  If set to 2 (or anything greater than 1 or 0), 
 
1154              then none of the javascript will get compressed.
 
1156   Arguments: JSDEBUG(0); # turn javascript debugging off
 
1157              JSDEBUG(1); # turn javascript debugging on, some javascript compression
 
1158              JSDEBUG(2); # turn javascript debugging on, no javascript compresstion
 
1159     Returns: prints a link to the url that is being generated automatically by
 
1160              the Ajax object. this is VERY useful for seeing what
 
1161              CGI::Ajax is doing. Following the link, will show a page
 
1162              with the output that the page is generating.
 
1164   Called By: $pjx->JSDEBUG(1) # where $pjx is a CGI::Ajax object;
 
1168     Purpose: Show debugging information in web server logs
 
1169   Arguments: DEBUG(0); # turn debugging off (default)
 
1170              DEBUG(1); # turn debugging on
 
1171     Returns: prints debugging information to the web server logs using
 
1173   Called By: $pjx->DEBUG(1) # where $pjx is a CGI::Ajax object;
 
1179 Follow any bugs at our homepage....
 
1181   http://www.perljax.us
 
1185 Check out the news/discussion/bugs lists at our homepage:
 
1187   http://www.perljax.us
 
1191   Brian C. Thomas     Brent Pedersen
 
1193   bct.x42@gmail.com   bpederse@gmail.com
 
1195 =head1 A NOTE ABOUT THE MODULE NAME
 
1197 This module was initiated using the name "Perljax", but then
 
1198 registered with CPAN under the WWW group "CGI::", and so became
 
1199 "CGI::Perljax".  Upon further deliberation, we decided to change it's
 
1200 name to L<CGI::Ajax>.
 
1204 This program is free software; you can redistribute
 
1205 it and/or modify it under the same terms as Perl itself.
 
1207 The full text of the license can be found in the
 
1208 LICENSE file included with this module.