blib/lib/CGI/Ajax.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 35 | 231 | 15.1 |
branch | 5 | 110 | 4.5 |
condition | 1 | 33 | 3.0 |
subroutine | 7 | 22 | 31.8 |
pod | 4 | 16 | 25.0 |
total | 52 | 412 | 12.6 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package CGI::Ajax; | ||||||
2 | 1 | 1 | 44284 | use strict; | |||
1 | 3 | ||||||
1 | 39 | ||||||
3 | 1 | 1 | 1690 | use Data::Dumper; | |||
1 | 20118 | ||||||
1 | 87 | ||||||
4 | 1 | 1 | 12 | use base qw(Class::Accessor); | |||
1 | 3 | ||||||
1 | 1351 | ||||||
5 | 1 | 1 | 3479 | use overload '""' => 'show_javascript'; # for building web pages, so | |||
1 | 2 | ||||||
1 | 9 | ||||||
6 | # you can just say: print $pjx | ||||||
7 | |||||||
8 | BEGIN { | ||||||
9 | 1 | 1 | 75 | use vars qw ($VERSION @ISA @METHODS); | |||
1 | 1 | ||||||
1 | 96 | ||||||
10 | 1 | 1 | 4 | @METHODS = qw(url_list coderef_list CACHE DEBUG JSDEBUG html | |||
11 | js_encode_function cgi_header_extra skip_header fname); | ||||||
12 | |||||||
13 | 1 | 7 | CGI::Ajax->mk_accessors(@METHODS); | ||||
14 | |||||||
15 | 1 | 3544 | $VERSION = .707; | ||||
16 | } | ||||||
17 | |||||||
18 | ########################################### main pod documentation begin ## | ||||||
19 | |||||||
20 | =head1 NAME | ||||||
21 | |||||||
22 | CGI::Ajax - a perl-specific system for writing Asynchronous web | ||||||
23 | applications | ||||||
24 | |||||||
25 | =head1 SYNOPSIS | ||||||
26 | |||||||
27 | use strict; | ||||||
28 | use CGI; # or any other CGI:: form handler/decoder | ||||||
29 | use CGI::Ajax; | ||||||
30 | |||||||
31 | my $cgi = new CGI; | ||||||
32 | my $pjx = new CGI::Ajax( 'exported_func' => \&perl_func ); | ||||||
33 | print $pjx->build_html( $cgi, \&Show_HTML); | ||||||
34 | |||||||
35 | sub perl_func { | ||||||
36 | my $input = shift; | ||||||
37 | # do something with $input | ||||||
38 | my $output = $input . " was the input!"; | ||||||
39 | return( $output ); | ||||||
40 | } | ||||||
41 | |||||||
42 | sub Show_HTML { | ||||||
43 | my $html = < | ||||||
44 | |||||||
45 | |||||||
46 | Enter something: | ||||||
47 | |||||||
48 | onkeyup="exported_func( ['val1'], ['resultdiv'] );"> | ||||||
49 | |
||||||
50 | |||||||
51 | |||||||
52 | |||||||
53 | EOHTML | ||||||
54 | return $html; | ||||||
55 | } | ||||||
56 | |||||||
57 | When you use CGI::Ajax within Applications that send their own header information, | ||||||
58 | you can skip the header: | ||||||
59 | |||||||
60 | my $pjx = new CGI::Ajax( | ||||||
61 | 'exported_func' => \&perl_func, | ||||||
62 | 'skip_header' => 1, | ||||||
63 | ); | ||||||
64 | $pjx->skip_header(1); | ||||||
65 | |||||||
66 | print $pjx->build_html( $cgi, \&Show_HTML); | ||||||
67 | |||||||
68 | I | ||||||
69 | directory of the distribution.> | ||||||
70 | |||||||
71 | =head1 DESCRIPTION | ||||||
72 | |||||||
73 | CGI::Ajax is an object-oriented module that provides a unique | ||||||
74 | mechanism for using perl code asynchronously from javascript- | ||||||
75 | enhanced HTML pages. CGI::Ajax unburdens the user from having to | ||||||
76 | write extensive javascript, except for associating an exported | ||||||
77 | method with a document-defined event (such as onClick, onKeyUp, | ||||||
78 | etc). CGI::Ajax also mixes well with HTML containing more complex | ||||||
79 | javascript. | ||||||
80 | |||||||
81 | CGI::Ajax supports methods that return single results or multiple | ||||||
82 | results to the web page, and supports returning values to multiple | ||||||
83 | DIV elements on the HTML page. | ||||||
84 | |||||||
85 | Using CGI::Ajax, the URL for the HTTP GET/POST request is | ||||||
86 | automatically generated based on HTML layout and events, and the | ||||||
87 | page is then dynamically updated with the output from the perl | ||||||
88 | function. Additionally, CGI::Ajax supports mapping URL's to a | ||||||
89 | CGI::Ajax function name, so you can separate your code processing | ||||||
90 | over multiple scripts. | ||||||
91 | |||||||
92 | Other than using the Class::Accessor module to generate CGI::Ajax' | ||||||
93 | accessor methods, CGI::Ajax is completely self-contained - it | ||||||
94 | does not require you to install a larger package or a full Content | ||||||
95 | Management System, etc. | ||||||
96 | |||||||
97 | We have added I |
||||||
98 | like L |
||||||
99 | since we run mod_perl2 only here. CGI::Ajax checks to see if a | ||||||
100 | header() method is available to the CGI object, and then uses it. | ||||||
101 | If method() isn't available, it creates it's own minimal header. | ||||||
102 | |||||||
103 | A primary goal of CGI::Ajax is to keep the module streamlined and | ||||||
104 | maximally flexible. We are trying to keep the generated javascript | ||||||
105 | code to a minimum, but still provide users with a variety of | ||||||
106 | methods for deploying CGI::Ajax. And VERY little user javascript. | ||||||
107 | |||||||
108 | =head1 EXAMPLES | ||||||
109 | |||||||
110 | The CGI::Ajax module allows a Perl subroutine to be called | ||||||
111 | asynchronously, when triggered from a javascript event on the | ||||||
112 | HTML page. To do this, the subroutine must be I |
||||||
113 | usually done during: | ||||||
114 | |||||||
115 | my $pjx = new CGI::Ajax( 'JSFUNC' => \&PERLFUNC ); | ||||||
116 | |||||||
117 | This maps a perl subroutine (PERLFUNC) to an automatically | ||||||
118 | generated Javascript function (JSFUNC). Next you setup a trigger this | ||||||
119 | function when an event occurs (e.g. "onClick"): | ||||||
120 | |||||||
121 | onClick="JSFUNC(['source1','source2'], ['dest1','dest2']);" | ||||||
122 | |||||||
123 | where 'source1', 'dest1', 'source2', 'dest2' are the DIV ids of | ||||||
124 | HTML elements in your page... | ||||||
125 | |||||||
126 | |||||||
127 | |||||||
128 | |||||||
129 | |||||||
130 | |||||||
131 | L |
||||||
132 | Perl subroutine and returns the results to dest1 and dest2. | ||||||
133 | |||||||
134 | =head2 4 Usage Methods | ||||||
135 | |||||||
136 | =over 4 | ||||||
137 | |||||||
138 | =item 1 Standard CGI::Ajax example | ||||||
139 | |||||||
140 | Start by defining a perl subroutine that you want available from | ||||||
141 | javascript. In this case we'll define a subrouting that determines | ||||||
142 | whether or not an input is odd, even, or not a number (NaN): | ||||||
143 | |||||||
144 | use strict; | ||||||
145 | use CGI::Ajax; | ||||||
146 | use CGI; | ||||||
147 | |||||||
148 | |||||||
149 | sub evenodd_func { | ||||||
150 | my $input = shift; | ||||||
151 | |||||||
152 | # see if input is defined | ||||||
153 | if ( not defined $input ) { | ||||||
154 | return("input not defined or NaN"); | ||||||
155 | } | ||||||
156 | |||||||
157 | # see if value is a number (*thanks Randall!*) | ||||||
158 | if ( $input !~ /\A\d+\z/ ) { | ||||||
159 | return("input is NaN"); | ||||||
160 | } | ||||||
161 | |||||||
162 | # got a number, so mod by 2 | ||||||
163 | $input % 2 == 0 ? return("EVEN") : return("ODD"); | ||||||
164 | } | ||||||
165 | |||||||
166 | Alternatively, we could have used coderefs to associate an | ||||||
167 | exported name... | ||||||
168 | |||||||
169 | my $evenodd_func = sub { | ||||||
170 | # exactly the same as in the above subroutine | ||||||
171 | }; | ||||||
172 | |||||||
173 | Next we define a function to generate the web page - this can | ||||||
174 | be done many different ways, and can also be defined as an | ||||||
175 | anonymous sub. The only requirement is that the sub send back | ||||||
176 | the html of the page. You can do this via a string containing the | ||||||
177 | html, or from a coderef that returns the html, or from a function | ||||||
178 | (as shown here)... | ||||||
179 | |||||||
180 | sub Show_HTML { | ||||||
181 | my $html = < | ||||||
182 | |||||||
183 | |
||||||
184 | |||||||
185 | |||||||
186 | Enter a number: | ||||||
187 | |||||||
188 | OnKeyUp="evenodd( ['val1'], ['resultdiv'] );"> | ||||||
189 | |
||||||
190 | |
||||||
191 | |
||||||
192 | |||||||
193 | |||||||
194 | |||||||
195 | EOT | ||||||
196 | return $html; | ||||||
197 | } | ||||||
198 | |||||||
199 | The exported Perl subrouting is triggered using the C |
||||||
200 | event handler of the input HTML element. The subroutine takes one | ||||||
201 | value from the form, the input element B<'val1'>, and returns the | ||||||
202 | the result to an HTML div element with an id of B<'resultdiv'>. | ||||||
203 | Sending in the input id in an array format is required to support | ||||||
204 | multiple inputs, and similarly, to output multiple the results, | ||||||
205 | you can use an array for the output divs, but this isn't mandatory - | ||||||
206 | as will be explained in the B |
||||||
207 | |||||||
208 | Now create a CGI object and a CGI::Ajax object, associating a reference | ||||||
209 | to our subroutine with the name we want available to javascript. | ||||||
210 | |||||||
211 | my $cgi = new CGI(); | ||||||
212 | my $pjx = new CGI::Ajax( 'evenodd' => \&evenodd_func ); | ||||||
213 | |||||||
214 | And if we used a coderef, it would look like this... | ||||||
215 | |||||||
216 | my $pjx = new CGI::Ajax( 'evenodd' => $evenodd_func ); | ||||||
217 | |||||||
218 | Now we're ready to print the output page; we send in the cgi | ||||||
219 | object and the HTML-generating function. | ||||||
220 | |||||||
221 | print $pjx->build_html($cgi,\&Show_HTML); | ||||||
222 | |||||||
223 | CGI::Ajax has support for passing in extra HTML header information | ||||||
224 | to the CGI object. This can be accomplished by adding a third | ||||||
225 | argument to the build_html() call. The argument needs to be a | ||||||
226 | hashref containing Key=>value pairs that CGI objects understand: | ||||||
227 | |||||||
228 | print $pjx->build_html($cgi,\&Show_HTML, | ||||||
229 | {-charset=>'UTF-8, -expires=>'-1d'}); | ||||||
230 | |||||||
231 | See L |
||||||
232 | Perl6 CGI) | ||||||
233 | |||||||
234 | That's it for the CGI::Ajax standard method. Let's look at | ||||||
235 | something more advanced. | ||||||
236 | |||||||
237 | =item 2 Advanced CGI::Ajax example | ||||||
238 | |||||||
239 | Let's say we wanted to have a perl subroutine process multiple | ||||||
240 | values from the HTML page, and similarly return multiple values | ||||||
241 | back to distinct divs on the page. This is easy to do, and | ||||||
242 | requires no changes to the perl code - you just create it as you | ||||||
243 | would any perl subroutine that works with multiple input values | ||||||
244 | and returns multiple values. The significant change happens in | ||||||
245 | the event handler javascript in the HTML... | ||||||
246 | |||||||
247 | onClick="exported_func(['input1','input2'],['result1','result2']);" | ||||||
248 | |||||||
249 | Here we associate our javascript function ("exported_func") with | ||||||
250 | two HTML element ids ('input1','input2'), and also send in two | ||||||
251 | HTML element ids to place the results in ('result1','result2'). | ||||||
252 | |||||||
253 | =item 3 Sending Perl Subroutine Output to a Javascript function | ||||||
254 | |||||||
255 | Occassionally, you might want to have a custom javascript function | ||||||
256 | process the returned information from your Perl subroutine. | ||||||
257 | This is possible, and the only requierment is that you change | ||||||
258 | your event handler code... | ||||||
259 | |||||||
260 | onClick="exported_func(['input1'],[js_process_func]);" | ||||||
261 | |||||||
262 | In this scenario, C |
||||||
263 | write to take the returned value from your Perl subroutine and | ||||||
264 | process the results. I | ||||||
265 | quoted -- if it were, then CGI::Ajax would look for a HTML element | ||||||
266 | with that id.> Beware that with this usage, B | ||||||
267 | for distributing the results to the appropriate place on the | ||||||
268 | HTML page>. If the exported Perl subroutine returns, e.g. 2 | ||||||
269 | values, then C |
||||||
270 | by working through an array, or using the javascript Function | ||||||
271 | C |
||||||
272 | |||||||
273 | function js_process_func() { | ||||||
274 | var input1 = arguments[0] | ||||||
275 | var input2 = arguments[1]; | ||||||
276 | // do something and return results, or set HTML divs using | ||||||
277 | // innerHTML | ||||||
278 | document.getElementById('outputdiv').innerHTML = input1; | ||||||
279 | } | ||||||
280 | |||||||
281 | =item 4 URL/Outside Script CGI::Ajax example | ||||||
282 | |||||||
283 | There are times when you may want a different script to | ||||||
284 | return content to your page. This could be because you have | ||||||
285 | an existing script already written to perform a particular | ||||||
286 | task, or you want to distribute a part of your application to another | ||||||
287 | script. This can be accomplished in L |
||||||
288 | place of a locally-defined Perl subroutine. In this usage, | ||||||
289 | you alter you creation of the L |
||||||
290 | exported javascript function name to a local URL instead of | ||||||
291 | a coderef or a subroutine. | ||||||
292 | |||||||
293 | my $url = 'scripts/other_script.pl'; | ||||||
294 | my $pjx = new CGI::Ajax( 'external' => $url ); | ||||||
295 | |||||||
296 | This will work as before in terms of how it is called from you | ||||||
297 | event handler: | ||||||
298 | |||||||
299 | onClick="external(['input1','input2'],['resultdiv']);" | ||||||
300 | |||||||
301 | The other_script.pl will get the values via a CGI object and | ||||||
302 | accessing the 'args' key. The values of the B<'args'> key will | ||||||
303 | be an array of everything that was sent into the script. | ||||||
304 | |||||||
305 | my @input = $cgi->params('args'); | ||||||
306 | $input[0]; # contains first argument | ||||||
307 | $input[1]; # contains second argument, etc... | ||||||
308 | |||||||
309 | This is good, but what if you need to send in arguments to the | ||||||
310 | other script which are directly from the calling Perl script, | ||||||
311 | i.e. you want a calling Perl script's variable to be sent, not | ||||||
312 | the value from an HTML element on the page? This is possible | ||||||
313 | using the following syntax: | ||||||
314 | |||||||
315 | onClick="exported_func(['args__$input1','args__$input2'], | ||||||
316 | ['resultdiv']);" | ||||||
317 | |||||||
318 | Similary, if the external script required a constant as input | ||||||
319 | (e.g. C |
||||||
320 | |||||||
321 | onClick="exported_func(['args__42'],['resultdiv']);" | ||||||
322 | |||||||
323 | In both of the above examples, the result from the external | ||||||
324 | script would get placed into the I |
||||||
325 | (the calling script's) page. | ||||||
326 | |||||||
327 | If you are sending more than one argument from an external perl | ||||||
328 | script back to a javascript function, you will need to split the | ||||||
329 | string (AJAX applications communicate in strings only) on something. | ||||||
330 | Internally, we use '__pjx__', and this string is checked for. If | ||||||
331 | found, L |
||||||
332 | don't want to use '__pjx__', you can do it yourself: | ||||||
333 | |||||||
334 | For example, from your Perl script, you would... | ||||||
335 | |||||||
336 | return("A|B"); # join with "|" | ||||||
337 | |||||||
338 | and then in the javascript function you would have something like... | ||||||
339 | |||||||
340 | process_func() { | ||||||
341 | var arr = arguments[0].split("|"); | ||||||
342 | // arr[0] eq 'A' | ||||||
343 | // arr[1] eq 'B' | ||||||
344 | } | ||||||
345 | |||||||
346 | In order to rename parameters, in case the outside script needs | ||||||
347 | specifically-named parameters and not CGI::Ajax' I<'args'> default | ||||||
348 | parameter name, change your event handler associated with an HTML | ||||||
349 | event like this | ||||||
350 | |||||||
351 | onClick="exported_func(['myname__$input1','myparam__$input2'], | ||||||
352 | ['resultdiv']);" | ||||||
353 | |||||||
354 | The URL generated would look like this... | ||||||
355 | |||||||
356 | C |
||||||
357 | |||||||
358 | You would then retrieve the input in the outside script with this... | ||||||
359 | |||||||
360 | my $p1 = $cgi->params('myname'); | ||||||
361 | my $p1 = $cgi->params('myparam'); | ||||||
362 | |||||||
363 | Finally, what if we need to get a value from our HTML page and we | ||||||
364 | want to send that value to an outside script but the outside script | ||||||
365 | requires a named parameter different from I<'args'>? You can | ||||||
366 | accomplish this with L |
||||||
367 | method (which returns an array, thus the C |
||||||
368 | |||||||
369 | onClick="exported_func(['myparam__' + getVal('div_id')[0]], | ||||||
370 | ['resultdiv']);" | ||||||
371 | |||||||
372 | This will get the value of our HTML element with and | ||||||
373 | I |
||||||
374 | I |
||||||
375 | called I'; | ||||||
624 | 0 | 0 | return $rv; | ||||
625 | } | ||||||
626 | |||||||
627 | ## new | ||||||
628 | sub new { | ||||||
629 | 1 | 1 | 1 | 14 | my ($class) = shift; | ||
630 | 1 | 33 | 11 | my $self = bless( {}, ref($class) || $class ); | |||
631 | |||||||
632 | # $self->SUPER::new(); | ||||||
633 | 1 | 8 | $self->fname("fname");# default parameter for exported function name | ||||
634 | 1 | 96 | $self->JSDEBUG(0); # turn javascript debugging off (if on, | ||||
635 | # extra info will be added to the web page output | ||||||
636 | # if set to 1, then the core js will get | ||||||
637 | # compressed, but the user-defined functions will | ||||||
638 | # not be compressed. If set to 2 (or anything | ||||||
639 | # greater than 1 or 0), then none of the | ||||||
640 | # javascript will get compressed. | ||||||
641 | # | ||||||
642 | 1 | 12 | $self->DEBUG(0); # turn debugging off (if on, check web logs) | ||||
643 | 1 | 12 | $self->CACHE(1); # default behavior is to allow cache of content | ||||
644 | # which can be explicitly switched off by passing | ||||||
645 | # NO_CACHE in the arg list | ||||||
646 | |||||||
647 | #accessorized attributes | ||||||
648 | 1 | 12 | $self->coderef_list( {} ); | ||||
649 | 1 | 12 | $self->url_list( {} ); | ||||
650 | |||||||
651 | #$self->html(""); | ||||||
652 | #$self->cgi(); | ||||||
653 | #$self->cgi_header_extra(""); # set cgi_header_extra to an empty string | ||||||
654 | |||||||
655 | # setup a default endcoding; if you need support for international | ||||||
656 | # charsets, use 'escape' instead of encodeURIComponent. Due to the | ||||||
657 | # number of browser problems users report about scripts with a default of | ||||||
658 | # encodeURIComponent, we are setting the default to 'escape' | ||||||
659 | 1 | 13 | $self->js_encode_function('escape'); | ||||
660 | |||||||
661 | 1 | 50 | 14 | if ( @_ < 2 ) { | |||
662 | 0 | 0 | die "incorrect usage: must have fn=>code pairs in new\n"; | ||||
663 | |||||||
664 | } | ||||||
665 | |||||||
666 | 1 | 11 | while (@_) { | ||||
667 | 1 | 4 | my ( $function_name, $code ) = splice( @_, 0, 2 ); | ||||
668 | |||||||
669 | 1 | 50 | 5 | if( $function_name eq 'skip_header' ){ | |||
670 | 0 | 0 | $self->skip_header( $code ); | ||||
671 | 0 | 0 | next; | ||||
672 | } | ||||||
673 | |||||||
674 | 1 | 50 | 18 | if ( ref($code) eq "CODE" ) { | |||
50 | |||||||
675 | 0 | 0 | 0 | if ( $self->DEBUG() ) { | |||
676 | 0 | 0 | print STDERR "name = $function_name, code = $code\n"; | ||||
677 | } | ||||||
678 | |||||||
679 | # add the name/code to hash | ||||||
680 | 0 | 0 | $self->coderef_list()->{$function_name} = $code; | ||||
681 | } | ||||||
682 | elsif ( ref($code) ) { | ||||||
683 | 0 | 0 | die "Unsuported code block/url\n"; | ||||
684 | } | ||||||
685 | else { | ||||||
686 | 1 | 50 | 4 | if ( $self->DEBUG() ) { | |||
687 | 0 | 0 | print STDERR "Setting function $function_name to url $code\n"; | ||||
688 | } | ||||||
689 | |||||||
690 | # if it's a url, it is added here | ||||||
691 | 1 | 21 | $self->url_list()->{$function_name} = $code; | ||||
692 | } | ||||||
693 | } | ||||||
694 | 1 | 12 | return ($self); | ||||
695 | } | ||||||
696 | |||||||
697 | ###################################################### | ||||||
698 | ## METHODS - private ## | ||||||
699 | ###################################################### | ||||||
700 | |||||||
701 | # sub cgiobj(), cgi() | ||||||
702 | # | ||||||
703 | # Purpose: accessor method to associate a CGI object with our | ||||||
704 | # CGI::Ajax object | ||||||
705 | # Arguments: a CGI object | ||||||
706 | # Returns: CGI::Ajax objects cgi object | ||||||
707 | # Called By: originating cgi script, or build_html() | ||||||
708 | # | ||||||
709 | sub cgiobj { | ||||||
710 | 0 | 0 | 0 | my $self = shift; | |||
711 | |||||||
712 | # see if any values were sent in... | ||||||
713 | 0 | 0 | if (@_) { | ||||
714 | 0 | my $cgi = shift; | |||||
715 | |||||||
716 | # add support for other CGI::* modules This requires that your web server | ||||||
717 | # be configured properly. I can't test anything but a mod_perl2 | ||||||
718 | # setup, so this prevents me from testing CGI::Lite,CGI::Simple, etc. | ||||||
719 | 0 | 0 | 0 | if ( ref($cgi) =~ /CGI.*/ | |||
0 | |||||||
720 | or ( $cgi->isa('CGI::Application') && $cgi->query =~ /CGI/ ) ) | ||||||
721 | { #pmg | ||||||
722 | 0 | 0 | if ( $self->DEBUG() ) { | ||||
723 | 0 | print STDERR "cgiobj() received a CGI-like object ($cgi)\n"; | |||||
724 | } | ||||||
725 | 0 | $self->{'cgi'} = $cgi; | |||||
726 | } | ||||||
727 | else { | ||||||
728 | 0 | die | |||||
729 | "CGI::Ajax -- Can't set internal CGI object to a non-CGI object ($cgi)\n"; | ||||||
730 | } | ||||||
731 | } | ||||||
732 | |||||||
733 | # return the object | ||||||
734 | 0 | return ( $self->{'cgi'} ); | |||||
735 | } | ||||||
736 | |||||||
737 | sub cgi { | ||||||
738 | 0 | 0 | 0 | my $self = shift; | |||
739 | 0 | 0 | if (@_) { | ||||
740 | 0 | return ( $self->cgiobj(@_) ); | |||||
741 | } | ||||||
742 | else { | ||||||
743 | 0 | return ( $self->cgiobj() ); | |||||
744 | } | ||||||
745 | } | ||||||
746 | |||||||
747 | ## # sub cgi_header_extra | ||||||
748 | ## # | ||||||
749 | ## # Purpose: accessor method to associate CGI header information | ||||||
750 | ## # with the CGI::Ajax object | ||||||
751 | ## # Arguments: a hashref with key=>value pairs that get handed off to | ||||||
752 | ## # the CGI object's header() method | ||||||
753 | ## # Returns: hashref of extra cgi header params | ||||||
754 | ## # Called By: originating cgi script, or build_html() | ||||||
755 | ## | ||||||
756 | ## sub cgi_header_extra { | ||||||
757 | ## my $self = shift; | ||||||
758 | ## if ( @_ ) { | ||||||
759 | ## $self->{'cgi_header_extra'} = shift; | ||||||
760 | ## } | ||||||
761 | ## return( $self->{'cgi_header_extra'} ); | ||||||
762 | ## } | ||||||
763 | |||||||
764 | # sub create_js_setRequestHeader | ||||||
765 | # | ||||||
766 | # Purpose: create text of the header for the javascript side, | ||||||
767 | # xmlhttprequest call | ||||||
768 | # Arguments: none | ||||||
769 | # Returns: text of header to pass to xmlhttpreq call so it will | ||||||
770 | # match whatever was setup for the main web-page | ||||||
771 | # Called By: originating cgi script, or build_html() | ||||||
772 | # | ||||||
773 | |||||||
774 | sub create_js_setRequestHeader { | ||||||
775 | 0 | 0 | 0 | my $self = shift; | |||
776 | 0 | my $cgi_header_extra = $self->cgi_header_extra(); | |||||
777 | 0 | my $js_header_string = q{r.setRequestHeader("}; | |||||
778 | |||||||
779 | #$js_header_string .= $self->cgi()->header( $cgi_header_extra ); | ||||||
780 | 0 | $js_header_string .= $self->getHeader; | |||||
781 | 0 | $js_header_string .= q{");}; | |||||
782 | |||||||
783 | #if ( ref $cgi_header_extra eq "HASH" ) { | ||||||
784 | # foreach my $k ( keys(%$cgi_header_extra) ) { | ||||||
785 | # $js_header_string .= $self->cgi()->header($cgi_headers) | ||||||
786 | # } | ||||||
787 | #} else { | ||||||
788 | #print STDERR $self->cgi()->header($cgi_headers) ; | ||||||
789 | |||||||
790 | 0 | 0 | if ( $self->DEBUG() ) { | ||||
791 | 0 | print STDERR "js_header_string is (", $js_header_string, ")\n"; | |||||
792 | } | ||||||
793 | |||||||
794 | 0 | return ($js_header_string); | |||||
795 | } | ||||||
796 | |||||||
797 | # sub show_common_js() | ||||||
798 | # | ||||||
799 | # Purpose: create text of the javascript needed to interface with | ||||||
800 | # the perl functions | ||||||
801 | # Arguments: none | ||||||
802 | # Returns: text of common javascript subroutine, 'do_http_request' | ||||||
803 | # Called By: originating cgi script, or build_html() | ||||||
804 | # | ||||||
805 | |||||||
806 | sub show_common_js { | ||||||
807 | 0 | 0 | 0 | my $self = shift; | |||
808 | 0 | my $fname = $self->fname(); | |||||
809 | 0 | my $encodefn = $self->js_encode_function(); | |||||
810 | 0 | my $decodefn = $encodefn; | |||||
811 | 0 | $decodefn =~ s/^(en)/de/; | |||||
812 | 0 | $decodefn =~ s/^(esc)/unesc/; | |||||
813 | |||||||
814 | #my $request_header_str = $self->create_js_setRequestHeader(); | ||||||
815 | 0 | my $request_header_str = ""; | |||||
816 | 0 | my $rv = < | |||||
817 | var ajax = []; | ||||||
818 | var cache; | ||||||
819 | |||||||
820 | function pjx(args,fname,method) { | ||||||
821 | this.target=args[1]; | ||||||
822 | this.args=args[0]; | ||||||
823 | method=(method)?method:'GET'; | ||||||
824 | if(method=='post'){method='POST';} | ||||||
825 | this.method = method; | ||||||
826 | this.r=ghr(); | ||||||
827 | this.url = this.getURL(fname); | ||||||
828 | } | ||||||
829 | |||||||
830 | function formDump(){ | ||||||
831 | var all = []; | ||||||
832 | var fL = document.forms.length; | ||||||
833 | for(var f = 0;f | ||||||
834 | var els = document.forms[f].elements; | ||||||
835 | for(var e in els){ | ||||||
836 | var tmp = (els[e].id != undefined)? els[e].id : els[e].name; | ||||||
837 | if(typeof tmp != 'string'){continue;} | ||||||
838 | if(tmp){ all[all.length]=tmp} | ||||||
839 | } | ||||||
840 | } | ||||||
841 | return all; | ||||||
842 | } | ||||||
843 | function getVal(id) { | ||||||
844 | if (id.constructor == Function ) { return id(); } | ||||||
845 | if (typeof(id)!= 'string') { return id; } | ||||||
846 | |||||||
847 | var element = document.getElementById(id); | ||||||
848 | if( !element ) { | ||||||
849 | for( var i=0; i | ||||||
850 | element = document.forms[i].elements[id]; | ||||||
851 | if( element ) break; | ||||||
852 | } | ||||||
853 | if( element && !element.type ) element = element[0]; | ||||||
854 | } | ||||||
855 | if(!element){ | ||||||
856 | alert('ERROR: Cant find HTML element with id or name: ' + | ||||||
857 | id+'. Check that an element with name or id='+id+' exists'); | ||||||
858 | return 0; | ||||||
859 | } | ||||||
860 | |||||||
861 | if(element.type == 'select-one') { | ||||||
862 | if(element.selectedIndex == -1) return; | ||||||
863 | var item = element[element.selectedIndex]; | ||||||
864 | return item.value || item.text; | ||||||
865 | } | ||||||
866 | if(element.type == 'select-multiple') { | ||||||
867 | var ans = []; | ||||||
868 | var k =0; | ||||||
869 | for (var i=0;i | ||||||
870 | if (element[i].selected || element[i].checked ) { | ||||||
871 | ans[k++]= element[i].value || element[i].text; | ||||||
872 | } | ||||||
873 | } | ||||||
874 | return ans; | ||||||
875 | } | ||||||
876 | if(element.type == 'radio' || element.type == 'checkbox'){ | ||||||
877 | var ans =[]; | ||||||
878 | var elms = document.getElementsByTagName('input'); | ||||||
879 | var endk = elms.length ; | ||||||
880 | var i =0; | ||||||
881 | for(var k=0;k | ||||||
882 | if(elms[k].type== element.type && elms[k].checked && (elms[k].id==id||elms[k].name==id)){ | ||||||
883 | ans[i++]=elms[k].value; | ||||||
884 | } | ||||||
885 | } | ||||||
886 | return ans; | ||||||
887 | } | ||||||
888 | if( element.value == undefined ){ | ||||||
889 | return element.innerHTML; | ||||||
890 | }else{ | ||||||
891 | return element.value; | ||||||
892 | } | ||||||
893 | } | ||||||
894 | function fnsplit(arg) { | ||||||
895 | var url=""; | ||||||
896 | if(arg=='NO_CACHE'){cache = 0; return "";}; | ||||||
897 | if((typeof(arg)).toLowerCase() == 'object'){ | ||||||
898 | for(var k in arg){ | ||||||
899 | url += '&' + k + '=' + arg[k]; | ||||||
900 | } | ||||||
901 | }else if (arg.indexOf('__') != -1) { | ||||||
902 | arga = arg.split(/__/); | ||||||
903 | url += '&' + arga[0] +'='+ $encodefn(arga[1]); | ||||||
904 | } else { | ||||||
905 | var res = getVal(arg) || ''; | ||||||
906 | if(res.constructor != Array){ res = [res] } | ||||||
907 | else if( res.length == 0 ) { res = [ '' ] } | ||||||
908 | for(var i=0;i | ||||||
909 | url += '&args=' + $encodefn(res[i]) + '&' + arg + '=' + $encodefn(res[i]); | ||||||
910 | } | ||||||
911 | } | ||||||
912 | return url; | ||||||
913 | } | ||||||
914 | |||||||
915 | pjx.prototype = { | ||||||
916 | send2perl : function(){ | ||||||
917 | var r = this.r; | ||||||
918 | var dt = this.target; | ||||||
919 | if (dt==undefined) { return true; } | ||||||
920 | this.pjxInitialized(dt); | ||||||
921 | var url=this.url; | ||||||
922 | var postdata; | ||||||
923 | if(this.method=="POST"){ | ||||||
924 | var idx=url.indexOf('?'); | ||||||
925 | postdata = url.substr(idx+1); | ||||||
926 | url = url.substr(0,idx); | ||||||
927 | } | ||||||
928 | r.open(this.method,url,true); | ||||||
929 | $request_header_str; | ||||||
930 | if(this.method=="POST"){ | ||||||
931 | r.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); | ||||||
932 | r.send(postdata); | ||||||
933 | } | ||||||
934 | if(this.method=="GET"){ | ||||||
935 | r.send(null); | ||||||
936 | } | ||||||
937 | r.onreadystatechange = handleReturn; | ||||||
938 | }, | ||||||
939 | pjxInitialized : function(){}, | ||||||
940 | pjxCompleted : function(){}, | ||||||
941 | readyState4 : function(){ | ||||||
942 | var rsp = $decodefn(this.r.responseText); /* the response from perl */ | ||||||
943 | var splitval = '__pjx__'; /* to split text */ | ||||||
944 | /* fix IE problems with undef values in an Array getting squashed*/ | ||||||
945 | rsp = rsp.replace(splitval+splitval+'g',splitval+" "+splitval); | ||||||
946 | var data = rsp.split(splitval); | ||||||
947 | dt = this.target; | ||||||
948 | if (dt.constructor != Array) { dt=[dt]; } | ||||||
949 | if (data.constructor != Array) { data=[data]; } | ||||||
950 | if (typeof(dt[0])!='function') { | ||||||
951 | for ( var i=0; i | ||||||
952 | var div = document.getElementById(dt[i]); | ||||||
953 | if (div.type =='text' || div.type=='textarea' || div.type=='hidden' ) { | ||||||
954 | div.value=data[i]; | ||||||
955 | } else if (div.type =='checkbox') { | ||||||
956 | div.checked=data[i]; | ||||||
957 | } else { | ||||||
958 | div.innerHTML = data[i]; | ||||||
959 | } | ||||||
960 | } | ||||||
961 | } else if (typeof(dt[0])=='function') { | ||||||
962 | dt[0].apply(this,data); | ||||||
963 | } | ||||||
964 | this.pjxCompleted(dt); | ||||||
965 | }, | ||||||
966 | |||||||
967 | getURL : function(fname) { | ||||||
968 | var args = this.args; | ||||||
969 | var url= '$fname=' + fname; | ||||||
970 | for (var i=0;i | ||||||
971 | url=url + args[i]; | ||||||
972 | } | ||||||
973 | return url; | ||||||
974 | } | ||||||
975 | }; | ||||||
976 | |||||||
977 | handleReturn = function() { | ||||||
978 | for( var k=0; k | ||||||
979 | if (ajax[k].r==null) { ajax.splice(k--,1); continue; } | ||||||
980 | if ( ajax[k].r.readyState== 4) { | ||||||
981 | ajax[k].readyState4(); | ||||||
982 | ajax.splice(k--,1); | ||||||
983 | continue; | ||||||
984 | } | ||||||
985 | } | ||||||
986 | }; | ||||||
987 | |||||||
988 | var ghr=getghr(); | ||||||
989 | function getghr(){ | ||||||
990 | if(typeof XMLHttpRequest != "undefined") | ||||||
991 | { | ||||||
992 | return function(){return new XMLHttpRequest();} | ||||||
993 | } | ||||||
994 | var msv= ["Msxml2.XMLHTTP.7.0", "Msxml2.XMLHTTP.6.0", | ||||||
995 | "Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", | ||||||
996 | "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"]; | ||||||
997 | for(var j=0;j<=msv.length;j++){ | ||||||
998 | try | ||||||
999 | { | ||||||
1000 | A = new ActiveXObject(msv[j]); | ||||||
1001 | if(A){ | ||||||
1002 | return function(){return new ActiveXObject(msv[j]);} | ||||||
1003 | } | ||||||
1004 | } | ||||||
1005 | catch(e) { } | ||||||
1006 | } | ||||||
1007 | return false; | ||||||
1008 | } | ||||||
1009 | |||||||
1010 | |||||||
1011 | function jsdebug(){ | ||||||
1012 | var tmp = document.getElementById('pjxdebugrequest').innerHTML = ""; |
||||||
1013 | for( var i=0; i < ajax.length; i++ ) { | ||||||
1014 | tmp += '' + | ||||||
1015 | decodeURI(ajax[i].url) + ' <' + '/a> '; |
||||||
1016 | } | ||||||
1017 | document.getElementById('pjxdebugrequest').innerHTML = tmp + "<" + "/pre>"; | ||||||
1018 | } | ||||||
1019 | |||||||
1020 | EOT | ||||||
1021 | |||||||
1022 | 0 | 0 | if ( $self->JSDEBUG() <= 1 ) { | ||||
1023 | 0 | $rv = $self->compress_js($rv); | |||||
1024 | } | ||||||
1025 | |||||||
1026 | 0 | return ($rv); | |||||
1027 | } | ||||||
1028 | |||||||
1029 | # sub compress_js() | ||||||
1030 | # | ||||||
1031 | # Purpose: searches the javascript for newlines and spaces and | ||||||
1032 | # removes them (if a newline) or shrinks them to a single (if | ||||||
1033 | # space). | ||||||
1034 | # Arguments: javascript to compress | ||||||
1035 | # Returns: compressed js string | ||||||
1036 | # Called By: show_common_js(), | ||||||
1037 | # | ||||||
1038 | |||||||
1039 | sub compress_js { | ||||||
1040 | 0 | 0 | 0 | my ( $self, $js ) = @_; | |||
1041 | 0 | 0 | return if not defined $js; | ||||
1042 | 0 | 0 | return if $js eq ""; | ||||
1043 | 0 | $js =~ s/\n//g; # drop newlines | |||||
1044 | 0 | $js =~ s/\s+/ /g; # replace 1+ spaces with just one space | |||||
1045 | 0 | return $js; | |||||
1046 | } | ||||||
1047 | |||||||
1048 | # sub insert_js_in_head() | ||||||
1049 | # | ||||||
1050 | # Purpose: searches the html value in the CGI::Ajax object and inserts | ||||||
1051 | # the ajax javascript code in the section, | ||||||
1052 | # or if no such section exists, then it creates it. If | ||||||
1053 | # JSDEBUG is set, then an extra div will be added and the | ||||||
1054 | # url will be displayed as a link | ||||||
1055 | # Arguments: none | ||||||
1056 | # Returns: none | ||||||
1057 | # Called By: build_html() | ||||||
1058 | # | ||||||
1059 | |||||||
1060 | sub insert_js_in_head { | ||||||
1061 | 0 | 0 | 0 | my $self = shift; | |||
1062 | 0 | my $mhtml = $self->html(); | |||||
1063 | 0 | my $newhtml; | |||||
1064 | my @shtml; | ||||||
1065 | 0 | my $js = $self->show_javascript(); | |||||
1066 | |||||||
1067 | 0 | 0 | if ( $self->JSDEBUG() ) { | ||||
1068 | 0 | my $showurl = qq! !; |
|||||
1069 | |||||||
1070 | # find the terminal |
so we can insert just before it