NAME

OpenThought - An AJAX transport and helper library, making AJAX-based page updates trivial

SYNOPSIS

 use OpenThought();
 use CGI();

 my $OT = OpenThought->new();
 my $q  = CGI->new;

 # First, put everything you wish to give to the browser into a hash
 my ($fields, $html, $image);
 $fields->{'myTextBox'}    = "Text Box Data";
 $fields->{'myCheckbox'}   = "true";
 $fields->{'myRadioBtn'}   = "RadioBtn2Value";
 $fields->{'mySelectList'} = [
                               [ "text1", "value1" ],
                               [ "text2", "value2" ],
                               [ "text3", "value3" ],
                             ];

 $html->{'id_tagname'} = "<b>New HTML Code</b>";

 $image->{'image_name'} = "http://example.com/my_image.gif";

 # You can also execute JavaScript, just put it into a scalar
 my $javascript_code = "alert('Howdy!')";

 # Then send it to the browser using:

 $OT->param( $fields );
 $OT->param( $html );
 $OT->param( $image );
 $OT->focus( "myTextBox" );
 $OT->javascript( $javascript_code );

 print $q->header:
 print $OT->response();

 # Or use the utility method:
 print $q->header;
 print $OT->response( param      => $fields,
                      param      => $html,
                      param      => $image,
                      focus      => "myTextBox",
                      javascript => $javascript_code,
                    );


 # In a seperate HTML file, you might have this (which is where you'd first
 # point the browser, the HTML then calls the Perl when you click the button or
 # select list)
 <html>
   <head>
     <script src="OpenThought.js"></script>
   </head>
   <body>
   <form name="my_form" onSubmit="return false">
     <input type="text" name="myTextBox">
     <input type="checkbox" name="myCheckbox">
     <input type="radio" name="myRadioBtn" value="RadioBtn1value">
     <input type="radio" name="myRadioBtn" value="RadioBtn2value">
     <select name="mySelectList" onChange="OpenThought.CallUrl(
                'http://example.com/my_openthought_app.pl', 'mySelectList')">
     <span id="id_tag_name">HTML Code will go here</span>

     // Sends the current value of the textbox 'myTextBox', as well as the
     // param 'this' with the value of 'that', to 'my_openthought_app.pl'.
     <input type="button" onClick="OpenThought.CallUrl(
                'http://example.com/my_openthought_app.pl', 'myTextBox', 'this=that')">
  </form>
  </body>
 </html>

DESCRIPTION

OpenThought is a library which implements an API for AJAX communication and updates. You can perform updates to form fields, HTML, call JavaScript functions, and more with a trivial amount of code. OpenThought strives to provide a simple yet powerful and flexible means for creating AJAX applications.

The interface is simple -- you just build a hash. Hash keys are mapped to field names or id tags in the HTML. The value your hash keys contain is dynamically inserted into the corresponding field (without reloading the page).

==head1 COMPATABILITY

OpenThought is compatible with a wide range of browsers, including Internet Explorer 4+, Netscape 4+, Mozilla/Firefox, Safari, Opera, Konqeueror, and others. It detects the browsers capabilities; if the browser doesn't support new functions such as XMLHttpRequest or XMLHTTP, it falls back to using iframes.

METHODS

new()
 $OT = OpenThought->new();

Creates a new OpenThought object.

Return Value
$OT

OpenThought object.

param()
 $OT->param( \%data, [ \%settings ] );

Update input-type form field elements (text boxes, radio buttons, checkboxes, select lists, text areas, etc), HTML elements, as well as images an image attributes.

This method accepts a hash reference containing keys which map to field names, html id's, and image names.

The form element, html id, or image will be dynamically updated to contain the value found within the hash key.

Text, Textarea, Password fields: These are very straight forward. The hash values are inserted directly into the input fields matching the hash keys.

Radio buttons: The value for the hash key should match the value attribute of the radio button element in your HTML code. When the hash key and value matches the radio button name and value, that radio button will become checked.

Select Lists: Sending a single array reference to a select list will cause that data to be appended to the select list. In contrast, sending data as a reference to an array of arrays or an array of hashes will cause any values within the select list to be overwritten with the new data.

You can modify this select list behaviour by using the selectbox_single_row_mode and selectbox_multi_row_mode options.

When sending data to a select list (which, as we said, is done as an array), the first element of the array is the text to be displayed, the second element is the underlying value associated with that text.

Sending a single scalar value to a select list highlights the corresponding entry in the select list which contains that value.

Sending undef, or a reference to an array with an empty string as it's only element will cause the select list to be cleared.

HTML elements: It accepts a hash reference containing keys which map to HTML id attributes. You can add id tags for nearly any HTML attribute. The hash values are inserted within the html containing an id tag matching the hash key (using innerHtml). The data may contain HTML tags, which will be correctly displayed.

 $OT->param({ "html_id_tag" => "<b>foo</b>" }).

Images: To change an image or image property, the hash key should be the image name. If you just want to load a new image, the hash value should be a scalar containing the url of the new image.

 $OT->param({ foo => 'http://example.com/new_image.jpg' });

 $OT->param({ foo => { width  => 100,
                       height => 150, });

Optional Parameter: Settings: The second optional parameter is a hash reference of settings that will effect just the data passed into this call of param(). See the settings() method for a list of available options.

javascript()
 $OT->javascript( "alert('Howdy');" );

This allows you to run JavaScript code, along with accessing JavaScript functions and variables.

It accepts a string containing the JavaScript code you wish to execute. There is no need to add script tags, they will be added for you.

focus()
 $OT->focus( "field_name" );

This allows you to focus a given input field or anchor tag.

It accepts a string containing the name of the field or anchor tag you wish to focus. If it's a field, it will be given the cursor. If it's an anchor tag, the browser will jump to it's position on the page.

url()
 $OT->url( "http://example.com/my_openthought_app.pl" );

 $OT->url([ "http://example.com/my_openthought_app.pl" =>
               { example_param => some_value,
                 param2        => another_value } ]);

The url method loads new page.

This method can be used by passing in the url as a scalar, or by passing in the url and url parameters within an arrayref. If you pass in an arrayref, the first element of the array should be the url, the second element should be a hash reference whose keys and values will be passed on as parameters to the new url.

settings
 $OT->settings({
                        settings_persist           => boolean,
                        log_start                  => string,
                        log_level                  => string,
                        require                    => { ... },
                        http_request_type          => string,
                        channel_type               => string,
                        channel_visible            => boolean,
                        channel_url_replace        => boolean,
                        selectbox_max_width        => size,
                        selectbox_trim_string      => string,
                        selectbox_single_row_mode  => string,
                        selectbox_multi_row_mode   => string,
                        checkbox_true_value        => string,
                        checkbox_false_value       => string,
                        radio_null_selection_value => string,
                        data_mode                  => string,
                     });

Alter settings in the OpenThought application running in the browser. Each parameter is optional. Only pass in the option(s) you wish to change.

For additional information on configuration, and for how/where to set the defaults, please see the section labeled CONFIGURATION.

This method accepts a hash reference where the keys are names of OpenThought options, and the values are the new option values.

By default, these options will only be good for one request. You can change that behaviour by either passing in the persist option to this method.

You can set the defaults for most of these settings at the top of the OpenThought.js file.

Parameters
settings_persist()
 $OT->settings({ settings_persist => "true" });

This specifies whether or not the settings being changed in the browser should be just for this request, or whether they should persist as long as the current page is loaded.

The default is to not persist.

If you use this parameter, only items you specify will be executed. That is, if you fail to mention where fields should be in the order, then fields will be completely ignored for that request.

If url is not last, everything sent after it will be lost when the page changes.

log_enabled
 $OT->settings({ log_enabled => "true" });

Enable a log window so you can see what's going on behind the scenes. If something in your app isn't working, try enabling this. This can be very useful for debugging, but you probably want it disabled while your app is in production. This, of course, won't work if your popup blocking software doesn't allow popups from the site you're running your application from.

log_level
 $OT->settings({ log_level => "info" });

What log level to run at. You have the ability to enable lots of debugging output, only serious errors, and various levels in between.

Options are debug, info, warn, error, fatal

require
 $OT->settings({ require =>
                        { "40dom" => "http://example.com/no_40dom",
                          "xmlhttp" => "http://example.com/no_xmlhttp",
                        } })

Define a set of browser requirements, and a page to go to if that requirement is not met.

Available requirements are 40dom, xmlhttp, layer, iframe, htmlrewrite.

http_request_type (EXPERIMENTAL)
 $OT->settings({ http_request_type => "POST" });

The request type for communications with the server. This can be overridden at any time by passing in either GET or POST as the first parameter to CallUrl(). The default (and known to work) option is GET.

Using POST has only been minimally tested. There have been problems noted when using Firefox and POST, if the channel_type option was changed from auto to iframes. This appears to be a Firefox bug.

Options are GET or POST (case sensitive).

channel_type
 $OT->settings({ channel_type => "iframe" });

The type of channel to use for communicating with the browser.

By default, OpenThought will attempt to use the XMLHttpRequest or XMLHTTP functions available in recent browsers, then fall back to iframes if the browser doesn't support those newer options.

However, XMLHttpRequest and XMLHTTP have one limitation -- for any given request, the server can only respond once, and the response is all at the same time.

Iframes don't have that restriction, and the server can send a variety of responses throughout the duration of the request.

XMLHttpRequest/XMLHTTP are fine for most uses, but some applications may benefit from being able to have the browser receive data a number of times throughtout a single request (ie, irc and other realtime chat applications).

Options are auto or iframe.

channel_visible
 $OT->settings({ channel_visible => "true" });

Normally, the channel used to communicate with the server is invisible. The curious may wish to see whats going on inside it (or perhaps need it for debugging). Enabling the following will make the channel visible. This only works if the channel is an iframe (which means it's either an older browser, or that you have channel_type set to iframe.

url_replace
 $OT->settings({ url_replace => "true" });

When using iframes and layers, the typical way to submit ajax requests to the server involves using a 'document.location.replace()'. This means the requests aren't being stored in the browser history. So, the back button will take you to the previous *page*, not the previous AJAX request. This is often what people want. This sometimes isn't what people want :-) Set to 'true' to not add AJAX requests to the browser's history, set to 'false' to have them added to the history.

This option has no effect when using XMLHttpRequest/XMLHTTP.

Options are true or false.

url_prefix
 $OT->settings({ url_prefix => "include/" });

During any call to the server (via CallUrl and FetchHtml), assume the script is located in this directory (ie, the file/dir you pass in is relative to this path). If there's no trailing slash, it will add one. This config option can be overridden by beginning the url with 'http' or '/'.

selectbox_single_row_mode
 $OT->settings({ selectbox_single_row_mode => "append" });

This defines whether or not sending a new row (an arrayref) to the select list overwrites the existing values, or adds to it. It can be set to append or overwrite.

The default behaviour for adding a row to select lists is to append itself to the end of the selectlist. Setting selectbox_single_row_mode to overwrite value is how you can alter that behavior. If selectbox_single_row_mode is overwrite, the contents of a select list are overwritten by the new row.

When selectbox_single_row_mode is set to append, you can still clear a select list by passing in an empty string as a parameter to the select list.

selectbox_multi_row_mode
 $OT->settings({ selectbox_single_row_mode => "overwrite" });

This defines whether or not sending multiple rows (an array of arrays) to the select list overwrites the existing values, or adds to it. It can be set to append or overwrite.

The default behaviour for adding multiple rows to select lists is to overwrite the existing list. Setting selectbox_multi_row_mode to append value is how you can alter that behavior. If selectbox_multi_row_mode is append, the contents of a select list are preserved, and all new data is appended to the end of the select list.

When selectbox_multi_row_mode is set to append, you can still clear a select list by passing in an empty string as a parameter to the select list.

selectbox_max_width
 $OT->settings({ selectbox_max_width => "50" });

Limit how many characters an entry in a select box can contain, 0 to not constrain the size. The default is 30.

Upon dynamically receiving select box content, most browsers resize the select box to the width of the longest entry. This seems like a neat feature, but resizing the select box will often adversely affect other parts of your visual layout. This option allows you to modify the size of text going into a select box, so the browser doesn't make the select box too big.

Netscape 4 is the only browser known not to perform dynamic resizing. Instead, it allows you to scroll side to side to view long text.

See selectbox_trim_string to learn what the trimmed text is replaced with.

selectbox_trim_string
 $OT->settings({ selectbox_trim_string => "+" });

Text to add to strings trimmed because of selectbox_max_width.

If the text being inserted into a selectbox needs to be resized to fit (due to selectbox_max_width), replace the removed text with the following string to make it clear that the string was trimmed.

The default is to use two periods: ..

checkbox_true_value
 $OT->settings({ checkbox_true_value => "1" });

The value a checkbox will return if it is checked, and no value is assigned to the checkbox (via the value= attribute). The default is "1".

checkbox_false_value
 $OT->settings({ checkbox_false_value => "0" });

The value a checkbox will return if it isn't checked.

radio_null_selection_value
 $OT->settings({ radio_null_selection_value => "0" });

The value a group of radio buttons will return if none of them are selected. The default is "0".

data_mode
 $OT->settings({ data_mode => "append" });
 $OT->param( $fields => { data_mode => "append" } );

Define whether data should be overwritten or appended, for objects other than select lists. It can be set to append or overwrite.

By default, data sent from the server to the browser overwrites existing content. This allows you to change that behaviour, and have it append.

response
 print $OT->response();

This returns the data gathered thus far, in a manner in which the browser will understand (ie, JavaScript). Typically, you would just send this directly to the browser, though you can modify it first if you desire.

Calling response clears all the data gathered so far on the internal stack.

JAVASCRIPT FUNCTIONS

There are a number of JavaScript functions available after you've added the following to your HTML:

  <script src="OpenThought.js"></script>
CallUrl
 OpenThought.CallUrl('script.pl', [ 'element1', 'element2', 'name1=value2' ] )

Make an AJAX call (ie, in the background) to the server, and dynamically update the current page with the server's response.

Parameters
Parameter #1: url

The first parameter is the url to send the request to. Due to limitations with JavaScript, the location being called must be on the same server the HTML page which is currently loaded came from.

Optional Parameters

After the url, all other parameters are optional. You can have as many additional parameters as you like. Additional parameters would be one of the following:

elements

Passing in an element name sends the current value of that element to the server.

An element could be the name of a form field (ie, text box, select list, checkbox), the name of an image, an id tag of an html element, and so on.

wildcards

If you have a bunch of elements that all start or end with the same string, and you don't want to pass in each one individually, you can add an asterisk '*' for as a wildcard. For example, sending in '*name' would send in values for the elements named first_name, last_name, and spouse_name. Sending in just '*' with nothing else will pass in every form element on the page as a parameter.

expressions

If you have a static value that you'd like to send in, instead of an element, you may do so using the syntax:

 'param_name=param_value'

arrays

You may find it works out easier for you to send in an array, instead of several individual parameters. That's fine, you may send in one or more arrays instead of single scalar values.

method

You can optionally specify the HTTP Request method to use. If you wish to do that, you may put GET or <POST> as the first parameter (before the url). If not specified, it uses whatever is in the http_request_method, which defaults to "GET".

FetchHtml
 OpenThought.FetchHtml('script.pl', [ 'element1', 'element2', 'name1=value2' ] )

This function is called just like CallUrl(), but they do very different things. Unlike CallUrl(), FetchHtml's job is to load a new page.

Other than that, since it's usage is identical to CallUrl(), see the CallUrl parameters above for information on how to use it.

JAVASCRIPT UTILITY FUNCTIONS

GetElement
 [element_type, element_value] = OpenThought.GetElement("someName");

Retrieves the current type and value for an element.

For example, if the element is a text box, this will be the text that currently resides within the text box. If it's a select list, it'll be the active selection(s).

SetElement
 OpenThought.SetElement("elementName", "new_value");

Sets the element with name "elementName" to the desired value.

FindElement
 element_object = OpenThought.FindElement("elementName");

Returns the object for elementName.

This is basically a cross browser implementation of getElementById. It works in all browsers that can run OpenThought.

Focus

Focus a form field or jump to an anchor tag.

HideElement, ShowElement

Hide and Show elements.

This allows you to hide pieces of HTML until some action occurs. On any event, you may call either of these to show or hide any type of HTML, including form elements and even entire div tags.

DisableElement, EnableElement
 OpenThought.EnableElement( "element_or_form_name" );

 OpenThought.DisableElement( form_name, { "EXCEPT" : [ "element3", "element4"] } );

Enable or disable an element or form.

There are cases where you'd want to disable an element or entire form. For example, if you want to display an HTML based dialog box, and disable all input except for the newly displayed dialog.

Calling DisableElement() causes the elements (generally form elements) in question to be greyed out, and to no longer accept input. Using EnableElement re-enables the input. You can pass in '*' as the parameter to enable or disable all form elements.

Note that disabled form elements cannot submit data to the server, you must first enable them.

If you choose to pass in a form name or '*' (as opposed to an individual element name), it will loop over all the elements in the form or forms, and disable them individually. Since you may not wish for each element to become disabled, you can pass in an exception list as the last parameter. To do so, you can use JavaScripts ability to create anonymous hashes. The first parameter to the hash must be "EXCEPT", the second parameter is an array, containing the names of all the elements to skip over. In the above example, element3 and <element4> are going to be skipped.

ElementChanged
 bool = OpenThought.ElementChanged("myElement")

Determine if a given element has changed since it's been loaded in the browser.

After passing in a form element name, it will return true or false, depending on whether or not the value of that particular form element has been changed since the page was initially loaded.

It cannot tell the difference between the user changing a value, and JavaScript changing the value. So, if you were to code something which altered the value of an element, it would always return true that it has been modified.

ElementReset
 OpenThought.ElementReset('ElementName')

Resets an element to it's original state.

This is quite similar to what a reset button in a form does, but it works for individual elements.

log
 OpenThought.log.debug("Output some debugging info");
 OpenThought.log.error("Something terrible has happened");

Log information, based on the current log level.

Available log levels are debug, info, warn, error, and fatal. If the current level is set to warn, only calling the warn, error, and fatal methods would generate logging output. The debug and info methods would be ignored. To get more logging, you'd simply have to set log_level to info or warn.

The default log level is set in the configuration section, and may be changed programmatically on the fly. And of course, the log.enabled setting must be true for you to actually see any of these messages.

browser
 OpenThought.browser.version
 OpenThought.browser.w3c
config
 alert( OpenThought.config.log_level );
 OpenThought.config.log_enabled = true;

Access any of the configuration settings.

You may change any of these on the fly.

CONFIGURATION

Most of the configuration defaults are kept at the top of the OpenThought.js file. All of those defaults can be changed at runtime using the settings method, discussed above.

While you can modify them directly in that file, that would mean future installations of OpenThought could cause them to be overwritten.

After loading those settings, the OpenThought JavaScript looks for the existance of a function (class) named OpenThoughtConfigLocal. If it exists, it uses variables setup in it to override what's at the top of the OpenThought.js.

To take advantage of that, you could create a (arbitrarily named) file called OpenThoughtLocal.js, and insert the following:

 function OpenThoughtConfigLocal() {

     ////////////////////////////////////////////////
     //
     // Local Config section - Custom config options
     //

     this.log_enabled = true;
     this.log_level = "debug";

     this.channel_visible = true
     this.selectbox_max_width = "50"

 }

The above would enable logging at the debug level, make the communication channel visible (for iframes anyway), and make the max selectbox width 50 characters instead of 30.

Then, in your HTML code, you'd simply add this line:

 <script src="OpenThoughtLocal.js"></script>

That must be above the line you use to include the OpenThought.js file. So, the two lines together would look like:

 <script src="OpenThoughtLocal.js"></script>
 <script src="OpenThought.js"></script>

SENDING DATA TO THE BROWSER

The following methods show you how you can send data from the server to the browser.

Just a Hashref

You only need a reference to a hash to send data to the browser. If the hashref containing all of our data is called %data, then all we need to do in our code is:

 # Populate the input fields, html, and/or images with the data within our hashref
 print $OT->param( \%data );

The keys in the $data hash would map to input field names, HTML id tags, or image names in the browser.

Populating Text, Password, and Textarea Form Elements

 $data->{'fieldname'} = "data";

Populating and Selecting Select List Form Elements

 $data->{'selectbox_name'} = [
                                 [ "Example 1", "value_one"   ],
                                 [ "Example 2", "value_two"   ],
                                 [ "Example 3", "value_three" ],
                             ];

This will set the text of a select box to the left column above, and the underlying value of that text to the right column.

You can also use an array of hashes:

 $data->{'selectbox_name'} = [
                                 { "Example 1" => "value_one"   },
                                 { "Example 2" => "value_two"   },
                                 { "Example 3" => "value_three" },
                             ];
In the case that you don't have two columns worth of data you wish to use, you
can also do:

 $data->{'selectbox_name'} = [
                                 [ "Example 1"  ],
                                 [ "Example 2"  ],
                                 [ "Example 3"  ],
                             ];

This makes both the text and value of the selectbox identical, and requires sending less data to the browser (which, of course, saves bandwidth, woohoo!).

By default, the above array of arrays and array of hashes will erase the current contents of the select list with the data in the array. To append a single item to the end of the select list, you can use the following:

 $data->{'selectbox_name'} = [ "Example 1", "value_one" ];

You can also use:

 $data->{'selectbox_name'} = [ "Example 1" ];

The latter will set both the text and value of the entry to "Example 1".

Also, you can use the following methods to manually clear the contents of a select list:

 $data->{'selectbox_name'} = undef;

   -- or --

 $data->{'selectbox_name'} = [ "" ];

That can be particularly useful if c<selectbox_single_row_mode> or selectbox_multi_row_mode are set to append, but you need to clear out the list for new data.

To select (highlight) an item in an existing select list, you can send a single string to your select list like so:

 $data->{'selectbox_name'} = "optionvalue";

Which ever item in the select list has the value optionvalue will become highlighted.

Selecting Checkbox Elements

 $data->{'checkbox_name'} = "boolean";

To uncheck a checkbox, set value to false, which can be any of:

    • false | False | FALSE

    • unchecked

    • any number less then 1

    • The current value of checked_false_value

Setting the value to anything other then the above will be interpreted as true, and will cause the checkbox to be checked.

Additionally, setting c<checked_true_value> to any of the above "normally false" values will override them.

Selecting Radio Button Form Elements

 $data->{'radiobtn_name'} = "radiobtn_value";

radiobtn_value is the value in the "value=" tag of the radio button.

Radio buttons can only be selected, they cannot be directly unselected. The only way to unselect a radio button is to select a different radio button in that group.

Updating Existing HTML Code

 $data->{'id_tagname'} = "<h2>New HTML Code</h2>";

This inserts the code "<h2>New HTML Code</h2>" inside the tag with the id attribute labeled 'id_tagname'. This replaces any text or code that may have originally existed within that tag.

Updating HTML does not work in Netscape 4.x, as it has a rather odd DOM. It is capable of working if someone felt like coding it, let me know if you're interested :-)

Focusing an Element

You can give the focus to any form element or anchor tag within the browser simply by saying:

 $OT->focus("fieldname");

Running JavaScript

You can easily send JavaScript to the browser, allowing you to call JavaScript functions, access JavaScript variables, and even create new functions -- all from the server.

The following calls the JavaScript 'alert' function:

 $OT->javascript("alert('Hello!')");

The next example calls the hypothetical javascript function 'myfunction', using param1 and param2 as arguments to that function:

 $OT->javascript("myfunction(param1, param2);");

You can send any JavaScript you want, but make sure it's properly formated code. OpenThought does not validate whether or not your JavaScript syntax is correct, the browser will be your judge! If something isn't working, pull up your browser's JavaScript console, it may provide you with some insight as to what isn't working properly. Setting log_enabled to true may help as well. You do not need to include script tags.

Loading a New Page

There are plenty of cases where it may be desirable load a new page within your content frame. Loading a new page is quite simple, and can be initiated from the server, or from the browser.

Here is an example of how you might tell the browser, from the server, to load a new page:

 $OT->url('http://example.com/newurl.pl');

This function will have the browser call the perl script 'newurl.pl'. It's then up to newurl.pl to deliver some sort of content back to the browser.

Using DBI

You can send the results of a database query directly to the browser, and have the data from the results put into their respective fields. You only need one thing in order for this to work -- the field names in your database need to match your field names in the HTML. For example:

 my $sql = "SELECT name, address, phone, age, married " .
           "FROM sometable WHERE name="Tim Toady";

 my $sth = $dbh->prepare($sql);
 $sth->execute;

 $data = $sth->fetchrow_hashref;

 $OT->param($data);
 print $q->header();
 print $OT->response();

In this case, lets say we have 'name', 'address', 'phone', and 'age' as names of text fields in our HTML, and 'married' is a checkbox. As soon as we send $data to the browser, these fields (which must exist) will all be filled in with the appropriate data.

This also works for select lists:

 my $sql = "SELECT name, ssn FROM sometable";

 my $sth = $dbh->prepare($sql);
 $sth->execute;

 $data->{'people'} = $sth->fetchall_arrayref;

 print $OT->parse_and_output({ auto_param => $data });

This selects the name and social security number from everyone in the table, and will allow us to use it to populate a select list named 'people'. The names are what will be displayed, the ssn will become the corresponding value.

Sending Data to the Server

You can send data from the browser to the server anytime an event occurs. Events are often generated by clicking buttons or links. JavaScript functions like onMouseOver, onClick, onChange, etc.. they all allow you to cash in on an event, and you can take advantage of them to send data to the server at that time.

There are two JavaScript functions available to you for communicating with the server. Their usage and parameters are identical, but they perform very different functions.

CallUrl

The CallUrl function is used when you want to use "AJAX" or "Remote Scripting" -- calling the browser in the background, and dynamically update the page with it's response.

FetchHtml

The function FetchHtml is what you want to use when you do want to load a new page.

The following are some examples of how you might use these two functions. In any of the following situations, the two functions are interchangable. It all just depends on what you want to happen.

Button Events

 <input type="button" name="search" value="Click me!"
        onClick="OpenThought.CallUrl('servercode.pl',
                                     'field1', 'field2', 'foo=bar');

Upon clicking this button, it will send the current contents of the fields named 'field1' and 'field2' to servercode.pl. It will also send the expression "foo=bar". When this gets to the server, 'foo' will be a parameter name, 'bar' will be it's value.

Be careful using submit and image buttons. You don't want your form to actually perform a "submit", which causes the page to refresh. You are merely looking to "catch" the submit event, and perform an action when that submit even is generated. If you wish to use a submit or image button, you should define your form like this:

 <form name="myForm" onSubmit="return false">

Now your browser can use submit and image buttons to send data to the server without actually refreshing.

Using 'A' Links

The following example shows you how you can use a typical HTML link to send data to the server without causing the page to refresh:

 <a href="#" onClick="OpenThought.CallUrl('/OpenThought/servercode.pl',
                                          'run_mode=forgot_password');
                                           return false;">
                                           Click me!</a>

Note: For things to work properly when using links, your JavaScript call has to be done within the onClick handler, and you need to finish it off using return false (ie, just like the example shows ;-)

Select List Events

 <select name="mySelectList" size="10"
         onChange="OpenThought.CallUrl('/OpenThought/servercode.pl',
                                       'mySelectList')>

By using onChange as we are above, whenever a select list item is clicked, it will send it's value to /OpenThought/servercode.pl.

A CLOSER LOOK AT THE DEMO

This is the gist of what happens in the Soul Food Cafe demo.

Filling the menu select lists:

    $data->{menu} = [
            [ "Fried Chicken",   0 ],
            [ "Chicken Wings",   1 ],
            [ "Chicken Nuggets", 2 ],
            [ "Dry White Toast", 3 ],
            [ "Dry Wheat Toast", 4 ],
            [ "Coke",            5 ],
            [ "Sprite",          6 ],
        ];

    print $q->header;
    print $OT->parse_and_output( auto_param => $data });

The above will fill the following select list:

    <select name="menu" size="6"
            onChange="OpenThought.CallUrl('index.pl', 'menu', 'mode_get_info'>

If the user clicks a menu item, the onChange event fires. It sends the value of the highlighted menu item to index.pl. We also send in an arbitrarily named parameter of mode=get_info, which the Perl code can test on to know what the user just clicked.

To return info about the "Fried Chicken", and display it in the html:

      $data-> {
          info => 'Best %*$# chicken in the state!',
          cost => '14.99',
      };

    print $q->header;
    $OT->param( $data );
    print $OT->response();

That updates the following html: (the data inside the span tags is replaced with the data in the above hash):

    <span id="info">(no item selected)</span>
    <span id="cost">0.00</span>

To add an item to the dinner selection, the user clicks this button:

    <input type="button" value="Add Item -->"
           onClick="OpenThought.CallUrl('index.pl', 'menu', 'mode=add_item'>

The onClick even fires, and the currently highlighted menu item is again sent to the server (but this time, we send in mode=add_item). The server runs this:

    $data->{dinner} = ["Fried Chicken", 0];

    print $q->header;
    print $OT->param($data);

That appends the data to this select list:

    <select name="dinner" size="6">

The above code samples are all taken from the soulfoodcafe application which comes with OpenThought. Feel free to take a look at it for a complete example of an OpenThought Application.

EXAMPLES

Here are some additional examples of how you might build an OpenThought application. Some of these examples are borrowed from the demo application. Take a look at the demo app if you'd like more information.

Text, Password, and Textarea Form Elements

Client:

    <form name="myForm">

    <input type="text" name="textbox_example">
    <input type="button"
       onClick="OpenThought.CallUrl( 'text.pl', 'textbox_example')">
    </form>

Server:

    my $q  = CGI->new();
    my $OT = OpenThought->new();

    my $param = $q->param('textbox_example');
    warn("We were sent $param");

    my $field_data;
    $field_data->{'textbox_example'} = "Blah blah blah";

    print $q->header;
    $OT->param($field_data);
    print $OT->response();

Selectbox Form Elements

Client:

    <form name="myForm">

    <select name="selectbox_example">
        <option value="test">Test!
    </select>

    <input type="button"
       onClick="OpenThought.CallUrl( 'selectbox.pl', 'selectbox_example')">
    </form>

Server:

    my $q  = CGI->new();
    my $OT = OpenThought->new();

    my $param = $q->param('selectbox_example')";
    warn("We were sent $param");

    my $field_data
    $field_data->{'selectbox_example'} = [
                                           [ "Example 1", "ex_one"   ],
                                           [ "Example 2", "ex_two"   ],
                                           [ "Example 3", "ex_three" ],
                                         ];

    print $q->header;
    $OT->param($field_data);
    print $OT->response();

Radio Button HTML Elements

Client:

    <form name="myForm">

    <input type="radio" name="radio_example" value="ex_one" checked>
    <input type="radio" name="radio_example" value="ex_two">
    <input type="radio" name="radio_example" value="ex_three">
    <input type="radio" name="radio_example" value="ex_four">

    <input type=button
            onClick="OpenThought.CallUrl( 'radio.pl', 'radiobox_example')">
    </form>

Server:

    my $q  = CGI->new();
    my $OT = OpenThought->new();

    my $param = $q->param('radiobtn_example')";
    warn("We were sent $param");

    my $field_data;
    $field_data->{'radio_example'} = "ex_one";

    print $q->header;
    $OT->param($field_data);
    print $OT->response();

Checkbox HTML Elements

Client:

    <form name="myForm">

    <input type="checkbox" name="checkbox_example">
    <input type="button"
           onClick="OpenThought.CallUrl( 'checkbox.pl', 'checkbox_example')">
    </form>

Server:

    my $q  = CGI->new();
    my $OT = OpenThought->new();

    my $param = $q->param('checkbox_example')";
    warn("We were sent $param");

    my $field_data;
    $field_data->{'checkbox_example'} = "true";

    print $q->header;
    $OT->param($field_data);
    print $OT->response();

HTML Example

Client:

    <h2>
      <div id="html-example"><b>Old HTML</b></div>
    </h2>

    <input type="button"
           onClick="OpenThought.CallUrl( 'html.pl', 'html-example')">

Server:

    my $q  = CGI->new();
    my $OT = OpenThought->new();

    my $param = $q->param('html-example')";
    warn("We were sent $param");

    my $data;
    $data->{'html_example'} = "<i>New HTML</i>";

    print $q->header();
    $OT->param($data);
    print $OT->response();
 }

Image Example

Client:

     <img name="img_example" src="/images/image1.png">

     <input type="button"
            onClick="OpenThought.CallUrl( 'image.pl', 'image-example')">

Server:

    my $q  = CGI->new();
    my $OT = OpenThought->new();

    my $param = $q->param('img_example')";
    warn("We were sent image $param");

    my $data;
    $data->{'img_example'} = "/images/image2.png";

    print $q->header();
    $OT->param($data);
    print $OT->response();
 }

JavaScript Example

Client:

     onClick="OpenThought.CallUrl( 'javascript.pl' )">

Server:

    my $q  = CGI->new();
    my $OT = OpenThought->new();

    my $js = qq!var greet="Hello World"; alert(greet); !;

    print $q->header();
    $OT->javascript($js);
    $OT->response();
 }

EXAMPLE USING CGI::Application

The .pm File

This is an example package built using CGI::Application together with OpenThought. This is just a package, you'll need an instance script (.pl file) to call it. That's just a handful of lines, and is well documented in CGI::Application.

 package Example;

 use strict;
 use base 'CGI::Application';
 use OpenThought();

 # Somewhat of a constructor -- called automatically by CGI::Application (and
 # before setup())
 sub cgiapp_init {
    my $self = shift;

    # Store the OpenThought object for later use
    $self->param('OpenThought' => OpenThought->new());

 }

 # Set up the run modes -- called automatically by CGI::Application
 sub setup {
     my $self = shift;

     $self->run_modes(
            'mode1' => 'init_example',
            'mode2' => 'some_screen',
            'mode3' => 'do_stuff',
            'mode4' => 'do_something_else',
            'mode5' => 'another_one',
     );

     $self->start_mode('mode1');
 }

 # The default run mode, called if no parameters were sent.  This would
 # normally return an html page (ie, the first page of the website).
 sub init_example {
    my $self = shift;

    my $OT = $self->param('OpenThought');

    return $self->show_html_for_initial_screen();

 }

 # An example run mode
 sub do_stuff {
    my $self = shift;
    my $q    = $self->query;
    my $OT   = $self->param('OpenThought');

    $data = {...};  # Assume we got some sort of interesting data here

    $OT->param($data);
    return $OT->response();
 }

AUTHOR

Eric Andreychek (eric at openthought.net)

THANKS TO

JJ < jj at jonallen dot info > John Jewitt < john at jjspc dot demon dot co dot uk > Buddy Burden < buddy at thinkgeek dot com > Brent Ashley < brent at ashleyit dot com > Greg Pomerantz < gmp216 at nyu dot edu >

COPYRIGHT and LICENSE

OpenThought is Copyright (c) 2000-2007 by Eric Andreychek.

This module is free software; you can redistribute it and/or modify it under the terms of either:

a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version,

or

b) the "Artistic License" which comes with this module.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details.

BUGS

Bug hunting season has been good. All known bugs have been eradicated. If you happen to run across one, please let me know and I'd be more then happy to take care of it. But real hackers would send a patch ;-)

SEE ALSO

CGI

CGI::Application

5 POD Errors

The following errors were encountered while parsing the POD:

Around line 965:

You forgot a '=back' before '=head1'

Around line 972:

'=item' outside of any '=over'

Around line 1050:

You forgot a '=back' before '=head1'

Around line 1052:

'=item' outside of any '=over'

Around line 1172:

You forgot a '=back' before '=head1'