Creating Property Forms

When developing Widgets and Shortcodes, it will become inevitable to display a dialog of options to the user to configure. Barebones CMS has a standard mechanism of creating the property form (dialog) at the top of the page. Dialogs, internally known as Property Forms, are a combination of the LoadProperties() editor Javascript call, which makes the AJAX call, and the BB_PropertyForm() editor global function, which displays the form.

An example of a property form/dialog.
An example of a property form/dialog.

LoadProperties(...)

This Javascript function is very simple. It takes a Javascript object and make an AJAX call with the output targeted to the property form on the page. This approach means that only one property form/dialog can be open at a time. However, this restriction doesn't really get in the way. For cases where BB_PropertyForm() won't be called, LoadProperties2() can be used.

Most property forms are created when the user clicks a hyperlink. When creating hyperlinks, LoadProperties() is wrapped up inside the BB_CreatePropertiesLink() function, which you should never need to call directly. For widgets, BB_CreateWidgetPropertiesLink() will generate a correct link. For shortcodes, CreateShortcodePropertiesLink() will generate a correct hyperlink.

For advanced property forms that have additional hyperlinks within the property form that load more property forms, the action phase (the current 'bb_action' value plus '_submit') may call LoadProperties() to return to a previous property form. Creating a correct object for a LoadProperties() call is wrapped up inside the BB_CreatePropertiesJS() function, which you should also never need to call directly. For widgets, BB_CreateWidgetPropertiesJS() will generate a correct Javascript object. For shortcodes, CreateShortcodePropertiesJS() will generate a correct Javascript object.

Example code from the Layout widget that returns to the configuration dialog after creating a new wireframe layout:

?>
<div class="success">Layout created.</div>
<script type="text/javascript">
LoadProperties(<?php echo BB_CreateWidgetPropertiesJS("bb_layout_configure_widget"); ?>);
</script>
<?php

The best way to learn how to use LoadProperties() is to look at the source code of the default Widgets and official Shortcodes.

BB_PropertyForm($options)

This PHP function is specifically designed for generating a property form/dialog during an AJAX request. It is only available inside the editor but is highly customizable. Every property form/dialog in the Barebones CMS editor uses this function to create a consistent user experience.

The only parameter passed into BB_PropertyForm() is an array of options. It is highly recommended to create the options array, pass it into a plugin callback via BB_RunPluginActionInfo(), and then run BB_PropertyForm(). This approach allows a plugin to modify the dialog.

Here is an example from the Layout widget:

<?php
	BB_RunPluginAction("pre_bb_layout_configure_widget_new_layout");

	$desc = "<br />";
	$desc .= BB_CreateWidgetPropertiesLink("Back", "bb_layout_configure_widget");

	$patterns = array();
	$dirlist = BB_GetDirectoryList(ROOT_PATH . "/" . WIDGET_PATH . "/" . $basepath);
	foreach ($dirlist["files"] as $name)
	{
		$pos = strrpos($name, ".");
		if ($pos !== false && substr($name, $pos) == ".html")
		{
			$info = $this->ExtractFileInfo(ROOT_PATH . "/" . WIDGET_PATH . "/" . $basepath . "/" . $name);
			if ($info !== false)  $patterns[substr($name, 0, $pos)] = $info[""]["info"][0];
		}
	}

	$options = array(
		"title" => "Configure " . $bb_widget->_f . " - New Layout",
		"desc" => "Create a new layout.",
		"htmldesc" => $desc,
		"fields" => array(
			array(
				"title" => "Pattern",
				"type" => "select",
				"name" => "pattern",
				"options" => $patterns,
				"desc" => "The pattern to use for the new layout."
			),
			array(
				"title" => "Name",
				"type" => "text",
				"name" => "name",
				"value" => "",
				"desc" => "The name of the new layout."
			)
		),
		"submit" => "Create",
		"focus" => true
	);

	BB_RunPluginActionInfo("bb_layout_configure_widget_new_layout_options", $options);

	BB_PropertyForm($options);

	BB_RunPluginAction("post_bb_layout_configure_widget_new_layout");
?>

Result:

The Layout widget New Layout property form/dialog.
The Layout widget New Layout property form/dialog.

The best way to learn how to use BB_PropertyForm() is to look at the source code of the default Widgets and official Shortcodes.

What follows is complete documentation on each option that can appear in the $options array. Some options are always required or required when some other option is specified and are clearly labeled as such. The extensive "fields" option gets its own special section of documentation.

Option: "title"

Required: Yes

Type: String

Example: "New Layout"

This specifies the title of the entire dialog. Displayed in a fairly large font, so try to keep it short.

Option: "desc"

Required: Yes

Type: String

Example: "Create a new layout."

This should be a simple plain-text explanation of what this dialog is for. If you need something more advanced, combine this with the "htmldesc" option.

Option: "htmldesc"

Required: No

Type: String

Example: [See the example at the start of this section]

This allows for custom HTML to be included immediately after the "desc" option. Most "htmldesc" definitions start with a line break 'br' tag.

Option: "submit"

Required: No

Type: String

Example: "Create"

This specifies the text to display on the button to submit the form. If not specified, no form will be created unless the "useform" option is set to true.

Option: "useform"

Required: No

Type: Boolean (Default is false)

This rarely used option forces a form to be created (surrounding 'form' tags) even when the "submit" option is not specified. Such forms are driven entirely by Javascript.

Option: "bb_action"

Required: No

Type: String (Default is $_REQUEST["bb_action"] . "_submit")

This option, primarily used in Shortcodes, allows the default target 'bb_action' to be changed. Shortcodes, in particular, use 'sc_action' instead of 'bb_action' to carry out tasks.

Option: "hidden"

Required: No

Type: Array

Example: array("id" => $id)

This is an array of hidden name => value pairs to be sent along with the form submission.

Option: "focus"

Required: No

Type: Boolean or String

Example: true

This sets the element of the property form/dialog to move keyboard focus to. When set to 'true', the first viable element is used. When set to 'false' or not set, no element gains focus. When set to a specific element id, that element gains focus.

Option: "fields"

Required: No

Type: Array

Example: [See the example at the start of this section]

This is a generic structure for defining the form fields/elements that will appear. If there is only one field/element and it doesn't specify a "title", a special class is added that removes the background and border (which is also useful for table-only property forms/dialogs). Form fields/elements appear in the order they are specified.

Each field/element can specify a "title" and a "desc" or "htmldesc". The "title" is displayed before the element in a bold font and should be short. A "desc" is the description of the field in more detail and displays after the element in a smaller font. The "htmldesc" option is to be rarely used since it does not HTML entity encode input, which can be useful in rare cases.

Each field/element must specify a "type", which must be one of the following strings: "static", "text", "password", "checkbox", "select", "textarea", "table", or "custom". Each of these are specified in detail below.

Option: "fields", "type" => "static"

Required:

This field/element type displays a string to the user for informational purposes only. Rarely used.

Option: "fields", "type" => "text"

Required:

This field/element type displays a standard single-line text field to the user that they can manipulate.

Option: "fields", "type" => "password"

Required:

This field/element type displays a standard single-line password field to the user that they can manipulate.

Option: "fields", "type" => "checkbox"

Required:

Optional:

This field/element type displays a standard checkbox and label to the user that they can click.

Option: "fields", "type" => "select"

Required:

Optional:

This field/element type displays a standard select dropdown to the user that they can select from. If the 'select' option is specified, one or more elements are selected. Multiple elements can only be selected when 'multiple' is 'true'. When 'multiple' is 'true', the dropdown becomes a series of checkboxes.

Dropdown groups are also supported. For the 'options' array, the 'name' becomes the name of the group and 'value' contains an array of 'name' => 'value' pairs.

Option: "fields", "type" => "textarea"

Required:

This field/element type displays a standard multi-line text field to the user that they can manipulate.

Option: "fields", "type" => "table"

Required:

Optional:

This element type displays a standard HTML table. A property form/dialog with a table is usually intermediate functionality with a number of common options for many items.

The 'order' option allows the user to reorder rows via drag-and-drop. A special column appears on the left-hand side that gets tied to jQuery TableDnD. This option requires either the 'submit' or 'useform' option to be used so the code can submit the form when the user reorders the rows.

Option: "fields", "type" => "custom"

Required:

This element type is used for things that are custom in nature. An example of this is the SWFUpload reusable component. An empty 'div' is used in a custom element and then Javascript later on loads the reusable component from the server and injects it into the 'div'.

Displaying Success and Error Messages

There are two different types of error message display and one way to display a success message from a property form/dialog. Most errors and success messages are handled in the '_submit' portion of the property form/dialog (i.e. the portion of code that takes action). Property forms/dialogs inject the output of the AJAX callback from the form right into the form. This section covers all three types of messages in detail.

Successfully Processed

Upon successful completion of processing, it is important to display a message even though its display will usually be brief (occasionally seen as a momentary flash of 'green' with text before the dialog goes away).

Example code from the Layout widget:

?>
<div class="success">Layout activated.</div>
<script type="text/javascript">
LoadProperties(<?php echo BB_CreateWidgetPropertiesJS("bb_layout_configure_widget"); ?>);
ReloadIFrame();
</script>
<?php

Notice the 'div' that precedes the Javascript code. That is the success message. Success messages always precede Javascript code that updates the modified areas of the Barebones CMS editor and either close the property form/dialog or load another property form/dialog.

Form Processing Errors

Inevitably a user will leave out some critical piece of information for a successful form submission. This is where the BB_PropertyFormError($message) function comes into play. This function takes a string to display to the user, displays it, and then exit()'s PHP. The function makes it easy to quickly exit processing as soon as an error occurs.

An error message is displayed when the user attempts to add a widget without specifying a display name.
An error message is displayed when the user attempts to add a widget without specifying a display name.

The error message is display in a red box and should be meaningful enough for the user to diagnose. That is, human-readable. Technical errors are not usually very helpful.

Form Creation Errors

The other type of error message is very rare. Occasionally, it is easier/faster to display an option to the user and then determine if they have permission to perform that option/action when they click it instead of not displaying the option. In these circumstances, the BB_PropertyFormLoadError($message) function comes into play. This function simply displays the error message (instead of a form) and closes the property form dialog that was initiated.

You should generally prefer to avoid this and, in most cases, it is avoidable. It really boils down to a judgment call as to how much CPU/RAM/etc. would it take to correctly calculate the permissions surrounding the option every time the code executes.

© CubicleSoft