These will be described below. There are some other important concepts to get out of the way first.
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 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.
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:
$c->set('name', "foo")
--> the fastest way $c->setName("foo")
--> uses a dynamic function with the property name uppercased $c->name = "foo"
--> uses hidden getters and setters and is slightly faster than option 2
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');
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.
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);
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);
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("<TKButton>Click Me!</TKButton>", 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);
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);
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:
$c
to a container's default slot: $container->add($c)
$container->add($c, 'header')
$container->addLabel("Foo")
$container->addLabelTo('header', "Foo")
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')));
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.
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)
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);
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);
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.
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.
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');
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')) ));
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.
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']
.
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.