This article explains how to use it to avoid messing HTML, JS & CSS code in complex fields.
To illustrate the problem we will use the existing core field to select users:
libraries/cms/form/field/user.php
This is the content of the getInput() function inside that field:
/**
* Method to get the user field input markup.
*
* @return string The field input markup.
*
* @since 1.6.0
*/
protected function getInput()
{
$html = array();
$groups = $this->getGroups();
$excluded = $this->getExcluded();
$link = 'index.php?option=com_users&view=users&layout=modal&tmpl=component&field=' . $this->id
. (isset($groups) ? ('&groups=' . base64_encode(json_encode($groups))) : '')
. (isset($excluded) ? ('&excluded=' . base64_encode(json_encode($excluded))) : '');// Initialize some field attributes.
$attr = $this->element['class'] ? ' class="' . (string) $this->element['class'] . '"' : '';
$attr .= $this->element['size'] ? ' size="' . (int) $this->element['size'] . '"' : '';// Initialize JavaScript field attributes.
$onchange = (string) $this->element['onchange'];// Load the modal behavior script.
JHtml::_('behavior.modal', 'a.modal_' . $this->id);// Build the script.
$script = array();
$script[] = ' function jSelectUser_' . $this->id . '(id, title) {';
$script[] = ' var old_id = document.getElementById("' . $this->id . '_id").value;';
$script[] = ' if (old_id != id) {';
$script[] = ' document.getElementById("' . $this->id . '_id").value = id;';
$script[] = ' document.getElementById("' . $this->id . '_name").value = title;';
$script[] = ' ' . $onchange;
$script[] = ' }';
$script[] = ' SqueezeBox.close();';
$script[] = ' }';// Add the script to the document head.
JFactory::getDocument()->addScriptDeclaration(implode("\n", $script));// Load the current username if available.
$table = JTable::getInstance('user');
if ($this->value)
{
$table->load($this->value);
}
else
{
$table->username = JText::_('JLIB_FORM_SELECT_USER');
}// Create a dummy text field with the user name.
$html[] = '<div class="input-append">';
$html[] = ' <input class="input-medium" type="text" id="' . $this->id . '_name" value="' . htmlspecialchars($table->name, ENT_COMPAT, 'UTF-8') . '"'
. ' disabled="disabled"' . $attr . ' />';// Create the user select button.
if ($this->element['readonly'] != 'true')
{
$html[] = ' <a class="btn btn-primary modal_' . $this->id . '" title="' . JText::_('JLIB_FORM_CHANGE_USER') . '" href="' . $link . '"'
. ' rel="{handler: \'iframe\', size: {x: 800, y: 500}}">';
$html[] = '<i class="icon-user"></i></a>';
}
$html[] = '</div>';// Create the real field, hidden, that stored the user id.
$html[] = '<input type="hidden" id="' . $this->id . '_id" name="' . $this->name . '" value="' . (int) $this->value . '" />';return implode("\n", $html);
}
As you can see there is some HTML and JS code embedded and messed with the PHP. The first reason to avoid/replace that is for readability. Also imagine that you have a template that doesn't use Bootstrap markup like Hathor or you want to load a different modal that doesn't use Mootools.
Can JLayouts help us here? Yes. In fact is probably the best solution. Let's do it.
First we will to move almost all the code to a layout. Our new getInput() function will be:
/**
* Method to get the user field input markup.
*
* @return string The field input markup.
*
* @since 1.6.0
*/
protected function getInput()
{
$this->groups = $this->getGroups();
$this->excluded = $this->getExcluded();return JLayoutHelper::render("libraries.cms.forms.fields.user", $this);
}
Just the basic to get the required data and pass it to the layout. Now we have to create the layout. You probably have noticed by the render function call that we are going to create it in:
layouts/libraries/cms/forms/fields/user.php
The content of the file is:
<?php
/**
* @package Joomla.Site
* @subpackage Layout
*
* @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/defined('JPATH_BASE') or die;
$data = $displayData;
$html = array();
$link = 'index.php?option=com_users&view=users&layout=modal&tmpl=component&field=' . $data->id
. (isset($data->groups) ? ('&groups=' . base64_encode(json_encode($data->groups))) : '')
. (isset($data->excluded) ? ('&excluded=' . base64_encode(json_encode($data->excluded))) : '');// Initialize some field attributes.
$attr = $data->element['class'] ? ' class="' . (string) $data->element['class'] . '"' : '';
$attr .= $data->element['size'] ? ' size="' . (int) $data->element['size'] . '"' : '';// Initialize JavaScript field attributes.
$onchange = (string) $data->element['onchange'];// Load the modal behavior script.
JHtml::_('behavior.modal', 'a.modal_' . $data->id);// Build the script.
$script = "
function jSelectUser_" . $data->id . "(id, title) {
var old_id = document.getElementById('" . $data->id . "_id').value;
if (old_id != id) {
document.getElementById('" . $data->id . "_id').value = id;
document.getElementById('" . $data->id . "_name').value = title;
" . $onchange . "
}
SqueezeBox.close();
}
";// Add the script to the document head.
JFactory::getDocument()->addScriptDeclaration($script);// Load the current username if available.
$table = JTable::getInstance('user');if ($data->value)
{
$table->load($data->value);
}
else
{
$table->username = JText::_('JLIB_FORM_SELECT_USER');
}
?>
<?php // Create a dummy text field with the user name. ?>
<div class="input-append">
<input class="input-medium" type="text" id="<?php echo $data->id; ?>_name" value="<?php echo htmlspecialchars($table->name, ENT_COMPAT, 'UTF-8'); ?>" disabled="disabled" <?php echo $attr; ?> />
<?php
// Create the user select button.
if ($data->element['readonly'] != 'true') : ?>
<a class="btn btn-primary modal_<?php echo $data->id; ?>" title="<?php echo JText::_('JLIB_FORM_CHANGE_USER'); ?>" href="/<?php echo $link; ?>" rel="{handler: 'iframe', size: {x: 800, y: 500}}">
<i class="icon-user"></i>
</a>
<?php endif; ?>
</div><?php // Create the real field, hidden, that stored the user id. ?>
<input type="hidden" id="<?php echo $data->id; ?>_id" name="<?php echo $data->name; ?>" value="<?php echo (int) $data->value; ?>" />
Now the HTML code is separated from the PHP. Also users can override it easily creating a file in the active template like:
templates/TEMPLATE_NAME/html/layouts/libraries/cms/forms/fields/user.php
All can be changed inside the template except the source data.
I sent a pull request to the core with this changes. You can see the full code submitted on Github.