plainblack.com
Username Password
search
Bookmark and Share

Form Controls

A significant part of traditional thick client application development over the last two decades has focused on so-called GUI's – graphical user interfaces. A GUI is a means of using visual metaphors and event-driven programming to allow a user to visually control and interact with a program. GUI's feature controls (referred to as widgets by some documentation) which are actual interface components with which the user can directly interact. These include buttons, drop-down lists, text input boxes, and things of that sort which have a defined way to visually respond to interface events. Object-oriented control toolkits (such as Microsoft's Windows Forms© framework, or the QtGui module of Trolltech's Qt© framework) typically use object-oriented techniques like inheritance to facilitate understanding and development.

 

WebGUI, being a GUI for web applications, also supports controls. Just like for thick client toolkits, WebGUI controls must be defined in code before they can be used. However, instead of using bulky designers to lay out the positioning of the controls, code and markup are used to precisely specify where they should be and how they should behave. Once constructed in code, however, the WebGUI UI allows for familiar point-and-click layout.

 

Form controls are used in WebGUI in a manner similar to how they are used in traditional thick clients: to convey data to WebGUI in a variety of different formats. This can be anything from a standard text entry to a hexadecimal color chooser or even an asset selector. These values are then passed in on form submission and are handled by the appropriate backend code. The backend code is not part of the form control code; the form control code is strictly and specifically concerned with just the interface and the behavior thereof, not with any logic associated with handling the data input into the control. Similar to the rest of WebGUI, and any well-designed application, the interface is separated from the behavior in this way.

 

In contrast to a WebGUI asset, form controls are for entering data, rather than displaying it. Form controls are generally part of an asset, but only for information to be displayed on that asset or otherwise used. An asset with a form control collects data from the users. After that data has been collected and processed, it's usually displayed on an asset (sometimes the same asset containing the form control, sometimes not). Use a form control in an asset for data collection and an asset for data display.

 

Before starting development of a new form control, there are several questions to ask. Much of this is common to all development and won't be covered here. However, there is one important question to consider before starting: does the functionality of this form control require any kind of active document technology, like Javascript? Form controls can use Javascript to implement their functionality, and it's important from a design perspective to know whether any potential controls need Javascript before starting development.

 

Hello World

The simplest example of a form control—or most any computer related task—is the “hello world”. This ensures that the tools (here, form controls) work, and it also serves to familiarize users with the tools and the environment. For form controls, this starts with the _control.skeleton file in the WebGUI/lib/WebGUI/Form directory. This file contains everything a form control needs, and more than it needs for a “hello world” example. The “hello world” form control won't output a form, but rather just the text, “Hello world!” To do this:

 

  • copy the skeleton file to a new .pm file in the Form directory

  • change the package line at the top of the file accordingly

  • change the definition and toHtml methods accordingly:

 

sub definition {

my $class = shift;

my $session = shift;

my $definition = shift || [];

push(@{$definition}, {});

return $class->SUPER::definition($session, $definition);

}

sub toHtml {

my $self = shift;

return 'hello world!';

}

 

After these steps, modify an asset's view method and style template to include the control.

 

sub view {

# other stuff

$var->{helloWorldControl} = WebGUI::Form::HelloWorld->new($session);

# other stuff

}

 

Then, include the template variable for the form control in the style template.

 

<tmpl_var helloWorldControl>

 

A Simple Example: Button

In order to better grasp how form controls work, a simple, functional, and easy to understand example works best. Perhaps the simplest of these is the humble, ubiquitous button. The button's entire existence is to serve as a punching bag, taking with stoic acceptance the beatings of hundreds or thousands of users a day. Yet buttons serve a very powerful purpose: without them (and excluding Javascript for the moment), form submissions would not be possible.

 

All WebGUI form controls live under the WebGUI/lib/WebGUI/Form directory in the WebGUI source tree. Each control is its own separate Perl module; the module for the button is WebGUI/lib/WebGUI/Form/Button.pm. For the sake of brevity (and the assumption that readers of this developer's manual have ready access to a computer with the WebGUI source code), the code for the button control is not reproduced here. However, a few parts of the code do deserve mention.

 

The first important part is the use base 'WebGUI::Form::Control'; line. All form controls must inherit from WebGUI::Form::Control. This class provides functionality necessary and common to all form controls. There are several methods that a form control should or must override, as well. These include getName, generateIdParameter, and toHtml. The details of overriding these methods will be discussed shortly.

 

The next important section is the definition subroutine. Like with most parts of WebGUI, this contains meta-information about the class in question, and default values for various attributes. It is, indeed, a definition, a kind of declarative programming. As with all definition subroutines, this one receives several parameters. The first is the class, followed by the WebGUI::Session object, and then the definition that this particular class extends, if any. WebGUI::Form::Button, being a child class of WebGUI::Form::Control, inherits many fields from WebGUI::Form::Control. However, the button class leaves most of these at their defaults and only defines a few.

 

Following this is the toHtml subroutine. For most controls, this subroutine does most of the important work. As its name implies, this subroutine generates the HTML required for rendering the control in the browser and any behavior associated with its interface. This can also include Javascript to enhance the behavior of the control. There are several controls which don't define their own toHtml method. Instead, they rely on a parent class to provide the required functionality.

 

It's time to take a look at what's needed to include a button on a page. Typically, in WebGUI, “page” means “asset”, so this will begin by going over some code and related template markup to include a button on a page. The button will be relatively simple, and will just display a message box saying “Hello, World!” to the user when clicked. In standard WebGUI style, the button will be inserted into the $var hashref passed to the processTemplate method of all assets. The template code will show how to include the button in an HTML document. First, the Perl code:

 

sub view {

my $self = shift;

my $session = $self->session;

 

# declare $var here, put stuff in it

 

$var->{simpleButton} = WebGUI::Form::Button($session, {

name => 'simpleButton',

value => 'simpleButton',

extras => q|removed="alert('Hello, world!')"|,

});

 

# other stuff this asset needs to do

# then call processTemplate and pass it $var

}

 

As for the template, it's as simple as designing the surrounding markup and including it in a tmpl_var statement like so:

 

<tmpl_var simpleButton>

 

Now, of course, this particular demonstration doesn't do anything altogether useful. However, it does establish the basic things required to get a button working on an asset. The rest is just additional logic.

 

For a deeper understanding of how this actually works, take a look at the HTML generated by this example. Again, it's relatively simple, but knowing what it outputs is nonetheless crucial in forming a complete understanding of how the button control functions and interacts with other page elements.

 

<input type="button" name="simpleButton" id="simpleButton_formId" value="simpleButton" removed="alert('hello, world!')" />

 

Everything here is rather straightforward: the name and value parameters passed to the constructor are mapped directly to the corresponding values in the HTML. As detailed above, the id parameter is constructed from the name with “_formId” appended. The extras field is appended as a raw string value. This is important to note, because it allows for the specification of custom attributes or behavior for the button that may not be specified in any other way.

 

As shown above, buttons are actually rather flexible. They serve as starting points for any kind of custom behavior whatsoever. They're similar to their counterparts in thick client applications, but with a few particularities about them resulting from the implementation of HTTP. In stark comparison to thick clients, web applications like WebGUI communicate over HTTP. The important thing to note here is that HTTP is a stateless protocol. What this means is that the web server doesn't keep track of values the user has filled in on various forms between client requests. Thus, other means -like cookies, request parameters, and session information stored in a database – must be used to maintain the information the user filled out on the page between submissions. To this end, any information that needs to persist across page requests must be passed along in one of these ways. While buttons aren't specifically concerned with submitting information, one of button's child classes, WebGUI::Form::Submit, is.

 

The submit form control is the ubiquitous submit button seen all over the web made into a form control. Its most typical use is to, obviously, submit some kind of data to the server. This requires an HTTP POST, typically, which requires a page load, so the information needs to be submitted along with the POST request, typically as parameters.

 

Getting Attached: the Attachment Control

The button is relatively simple to understand. To develop a more thorough understanding of form controls, how they interact with pages and how to include them in pages, take a look at a more complicated example. The attachment control, used in WebGUI's powerful and extensive Wiki asset, allows for file attachments to be made to Wiki pages.

 

The attachment control allows for all the necessary operations on attachments: creating, reading, deleting. These three operations are supported using www_ helper methods. These function in much the same way as www_ helper methods do in assets: WebGUI invokes them based upon parameters passed in on the URL of the request, but with the www_ part stripped. For example, to call the www_delete method of the attachments control, the URL would look something like this:

 

http://your.company.com/wiki/funWikiPage?op=formHelper;class=Attachments;sub=delete;maxAttachments=5;maxImageSize=100000;thumbnailSize=50;attachments=yfyFDxQam6bEMxbwxu1QEw;assetId=yfyFDxQam6bEMxbwxu1QEw;name=attachments

 

To fully understand what's going on, analyze this piece by piece. First, the standard protocol prefix, followed by the domain name. Then the location of the wiki asset in the tree, and a page of that wiki (“funWikiPage”). Next is an invocation of a WebGUI operation. The formHelper operation specifies the class name (Attachments, here, expanded to WebGUI::Form::Attachments) and the web-accessible method to call on that attachment (here, delete). Following are parameters required for attachment operation. The attachments parameter, which may be specified more than once, lists the attachments for this particular Wiki page. Next, the assetId parameter specifies the actual attachment to delete.

 

The quick run-through above details a specific feature of the attachment control. What about how the code works, and how to include an attachment form on a page? Let's start with the attachment definition. The definition contains a few fields particular to the attachment control that are noteworthy. The first of these, maxAttachments, specifies the maximum number of attachments the control will accept at any one time. For the WikiPage asset, this is specified in the Security tab and defaults to zero. The next two fields, maxImageSize and thumbnailSize, describe the maximum and thumbnail image sizes for attachments, respectively.

 

The next noteworthy aspect of the attachment control is the getValueFromPost method. This method returns an arrayref of asset ID's. When files are uploaded via the attachment control, they are placed in a temporary location. It is the developer's responsibility to move these to a proper location, or else they'll be deleted.

 

Next is the toHtml method. Just like in button, this method renders the HTML required for this form control to function on the page. Take a look at the HTML generated by this control. There are two parts: an iframe, and the code rendered by the iframe. Here's the iframe code:

 

<iframe src="/wiki?op=formHelper;class=Attachments;sub=show;name=attachments;maxAttachments=1;maxImageSize=100000;thumbnailSize=50;" style="width: 100%; height: 120px;"></iframe><div id="attachments_formId"></div></td></tr>

 

And here's the HTML generated by the iframe:

 

<html><head> <script src="/extras/AttachmentsControl/AttachmentsControl.js" type="text/JavaScript"></script>

<link href="/extras/AttachmentsControl/AttachmentsControl.css" rel="stylesheet" type="text/css" />

 

<script type="text/javascript">

parent.document.getElementById("attachments_formId").innerHTML = '';

</script>

</head> <body>

<div id="uploadForm">

<a href="#" removed="WebguiAttachmentUploadForm.hide();" id="uploadFormCloser">X</a>

<form action="/wiki" enctype="multipart/form-data" method="post">



<input type="hidden" name="maxAttachments" value="1" />

<input type="hidden" name="maxImageSize" value="100000" />

<input type="hidden" name="thumbnailSize" value="50" />

<input type="hidden" name="name" value="attachments" />

<input type="hidden" name="op" value="formHelper" />

<input type="hidden" name="class" value="Attachments" />

<input type="hidden" name="sub" value="upload" /> <input type="file" name="attachment" />

<input type="submit" value="Upload" /> </form> </div>



<a id="upload" href="#" removed="WebguiAttachmentUploadForm.show();">Upload an attachment.</a>

<div id="instructions">Upload attachments here. Copy and paste attachments into the editor.</div>

<div id="attachments"> </div> </body> </html>

 

Again, as you can see, the properties of the control are propagated to various parts of the HTML. The actual content of the iframe is a relatively basic file upload form with some hidden fields to maintain state. One thing to note is that the sub parameter of the processed form contains “upload” Again, this corresponds to the www_upload method in the attachments class.

 

Next is the www_delete web method. As discussed earlier, this method deletes an attachment from the relevant asset. All attachments are stored as assets, so they have access to all of the functionality available to assets: getting ID's, content, exporting, and cleanup methods. The www_delete method uses one of these cleanup methods, purge, to remove the attachment from the asset. When finished, www_delete calls www_show, described next, and returns the value returned from that web subroutine.

 

The www_show method is rather large, and has a lot going on. As with all but the most trivial subroutines, www_show starts with declaring some variables to be used throughout the sub. If called with a second parameter, it initializes a lexical variable to that parameter (the call in www_delete works this way); otherwise, it takes the parameter list from the URL. Next, after disabling cache control and adding necessary Javascript and style information, the method prepares the markup required for the upload form. Then, the markup used for managing attachments is constructed. After this, the final content, containing the list of existing attachments, the upload form, and management controls, is constructed, and returned.

 

Last is the www_upload method. Like with www_show, www_upload starts with collecting some information, including information required for saving state. Then there's a call to a very particular method: addFileFromFormPost. This method in the WebGUI::Storage class, obviously, handles uploaded files from form posts. The method saves the content of the file to a location in WebGUI's storage, and returns the filename of where the file was saved. After a security check preventing visitors from doing naughty things with items they've put in tempspace, the method assigns some properties and creates an asset from the uploaded file. After, it adds the new asset's ID to the list of attachments for this asset and calls www_show with the session and this array of asset ID's. Finally, it clears the temporary storage and returns the result of calling www_view, with the session object and the new list of asset ID's.

 

That's what the methods do. But... how does the blasted thing actually work? Let's take a look at it one step at a time, from the browser's perspective. First, before anything else, the toHtml method of the control is called. This generates the iframe. The iframe, as described above, contains a URL that invokes the www_show method. The www_show method is where most of the work takes place. Almost all of the content is generated here, and it serves as the main window, so to speak, of a traditional GUI application. From the layout rendered by the www_show method, all of the useful functionality of the attachment control can be realized. Uploading files, viewing and managing files, deleting files... it's all possible from this view. Each of these functions invokes a different www_ helper method.

 

Writing Your Own Form Control

So far, an example of a simple control (the button control) and a more complex control (the attachments control) have been introduced, but what are the steps needed to construct your own form control? Like most parts of WebGUI, form controls have a ready-made skeleton file that you can copy and use as a starting point for custom development. This file is located in the WebGUI/lib/WebGUI/Form directory and is named _control.skeleton. Let's examine this file and see how you can use it to put together your very own form control.

 

First, decide on a name for the control. This will designate the name of the file name, and the package name used to refer to the form in code. For the purpose of this example, call the control SimpleControl. Copy _control.skeleton to SimpleControl.pm. Open up the new file, and take a look at what it provides for you. Each section is covered next.

 

Before proceeding one step further, change the package name! WebGUI will be unable to find your control and will give you page compilation errors if you forget this most crucial, yet easy to forget, step. It's a very simple thing that, in the excitement of writing new code, developers sometimes completely neglect. Save yourself future headaches (“I'm positive the code is correct and it's in the right spot; why can't WebGUI find it? I'm switching to Mambo...”) and change the package name immediately! You'll thank yourself later.

 

Now that you've saved yourself from embarrassment in front of the boss, take a look at what the skeleton provides and how you can use it. After the Plain Black copyright statement (feel free to add additional legal information to this section pertinent to your organization), the skeleton has various use statements that load various modules and set up the necessary inheritance relationship with WebGUI::Form::Control. Keep the inheritance statement; that's required for the form control to work and it'll do Bad Things® if you take it out.

 

Next is the obligatory definition subroutine. It's pretty boilerplate, really, but all the parts are there for you to extend in any way you need. Custom fields are easy enough to add, like the thumbnailSize field for the attachments control.

 

After that is getValueFromPost. This method appeared in the attachments control, but not the button control (there's no information to get from a button; if there's a post at all, you know the button was clicked, and that's the only information the button can provide). Depending upon the functionality of the control you intend to design, you may or may not need this method.

 

Following getValueFromPost is toHtml. This method, of course, outputs the initial HTML the user sees when they see your control. This could be all they need to see, like with button, or it could be just the beginning, leading to a more complex presentation, like with attachments. Either way, you'll very likely need to change this to output the HTML and/or JavaScript required for your control to function.

 

That's it. Of course, you'll probably want to divide your functionality into methods and www_ helper functions as designated by your specifications. There are plenty of examples of how to do things already, and it's not uncommon at all for form controls to inherit from one another or use one another to accomplish their tasks. There are dozens of instances of form controls reusing code. Don't be afraid to do the same yourself!

 

As for using your new control in your control, it's a fairly simple procedure. First, you need to use the package containing the code for your control (remember you had to change the package declaration when you copied the skeleton? You did do that, right?), and then instantiate it. It'll look something like this:

 

use WebGUI::Form::SimpleControl;



# somewhere in your asset code

my $formHeader = WebGUI::Form::formHeader(...);

my $simpleControl = WebGUI::Form::SimpleControl->new($session, foo => bar, baz => quux);

my $formFooter = WebGUI::Form::formFooter(...);

 

Then, put these objects in your template and you're set.

Keywords: asset controls GUI iframe template template variable

Search | Most Popular | Recent Changes | Wiki Home
© 2018 Plain Black Corporation | All Rights Reserved