File Coverage

blib/lib/OpenThought.pm
Criterion Covered Total %
statement 9 196 4.5
branch 0 66 0.0
condition 0 28 0.0
subroutine 3 17 17.6
pod 7 8 87.5
total 19 315 6.0


line stmt bran cond sub pod time code
1             # This file is Copyright (c) 2000-2007 Eric Andreychek. All rights reserved.
2             # For distribution terms, please see the included LICENSE file.
3              
4             package OpenThought;
5              
6             =head1 NAME
7              
8             OpenThought - An AJAX transport and helper library, making AJAX-based page updates trivial
9              
10             =head1 SYNOPSIS
11              
12             use OpenThought();
13             use CGI();
14              
15             my $OT = OpenThought->new();
16             my $q = CGI->new;
17              
18             # First, put everything you wish to give to the browser into a hash
19             my ($fields, $html, $image);
20             $fields->{'myTextBox'} = "Text Box Data";
21             $fields->{'myCheckbox'} = "true";
22             $fields->{'myRadioBtn'} = "RadioBtn2Value";
23             $fields->{'mySelectList'} = [
24             [ "text1", "value1" ],
25             [ "text2", "value2" ],
26             [ "text3", "value3" ],
27             ];
28              
29             $html->{'id_tagname'} = "New HTML Code";
30              
31             $image->{'image_name'} = "http://example.com/my_image.gif";
32              
33             # You can also execute JavaScript, just put it into a scalar
34             my $javascript_code = "alert('Howdy!')";
35              
36             # Then send it to the browser using:
37              
38             $OT->param( $fields );
39             $OT->param( $html );
40             $OT->param( $image );
41             $OT->focus( "myTextBox" );
42             $OT->javascript( $javascript_code );
43              
44             print $q->header:
45             print $OT->response();
46              
47             # Or use the utility method:
48             print $q->header;
49             print $OT->response( param => $fields,
50             param => $html,
51             param => $image,
52             focus => "myTextBox",
53             javascript => $javascript_code,
54             );
55              
56              
57             # In a seperate HTML file, you might have this (which is where you'd first
58             # point the browser, the HTML then calls the Perl when you click the button or
59             # select list)
60            
61            
62            
63            
64            
65            
66            
67            
68            
69            
70                         'http://example.com/my_openthought_app.pl', 'mySelectList')">
72             HTML Code will go here
73              
74             // Sends the current value of the textbox 'myTextBox', as well as the
75             // param 'this' with the value of 'that', to 'my_openthought_app.pl'.
76             77             'http://example.com/my_openthought_app.pl', 'myTextBox', 'this=that')">
78            
79            
80            
81              
82             =head1 DESCRIPTION
83              
84             OpenThought is a library which implements an API for AJAX communication and
85             updates. You can perform updates to form fields, HTML, call JavaScript
86             functions, and more with a trivial amount of code. OpenThought strives to
87             provide a simple yet powerful and flexible means for creating AJAX
88             applications.
89              
90             The interface is simple -- you just build a hash. Hash keys are mapped to
91             field names or id tags in the HTML. The value your hash keys contain is
92             dynamically inserted into the corresponding field (without reloading the page).
93              
94             ==head1 COMPATABILITY
95              
96             OpenThought is compatible with a wide range of browsers, including Internet
97             Explorer 4+, Netscape 4+, Mozilla/Firefox, Safari, Opera, Konqeueror, and
98             others. It detects the browsers capabilities; if the browser doesn't support
99             new functions such as XMLHttpRequest or XMLHTTP, it falls back to using
100             iframes.
101              
102             =head1 METHODS
103              
104             =cut
105              
106 1     1   1371 use strict;
  1         4  
  1         46  
107 1     1   7 use Carp;
  1         2  
  1         125  
108              
109             $OpenThought::VERSION="1.99.16";
110              
111             $OpenThought::DEBUG ||= 0;
112              
113 1     1   17 use vars qw( $DEBUG );
  1         2  
  1         2732  
114              
115              
116             #/-------------------------------------------------------------------------
117             # function: new
118             #
119              
120             =pod
121              
122             =over 4
123              
124             =item new()
125              
126             $OT = OpenThought->new();
127              
128             Creates a new OpenThought object.
129              
130             =item Return Value
131              
132             =over 4
133              
134             =item $OT
135              
136             OpenThought object.
137              
138             =back
139              
140             =back
141              
142             =cut
143              
144             # The main OpenThought constructor
145             sub new {
146 0     0 1   my ( $pkg, $args ) = @_;
147              
148 0   0       $args ||= {};
149              
150 0   0       my $class = ref $pkg || $pkg;
151              
152 0           my $self = {
153              
154 0   0       %{ $args },
155              
156             _persist => $args->{persist} || 0,
157              
158             };
159              
160 0           bless ($self, $class);
161              
162 0           $self->_init();
163              
164 0           return $self;
165             }
166              
167             sub _init {
168 0     0     my $self = shift;
169              
170 0           my @settings = qw(
171             log_enabled
172             log_level
173             require
174             channel_type
175             channel_visible
176             channel_url_replace
177             selectbox_max_width
178             selectbox_trim_string
179             selectbox_single_row_mode
180             selectbox_multi_row_mode
181             checkbox_true_value
182             checkbox_false_value
183             radio_null_selection_value
184             data_mode
185             );
186              
187 0 0         delete $self->{_settings} if exists $self->{_settings};
188              
189 0           foreach my $setting ( @settings ) {
190 0           $self->{_settings}{$setting} = [];
191             }
192              
193 0           $self->{_response} = [];
194              
195             }
196              
197              
198             # Generate, in the proper order, the serialized params and settings
199             sub output {
200 0     0 0   my $self = shift;
201              
202 0           my ( $save, $serialized_data, $restore );
203 0           $save = $serialized_data = $restore = "";
204              
205 0           my @settings;
206 0           foreach my $setting ( keys %{ $self->{_settings} } ) {
  0            
207             # There needs to be at least one passed in
208 0 0         next unless scalar @{ $self->{_settings}{$setting} } > 0;
  0            
209              
210 0           $serialized_data .= join '', @{ $self->{_settings}{$setting} };
  0            
211 0           push @settings, $setting;
212             }
213              
214             # Grab all the response data (params, focus, url, javascript, etc)
215 0           $serialized_data .= join '', @{ $self->{_response} };
  0            
216              
217             # Save/restore the current settings unless told to make them
218             # persist
219 0 0         unless( $self->{settings_persist} ) {
220 0 0         if (@settings) {
221 0           $save .= $self->_settings_save( @settings );
222 0           $restore .= $self->_settings_restore( @settings );
223             }
224             }
225              
226             # Hands JavaScript code to the browser. The browser processes the data
227             # automatically as we hand it over -- as far as the browser is concerned,
228             # it is simply loading a new page now (but in the hidden frame).
229 0           my $code = $self->_add_tags( "${save}${serialized_data}${restore}");
230              
231 0 0         $DEBUG && carp $code ;
232              
233 0           return $code;
234              
235             }
236              
237             *auto_param = \¶m;
238             *fields = \¶m;
239             *html = \¶m;
240             *images = \¶m;
241              
242             # The user has html, input fields, or images they want displayed in the browser
243             sub param {
244 0     0 1   my ( $self, $data, $options ) = @_;
245              
246 0 0         if (ref $data eq "ARRAY") {
247 0   0       $options = $data->[1] || {};
248 0   0       $data = $data->[0] || {};
249             }
250              
251 0           $data = $self->_as_javascript( $data );
252              
253 0           my $save = "";
254 0           my $restore = "";
255 0 0         if ($options) {
256 0           $save = $self->_settings_save( keys %{ $options } ) .
  0            
257             $self->settings($options, 1);
258 0           $restore = $self->_settings_restore( keys %{ $options } );
  0            
259             }
260              
261 0           $data = "${save}parent.OpenThought.ServerResponse(${data});${restore}";
262              
263 0           push @{ $self->{_response} }, $data;
  0            
264              
265 0           return $self->_add_tags($data);
266             }
267              
268             # Calls the Focus function within the browser, which in turn takes the
269             # cursor and puts it into a particular field
270             sub focus {
271 0     0 1   my ( $self, $field ) = @_;
272              
273 0           my $data = " parent.OpenThought.Focus('$field');";
274              
275 0           push @{ $self->{_response} }, $data;
  0            
276              
277 0           return $self->_add_tags($data);
278             }
279              
280             # Send Javascript code to be interpreted by the browser. This would often be
281             # used to call a user defined Javascript function.. an example application of
282             # this would be to use the dynapi Dynamic HTML API Library to create and
283             # manipulate DHTML objects from the server.
284             sub javascript {
285 0     0 1   my ( $self, $javascript_code ) = @_;
286              
287             # NOTE: it really doesn't work to escape the JS! The developer needs to do
288             # it themselves...
289 0           my $data = " with (parent.document) { $javascript_code }";
290              
291 0           push @{ $self->{_response} }, $data;
  0            
292              
293 0           return $self->_add_tags($data);
294             }
295              
296             # Jump to a new page with this url
297             sub url {
298 0     0 1   my ( $self, $url ) = @_;
299              
300 0 0         unless ( $url ) {
301 0           croak "You're missing the parameter to 'url'.";
302             }
303              
304 0           my $javascript_code;
305              
306 0 0         if ( ref $url eq "ARRAY" ) {
    0          
307 0 0         if ( $url->[0] ) {
308 0 0         unless ( not ref $url->[0] ) {
309 0           croak "The first element of the arrayref passed into 'url' should be a scalar containing the url.";
310             }
311              
312 0           $javascript_code = "parent.OpenThought.FetchHtml('$url->[0]'";
313             }
314 0 0         if ( $url->[1] ) {
315 0 0         unless ( ref $url->[1] eq "HASH" ) {
316 0           croak "The second element of the arrayref passed into 'url' is optional, but if supplied, must be a hashref.";
317             }
318 0           foreach my $param ( keys %{ $url->[1] } ) {
  0            
319 0 0         if ( defined $url->[1]->{ $param } ) {
320 0           $javascript_code .= ",'$param=$url->[1]{ $param }'";
321             }
322             else {
323 0           $javascript_code .= ",'$param'";
324             }
325             }
326             }
327             }
328             elsif ( not ref $url ) {
329 0           $javascript_code = "parent.OpenThought.FetchHtml('$url'";
330             }
331             else {
332 0           croak "The 'url' method takes either a scalar containing the url, or an an arrayref containing both the url and a hashref with url parameters.";
333             }
334              
335 0           $javascript_code .= ");";
336              
337 0           push @{ $self->{_response} }, $javascript_code;
  0            
338              
339 0           return $self->_add_tags($javascript_code);
340             }
341              
342             # Alter settings within the existing OpenThought Application
343             sub settings {
344 0     0 1   my ( $self, $settings, $return_only ) = @_;
345              
346 0 0         unless ( ref $settings eq "HASH" ){
347 0           croak "When you pass in settings, they need to be a hash " .
348             'reference. Either $OT->settings( \%settings ) or ' .
349             '$OT->response( settings => \%settings ).';
350             }
351              
352 0           my $data;
353 0           foreach my $name ( keys %{ $settings } ) {
  0            
354             # Persist is special as well. It defines whether the settings
355             # being sent are to remain for the life of this page, or just for this
356             # current request.
357 0 0         if( $name eq "settings_persist" ) {
    0          
358 0           $self->{settings_persist} = $settings->{$name};
359             }
360              
361             # All other parameters are treated the same here
362             elsif ( $self->{_settings}{$name} ) {
363 0           my $setting = "parent.OpenThought.config.$name = \"" .
364             # $self->_escape_javascript( $settings->{$name} ) . "\");";
365             $self->_escape_javascript( $settings->{$name} ) . "\";";
366              
367 0 0         unless ($return_only) {
368 0           push @{ $self->{_settings}{$name} }, $setting;
  0            
369             }
370              
371 0           $data .= $setting;
372              
373             }
374             else {
375 0           carp "No such setting [$name].";
376             }
377             }
378              
379 0 0         if ($return_only) {
380 0           return $data;
381             }
382             else {
383 0           return $self->_add_tags($data);
384             }
385             }
386              
387              
388             =pod
389              
390             =over 4
391              
392             =item param()
393              
394             $OT->param( \%data, [ \%settings ] );
395              
396             Update input-type form field elements (text boxes, radio buttons, checkboxes,
397             select lists, text areas, etc), HTML elements, as well as images an image attributes.
398              
399             This method accepts a hash reference containing keys which map to field
400             names, html id's, and image names.
401              
402             The form element, html id, or image will be dynamically updated to contain the value found within the
403             hash key.
404              
405             B: These are very straight forward. The hash
406             values are inserted directly into the input fields matching the hash keys.
407              
408             B: The value for the hash key should match the C
409             attribute of the radio button element in your HTML code. When the hash key and
410             value matches the radio button name and value, that radio button will become
411             checked.
412              
413             B
414             that data to be appended to the select list. In contrast, sending data as a
415             reference to an array of arrays or an array of hashes will cause any values
416             within the select list to be overwritten with the new data.
417              
418             You can modify this select list behaviour by using the
419             C and C options.
420              
421             When sending data to a select list (which, as we said, is done as an array),
422             the first element of the array is the text to be displayed, the second element
423             is the underlying value associated with that text.
424              
425             Sending a single scalar value to a select list highlights the corresponding
426             entry in the select list which contains that value.
427              
428             Sending undef, or a reference to an array with an empty string as it's only
429             element will cause the select list to be cleared.
430              
431             B: It accepts a hash reference containing keys which map to HTML id attributes.
432             You can add id tags for nearly any HTML attribute. The hash values are inserted
433             within the html containing an id tag matching the hash key (using innerHtml). The data may contain HTML
434             tags, which will be correctly displayed.
435              
436             $OT->param({ "html_id_tag" => "foo" }).
437              
438             B: To change an image or image property, the hash key should be the image name. If you just want
439             to load a new image, the hash value should be a scalar containing the url of the new image.
440              
441             $OT->param({ foo => 'http://example.com/new_image.jpg' });
442              
443             $OT->param({ foo => { width => 100,
444             height => 150, });
445              
446             B: The second optional parameter is a hash reference of settings that will
447             effect just the data passed into this call of C. See the C method for a list of
448             available options.
449              
450             =item javascript()
451              
452             $OT->javascript( "alert('Howdy');" );
453              
454             This allows you to run JavaScript code, along with accessing JavaScript
455             functions and variables.
456              
457             It accepts a string containing the JavaScript code you wish to execute. There
458             is no need to add script tags, they will be added for you.
459              
460             =item focus()
461              
462             $OT->focus( "field_name" );
463              
464             This allows you to focus a given input field or anchor tag.
465              
466             It accepts a string containing the name of the field or anchor tag you wish to
467             focus. If it's a field, it will be given the cursor. If it's an anchor tag,
468             the browser will jump to it's position on the page.
469              
470             =item url()
471              
472             $OT->url( "http://example.com/my_openthought_app.pl" );
473              
474             $OT->url([ "http://example.com/my_openthought_app.pl" =>
475             { example_param => some_value,
476             param2 => another_value } ]);
477              
478             The C method loads new page.
479              
480             This method can be used by passing in the url as a scalar, or by passing in the
481             url and url parameters within an arrayref. If you pass in an arrayref, the
482             first element of the array should be the url, the second element should be a
483             hash reference whose keys and values will be passed on as parameters to the new
484             url.
485              
486             =item settings
487              
488             $OT->settings({
489             settings_persist => boolean,
490             log_start => string,
491             log_level => string,
492             require => { ... },
493             http_request_type => string,
494             channel_type => string,
495             channel_visible => boolean,
496             channel_url_replace => boolean,
497             selectbox_max_width => size,
498             selectbox_trim_string => string,
499             selectbox_single_row_mode => string,
500             selectbox_multi_row_mode => string,
501             checkbox_true_value => string,
502             checkbox_false_value => string,
503             radio_null_selection_value => string,
504             data_mode => string,
505             });
506              
507             Alter settings in the OpenThought application running in the browser. Each
508             parameter is optional. Only pass in the option(s) you wish to change.
509              
510             For additional information on configuration, and for how/where to set the
511             defaults, please see the section labeled C.
512              
513             This method accepts a hash reference where the keys are names of OpenThought
514             options, and the values are the new option values.
515              
516             By default, these options will only be good for one request. You can change
517             that behaviour by either passing in the C option to this method.
518              
519             You can set the defaults for most of these settings at the top of the
520             OpenThought.js file.
521              
522             =over 4
523              
524             =item Parameters
525              
526             =over 4
527              
528             =item settings_persist()
529              
530             $OT->settings({ settings_persist => "true" });
531              
532             This specifies whether or not the settings being changed in the browser should
533             be just for this request, or whether they should persist as long as the current
534             page is loaded.
535              
536             The default is to not persist.
537              
538             If you use this parameter, only items you specify will be executed. That is,
539             if you fail to mention where C should be in the order, then C
540             will be completely ignored for that request.
541              
542             If C is not last, everything sent after it will be lost when the page
543             changes.
544              
545             =item log_enabled
546              
547             $OT->settings({ log_enabled => "true" });
548              
549             Enable a log window so you can see what's going on behind the scenes. If
550             something in your app isn't working, try enabling this. This can be very
551             useful for debugging, but you probably want it disabled while your app is in
552             production. This, of course, won't work if your popup blocking software
553             doesn't allow popups from the site you're running your application from.
554              
555             =item log_level
556              
557             $OT->settings({ log_level => "info" });
558              
559             What log level to run at. You have the ability to enable lots of debugging
560             output, only serious errors, and various levels in between.
561              
562             Options are C, C, C, C, C
563              
564             =item require
565              
566             $OT->settings({ require =>
567             { "40dom" => "http://example.com/no_40dom",
568             "xmlhttp" => "http://example.com/no_xmlhttp",
569             } })
570              
571             Define a set of browser requirements, and a page to go to if that requirement
572             is not met.
573              
574             Available requirements are C<40dom>, C, C, C