API Guide

Table Of Contents

Overview

Toolkit2 is similar to the old Toolkit in that it presents a hierarchical, object-oriented mechanism to generate web-based user interfaces. The differences lie in the fact that Toolkit2 does away with layout managers and alternate component models. It also introduces new ways to use the toolkit. One of the complaints from the first toolkit was that you couldn't easily use single toolkit components in an otherwise PageRender2/HTML context. For example, it was difficult to create a working toolkit button unless you used the rest of the toolkit "stuff". The new toolkit has three ways to use the toolkit:

These will be described below. There are some other important concepts to get out of the way first.

The Basics

The toolkit consists of a large set of PHP classes which have various purposes. Some of them represent HTML objects in a page (components and containers), while others have a more facilitating nature (actions and themes). Let's first take a look at these different types of classes.

The main type of class is a component. A component represents enough information and PHP code to generate some amount of HTML on the page. The HTML corresponds to some meaningful entity, ranging from simple buttons to complex tree views. The idea is that a component will represent something useful, that would be difficult to reproduce correctly in each project, or that would simply be tedious. This is, after all, the whole idea behind the toolkit. There's nothing the toolkit can do that HTML+CSS+JavaScript can't do. The toolkit is supposed to make generating HTML+CSS+JavaScript easier and faster for the web developer. Components are the chunks that get generated faster and easier. Additionally, there is the benefit of reusability, extensibility and general code cleanliness. There is more to components than these idealistic facts. See the Component section below in "The Details".

Containers are a type of component that are meant to hold other components or containers inside of them, logically and in terms of the HTML. There are some basic types of containers, called layout containers, that have no real visual representation on the screen, but help to lay out components on the screen without a lot of work. The two basic ones are TKVBox and TKHBox. Other containers have more complex functionality, such as TKTree which provides a full tree view. The components contained within it are nodes in the tree. Since containers are instances of components, they can do anything a component can do.

Actions and themes fall into a different category than components and containers. Let's start with themes since they are simpler to understand. A theme simply describes some default set of properties for various types of components. For example, we might want our tree view to have some default CSS for making the collapse/expand buttons look nice. The default theme would provide this, instead of hardcoding the CSS in the tree view, or relying on the application programmer to manually set CSS classes and styles. By changing the theme of a component, or the entire site, the entire look of the site is changed in one step. It doesn't require recoding hand-crafted CSS (even inline classes and such) in custom HTML.

Actions represent some sort of JavaScript activity. They are invoked by inline JavaScript events, such as "onclick" inside a button. They can also be invoked by other actions. Instead of writing custom JavaScript, you can use predefined actions and use Toolkit methods to set everything up. No JavaScript needs to be written.

The Details

Components

A component is a PHP object that is an instance of a class derived from TKComponent. You cannot instantiate TKComponent itself as it is an abstract class, but it does provide a great deal of the functionality used by components. Every component has the following features:

The basic lifecycle of a component is being created, being modified by setting properties or attaching actions to events and then being rendered into HTML. Sometimes the rendering is done by PageRender2 or another component or container. But it can also be done directly by calling the components render() method. Below is an example of the general usage of a component in a script:

$but = new TKButton("Click!");
$but->set('style', array('width' => '500px', 'height' => '500px'));
$prm->add($but);

This code segment creates an HTML button with the caption "Click!", sets its width and height to be 500 pixels and then adds it to the PageRender module, which will render the button (by calling its render() method) and then append the HTML to the page.

Properties

Properties are like member variables, but they are more tightly controlled. The set of properties available for a component is defined on a class by class basis. The set of properties cannot be changed from outside the class. Properties also have one of five types: If you attempt to assign a value to a property which does not have the same type as the new value, the toolkit will display an error and will not set the property.

There are several ways to set or get a property. Assuming we have a component named $c and we want to set a string property 'name' to the value 'foo', then we can do it in the following ways:

All of these ways are equivalent. The rules for option 2 are that the property name, which is always lowercase with multiple words separated by underscores, is converted such that the first letter of each word is uppercased and the underscores are removed. So the property 'item_class' is converted to 'ItemClass': setItemClass() and getItemClass().

Properties can also be appended to. This requires the use of the append() method, or the appropriate appendXxx() method, where Xxx is the converted property name. Booleans, numerics and objects cannot be appended. Strings are appended as normal, with the dot operator. Arrays are more complex. If you append an array to an array, the arrays are merged using array_merge(). If you append anything else to the array, then that anything else is array_push()'d onto the end of the property's array. There is no notation for appending using hidden getters and setters. Doing something like $c->name .= 'bar' will have the same result as $c->append('name', "bar") but it is approximated by PHP, rather than being done by the toolkit itself. This is especially problematic for arrays, where PHP does its own thing different from the rules specified above.

Some examples with arrays:

// 'class' is an array property, so it should be assigned as an array
$c->class = array('myCSSClass');
// ...but you can also do this because the toolkit will convert a single element
//  into an array containing that element
$c->class = 'myCSSClass';

// 'style' is also an array property
$c->style = array('color' => 'red');
// ...but thanks to PHP, you can also use this little trick to set individual keys of the 'style' property's array
$c->style['color'] = 'red';

If you use the setXxx() functions or set('xxx', ...), you can chain calls together for convenience of coding, as these functions return the object which they were called on:

// you can do this
$c->setClass('myCSSClass')->setStyle(array('color' => 'red'));
// ... instead of this
$c->setClass('myCSSClass');
$c->setStyle(array('color' => 'red'));

// it is useful for things like this
$button = $foo->addButton("Hello")->setClass('buttonClass');
// instead of the more verbose (but perhaps more readable)
$button = $foo->addButton("Hello");
$button->setClass('buttonClass');

Events

As with properties, each component class has associated with it a set of events. These are usually the same as the JavaScript events, such as "onclick", etc. Events which are the same as JavaScript events are called direct events. Other events are called indirect as they must be generated (or "emitted") by toolkit actions. For the user of a component, it doesn't really matter how an event is generated. The mechanism to attach actions to events is the same. You simply call setAction() naming the event and passing in a new instance of an action:

// show a JavaScript alert dialog saying "I was clicked!" when the user clicks on the component
$c->setAction('onclick', new TKAlertAction("I was clicked!"));
// change the background to red when the user mouses over the component (note
//    that the background will not change back to what it was before)
$c->setAction('onmouseover', new TKChangeStyleAction($c, array('background' => 'red')));

For the user of the toolkit, there is not much more to say about events. It is best to use the library of actions available in the toolkit already. You can attach multiple actions to an event by calling setAction() multiple times. The set of events available for a class is documented in each class. If you attempt to attach an action to an event that does not exist, you will get a toolkit error message.

You can use a shorthand notation for setting actions, similar to the notation for setting properties. The following is exactly equivalent to the above code segment:

$c->onclick = new TKAlertAction("I was clicked!");
$c->onmouseover = new TKChangeStyleAction($c, array('background' => 'red'));

Finally, you can assign JavaScript directly to an event, by setting the action to be a string, or an array of two strings:

$c->onclick = "alert('Hello world!')";
$c->onclick = array("function myfunc(msg) { alert(msg); }", "myfunc('Hello world!')");

If you use the single string form, then that JavaScript will be put inside the onclick attribute of the HTML element to which the event applies (e.g., for a TKButton, it would be the <button> tag). If you use the array of two strings, the first string will be embedded at the top of the page as extra JavaScript (PageRender "ExtraJS" target), and the second string will be put inside the HTML event handler attribute like it would be if you just had one string.

This shortcut method is the same as instantiating a TKCustomAction class, whose constructor takes the two strings as described above. The difference is that setAction() automatically converts the string or array to a TKCustomAction and then adds it.

Useful Components

Here is a list of some useful components and basic usage:

TKButton

This component represents a basic HTML button with a text caption. The following code creates a button that, when clicked, pops up an alert dialog which says "Somebody clicked the button".

$button = new TKButton("Click Me!");
$button->onclick = new TKAlertAction("Somebody clicked the button");
$prm->add($button);

TKLabel

A label is basically a section of text or HTML. It can be block (contained in a div), inline (contained in a span) or "neither" (no containing tag). In the latter case, it is preferable to load HTML directory into the PageRender Module, or use the addText() method available on all Toolkit containers. The following code creates two labels and a button, the labels are on either side of the button with different background colors.

$label1 = new TKLabel("Left Label");
$label2 = new TKLabel("Right Label");
$button = new TKButton("Middle");
$label1->style['background'] = 'green';
$label2->style['background'] = 'red';
$prm->add($label1);
$prm->add($button);
$prm->add($label2);

TKHTML

This component can be used to contain plain HTML, or it can be used to contain TKXML. For the former, it is better to use TKLabel or addText(). For the latter, you must use TKHTML.

$tkxml = new TKHTML("&lt;TKButton&gt;Click Me!&lt;/TKButton&gt;", TKHTML::HTML_TK);
$prm->add($tkxml);

TKFormInput, TKCheckBox, TKRadioButton and TKTextArea

These are the main members of the set of components which allow you to build HTML forms with the Toolkit. TKFormInput represents any type of form input that can be created with the HTML <input> tag. TKCheckBox and TKRadioButton are subclasses of TKFormInput that have special support for checkboxes and radio buttons. TKTextArea represents the <textarea> tag, but functions pretty similarly to TKFormInput otherwise. Below is an example of building a simple form with these classes:

$form = new TKForm($PATH['something']);
$form->addText("First Name");
$form->addFormInput('text', 'firstName');
$form->addText("<br />Last Name");
$form->addFormInput('text', 'lastName');
$form->addText("<br />");
$form->addFormInput('submit', 'submit', "Submit");
$prm->add($form);

TKSelect

A select can be a drop-down ("combo box") or a list where multiple items can be selected at once. The Toolkit additionally provides a way to associate actions with the user selecting or deselecting specific items in the drop-down. Below is an example of using TKSelect to build a short drop-down menu:

$sel = new TKSelect('ageRange');
$sel->addOption('under18', "Under 18");
$sel->addOption('18_24', "18-24");
$sel->addOption('25_36', "25-36");
$sel->addOption('ancient', "37+");
$prm->add($sel);

Containers

A container is a type of component that can hold other components. It is up to the container to initiate the rendering of the components inside it and put their HTML in some appropriate form. The main addition containers add is the idea of slots. A slot is like a bucket that can be filled with components. The slots have some logical meaning. They may or may not have a meaning on the screen. Most containers have one slot, the default slot (also called 'main'). Other slots must be explicitly named when adding a component to a container. Some slots only allow for one component to fill them, and some slots are considered private, in which case only the container itself can add elements to the slot. Private slots are generally not documented in a container's documentation.

You can add components to a container in one of several ways. Two ways are supported by default, and additional ways may be provided by a container if it makes more sense (TKTree used to have an addItem() method which would take care of some details and provide extra parameters). The two default ways are the add() method and the dynamic calls addXxx() and addXxxTo(). Some examples:

Some containers like to take an array of additional parameters when adding a component. This array is always the last parameter in any of the above methods. All of the add-type functions return the object added, or null if adding fails (in which case, an appropriate error message will be displayed). When using the dynamic calls, the toolkit class name is stripped of its initial 'TK' and is used after the 'add' of the method name. So, in the examples above, the class is 'TKLabel', but the methods were 'addLabel' and 'addLabelTo'.

Containers can be added to other containers as many levels as you wish. Entire pages could be constructed hierarchically. This was the preferred method in the first toolkit, but it is no longer required or even encouraged. Such a hierarchy is only useful when doing composite layouts, such as having an HBox containing multiple VBoxes, themselves containing components.

Containers support a special widget type called 'text', which is like a label, but doesn't exist as a separate widget in the hierarchy and has no HTML id. It is meant to fill in labels on tables and forms, or for places where you need to add raw HTML. It is lighter-weight than a TKLabel, so unless you need the features of a TKLabel, opt to use text instead. To add text, you call the addText() and addTextTo functions on a container. They work just like other add-type functions. The first takes one argument: the text to be added, and the second takes two arguments, the slot to add the text to and the text to be added. They both take an optional final argument, which is an array of parameters. Only some containers care about parameters. See the documentation for those containers. For TKTable, you can specify class and style in the parameters list, and these will be applied to the cell containing the text.

Some examples:

$cont->addText("Hello");

$table->addTextTo('header', "User Name");
$table->addTextTo('header', "ID");

$table->addText("foo", array('style' => array('color' => 'red')));

Useful Containers

TKVBox and TKHBox

These containers provide a vertical and horizontal layout, respectively. In the vertical layout, each component in the container appears below the previous component, as if they are stacked. In the horizontal layout, they appear next to each other on a line.

TKTable

This container represents an HTML table. Components are added left to right to the table and usually top to bottom, although you can technically insert components into any row at any time. A table also has a header and a footer (implemented as slots). Below is a simple table that shows some staff information for folks here at Shodor:

$table = new TKTable();
$table->addTextTo('header', "Name");
$table->addTextTo('header', "Favorite Language");
$table->addTextTo('header', "Favorite Food");

$table->addText("Joel");
$table->addText("C");
$table->addText("Pizza");

$table->addRow();
$table->addText("Jonathan");
$table->addText("Lisp");
$table->addText("Nobody knows");

$table->addRow();
$table->addText("Ismael");
$table->addText("PHP");
$table->addText("Tuna");

$prm->add($table)

TKTree

A TKTree provides a collapsable tree view of hierarchical data. The collapsing/expanding nature of the tree is done automatically by the tree, but you can control these actions yourself using TKTreeAction. Below is an example of a small tree which shows the categorization of basic shapes:

$tree = new TKTree();
$shape = $tree->addText("Shape");
$rectangle = $tree->addText("Rectangle", array('parent' => $shape));
$square = $tree->addText("Square", array('parent' => $rectangle));
$circle = $tree->addText("Circle", array('parent' => $shape));
$prm->add($tree);

Actions

Events were already described above. Actions are simply the objects representing JavaScript actions to be taken when events occur. The toolkit comes with a decent set of built in action classes. It is possible to create your own, or use pure JavaScript in conjunction with the toolkit (see the Events section above for more). What follows here is a description of the core action classes and examples of their usage:

TKChangeStyleAction

Causes some other toolkit component to change its style.

The constructor takes two arguments: the target (instance of class derived from TKComponent) and an associate array of CSS style attributes to be applied to that target when the action is invoked. Here is an example of its usage:

$button = new TKButton("Change Color");
$label = new TKLabel("This is a label whose color will change");

$button->onclick = new TKChangeStyleAction($label, array('background-color' => 'green'));

$prm->add($label);
$prm->add($button);

TKConfirmAction

Pops up a confirm dialog, which, if canceled, results in further actions not being executed.

This is useful to get the user to confirm an action before proceeding to do it. The idiom to make this work is to first assign this action to the onclick event of the button (or other component) and then assign further actions to the button. Since those actions are executed after the confirm action, if the confirm dialog is canceled, these actions will not be executed.

$button = new TKButton("Destroy Important Data");
$button->onclick = new TKConfirmAction("Are you sure you want to destroy this data?");
$button->onclick = new TKPostAction(array('dataId' => 37), $_SERVER['REQUEST_URI']);

The second action won't be executed if the confirmation dialog is canceled.

TKCustomAction

This is a pass-thru action which allows the programmer to include arbitrary JavaScript as actions instead of classes.

The class is implicitly used when you assign a string or array to an event on a component. It is useful, however, for those actions which require instances of other actions to operate (for example, TKToggleAction). The constructor takes two arguments. The first is JavaScript that should be put in the header of the page, and the second is JavaScript that should be put inside the event handler in an HTML tag.

$button = new TKButton("Click!");
$button->onclick = new TKCustomAction("var clickMsg = 'Hello';", "alert(clickMsg)");

This example stores a message string in the header of the page, and then uses that string inside an alert() call.

TKDisableAction and TKEnableAction

These classes will disable or enable another toolkit component or set of components, respectively.

$button = new TKButton("Disable Me!");
$button->onclick = new TKDisableAction($button);

The button will disable itself when clicked.

TKHideAction and TKShowAction

These classes will hide or show another toolkit component, respectively.

You must specify how those components are to be hidden or shown. There are currently two options: using CSS visibility and using CSS display. The latter is preferred if you want to avoid large blank slots on the page. It is also the default, so 'display' does not have to be passed as the second parameter if the CSS display property is used for hiding/showing.

$label = new TKLabel("This label will be shown and hidden");
$show = new TKButton("Show");
$hide = new TKButton("Hide");
$show->onclick = new TKShowAction($label, 'display');
$hide->onclick = new TKHideAction($label, 'display');

TKToggleAction

Rotates through a set of actions.

Toggle action takes an array of actions. The first time the toggle action is invoked, it invokes the first action in the array. The second time it is invoked, it invokes the second action, and so forth. If it runs out of actions in the array, it goes back to the beginning. A simple case is a two-state toggle on a button where the first click invokes, for example, an enable action on some component, and the second click on the button invokes a disable action on that component. The third click goes back to the enable action. The effect is to have an on/off switch. But any number of states are allowed. It is even possible, though confusing, to nest toggle actions.

// two-state toggle button that toggles the color of a label
$label = new TKLabel("My background color will change");
$label->style['background-color'] = "red";

$button = new TKButton("Toggle Color");
$button->onclick = new TKToggleAction(array(
    new TKChangeStyleAction($label, array('background-color' => 'green')),
    new TKChangeStyleAction($label, array('background-color' => 'red'))
));

TKGetAction and TKPostAction

These actions initiate GET or POST requests, respectively.

Note that these are not AJAX requests. A new page will be loaded. The constructor takes two parameters: an associative array of GET/POST variables and an action, which is the URL of the page to send the request to. Both parameters are option. If no variables are given, then an empty GET/POST request is sent. If the action is not given, then the value of $_SERVER['REQUEST_URI'] will be used.

The first parameter to the constructor can also be a TKForm, in which case invoking the action will submit the form.

$button = new TKButton("Create Page");
$button->onclick = new TKPostAction(
   array('pageName' => $somePageName, 'parentId' => $pId),
   $PATH['createPage']
);

// if we have an existing form that we want to POST...
$form = new TKForm($_SERVER['REQUEST_URI'], "post");
$form->addFormInput('text', 'firstName');
//...
$button = new TKButton("Create User");
$button->onclick = new TKPostAction($form);

Note that we could use a TKSubmitAction here, as both TKPostAction and TKSubmitAction will submit the form. The value in using either over having a submit button is that the button can be located outside of the form, or can be triggered by some other mechanism, using these actions.

TKSubmitAction

TKSWATAction

Invokes a SWAT event handler (see documentation for SWAT). Similar to a Post action.

A SWAT action takes a target (which is NOT a toolkit component), an action to be performed (numeric ID), an array of additional variables to be passed to the event handler via POST and then a URL to POST to.

$button = new TKButton("Add Comment");
$button->onclick = new TKSWATAction(
    $blog->getId(),
    LocalEventHandler::ADD_COMMENT,
    array('replyTo' => $parentComment->getId()),
    $_SERVER['REQUEST_URI']
);

In recent ShERPA template-based webapps, the URL should almost always be $_SERVER['REQUEST_URI'].

TKLinkAction

TKTreeAction

Themes

All themes are derived from TKTheme. Every toolkit component has an instance of some theme class associated with it (or null). When the component is to be rendered, if it has a theme associated with it, the theme will modify the component's properties to provide suitable defaults for things such as CSS. Themes could theoretically provide more functionality, such as methods that do some partial rendering of a component in accordance with the way the theme should look, or at least providing hints. In the future, this functionality may be added to the toolkit. For now, themes simply define a default set of properties for components.

Each theme provides a default set of properties for components as well as "theme classes". The idea is that a theme could provide defaults for TKLabel, but also provide defaults for TKLabel's that have some specific purpose. These kinds of labels would be identified by having a theme class set (such as "user name"), and the theme might provide a different set of default properties for those kinds of labels. If a theme does not default any special properties for a theme class, the theme defaults are used instead. And if the theme does not provide any defaults for a given property, then the theme engine looks at parent classes for defaults (for example, if the theme does not provide a default CSS class for TKLabel, then it will look at the theme defaults for TKComponent1). If there are still none, then the property is not modified.

The default theme is TKDefaultTheme. You can change the default theme by calling Toolkit::setDefaultTheme(). This function can also force all existing components to use the new theme, if they were using the previous default theme. You can set the theme of a particular object by calling its setTheme() method. As long as the theme is changed before calling render() on the object, the changes will be visible.

1For performance reasons, this is not currently implemented. It will be added eventually.


Generated on Wed Nov 24 02:01:29 2010 for Common by  doxygen 1.5.6