ENHANCEMENT: populate FormField:: on the fly based on class name of field rather than requiring explict definition.

This commit is contained in:
Will Rossiter 2012-04-14 17:32:29 +12:00
parent 907568b182
commit 07d2d5273a
35 changed files with 272 additions and 221 deletions

View File

@ -65,10 +65,10 @@
.cms table.ss-gridfield-table tr th button.ss-gridfield-sort:hover { background-position: right -34px; } .cms table.ss-gridfield-table tr th button.ss-gridfield-sort:hover { background-position: right -34px; }
.cms table.ss-gridfield-table tr th button.ss-gridfield-sort.ss-gridfield-sorted-desc { background-position: right -72px; } .cms table.ss-gridfield-table tr th button.ss-gridfield-sort.ss-gridfield-sorted-desc { background-position: right -72px; }
.cms table.ss-gridfield-table tr th button.ss-gridfield-sort.ss-gridfield-sorted-asc { background-position: right -116px; } .cms table.ss-gridfield-table tr th button.ss-gridfield-sort.ss-gridfield-sorted-asc { background-position: right -116px; }
.cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button { position: absolute; right: 5px; top: -28px; display: block; text-indent: -9999em; width: 30px; height: 28px; border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-width: 1px; border-color: #9a9a9a; background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -webkit-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -moz-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -o-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -ms-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, linear-gradient(#ffffff, #d9d9d9); } .cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button { position: absolute; top: 0; right: 0; display: block; text-indent: -9999em; width: 30px; height: 28px; border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-width: 1px; border-color: #9a9a9a; background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -webkit-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -moz-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -o-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -ms-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, linear-gradient(#ffffff, #d9d9d9); }
.cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button.hover-alike:active { background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4199cd), color-stop(100%, #2e7ead)); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -moz-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -o-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -ms-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient(#4199cd, #2e7ead); -moz-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -webkit-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -o-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); } .cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button.hover-alike:active { background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4199cd), color-stop(100%, #2e7ead)); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -moz-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -o-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -ms-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient(#4199cd, #2e7ead); -moz-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -webkit-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -o-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); }
.cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button.hover-alike { background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4199cd), color-stop(100%, #2e7ead)); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -moz-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -o-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -ms-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient(#4199cd, #2e7ead); } .cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button.hover-alike { background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4199cd), color-stop(100%, #2e7ead)); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -moz-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -o-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -ms-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient(#4199cd, #2e7ead); }
.cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button { position: absolute; right: 34px; top: -28px; display: block; text-indent: -9999em; width: 30px; height: 28px; float: right; border-radius: 0px; border-bottom-width: 1px; border-color: #9a9a9a; background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -webkit-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -moz-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -o-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -ms-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, linear-gradient(#ffffff, #d9d9d9); } .cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button { position: absolute; right: 29px; top: 0; display: block; text-indent: -9999em; width: 30px; height: 28px; float: right; border-radius: 0px; border-bottom-width: 1px; border-color: #9a9a9a; background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -webkit-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -moz-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -o-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -ms-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, linear-gradient(#ffffff, #d9d9d9); }
.cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button.filtered:hover { background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ff0000), color-stop(100%, #cc0000)); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -moz-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -o-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -ms-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient(#ff0000, #cc0000); } .cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button.filtered:hover { background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ff0000), color-stop(100%, #cc0000)); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -moz-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -o-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -ms-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient(#ff0000, #cc0000); }
.cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button.filtered:active { background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ff0000), color-stop(100%, #cc0000)); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -moz-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -o-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -ms-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient(#ff0000, #cc0000); -moz-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -webkit-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -o-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); } .cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button.filtered:active { background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ff0000), color-stop(100%, #cc0000)); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -moz-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -o-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -ms-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient(#ff0000, #cc0000); -moz-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -webkit-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -o-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); }
.cms table.ss-gridfield-table tr th input.ss-gridfield-sort { padding: 2px; } .cms table.ss-gridfield-table tr th input.ss-gridfield-sort { padding: 2px; }

View File

@ -1,15 +1,12 @@
<?php <?php
/** /**
* Single checkbox field. * Single checkbox field.
*
* @package forms * @package forms
* @subpackage fields-basic * @subpackage fields-basic
*/ */
class CheckboxField extends FormField { class CheckboxField extends FormField {
protected $template = 'CheckboxField';
protected $fieldHolderTemplate = 'CheckboxFieldHolder';
function setValue($value) { function setValue($value) {
$this->value = ($value) ? 1 : 0; $this->value = ($value) ? 1 : 0;
return $this; return $this;
@ -23,17 +20,6 @@ class CheckboxField extends FormField {
return ($this->value) ? 1 : 0; return ($this->value) ? 1 : 0;
} }
/**
* Returns a restricted field holder used within things like FieldGroups
*/
function SmallFieldHolder() {
$result = $this->Field();
if($t = $this->Title()) {
$result .= "<label for=\"" . $this->id() ."\">$t</label> ";
}
return $result;
}
function getAttributes() { function getAttributes() {
$attrs = parent::getAttributes(); $attrs = parent::getAttributes();
$attrs['value'] = 1; $attrs['value'] = 1;
@ -65,6 +51,7 @@ class CheckboxField extends FormField {
/** /**
* Readonly version of a checkbox field - "Yes" or "No". * Readonly version of a checkbox field - "Yes" or "No".
*
* @package forms * @package forms
* @subpackage fields-basic * @subpackage fields-basic
*/ */

View File

@ -34,10 +34,8 @@
*/ */
class CheckboxSetField extends OptionsetField { class CheckboxSetField extends OptionsetField {
protected $template = 'CheckboxSetField';
/** /**
* @var Array * @var array
*/ */
protected $defaultItems = array(); protected $defaultItems = array();
@ -130,7 +128,7 @@ class CheckboxSetField extends OptionsetField {
$properties = array_merge($properties, array('Options' => new ArrayList($options))); $properties = array_merge($properties, array('Options' => new ArrayList($options)));
return $this->customise($properties)->renderWith($this->getTemplate()); return $this->customise($properties)->renderWith($this->getTemplates());
} }
/** /**
@ -288,5 +286,4 @@ class CheckboxSetField extends OptionsetField {
function ExtraOptions() { function ExtraOptions() {
return FormField::ExtraOptions(); return FormField::ExtraOptions();
} }
} }

View File

@ -1,8 +1,11 @@
<?php <?php
/** /**
* Base class for all fields that contain other fields. * Base class for all fields that contain other fields.
* Implements sequentialisation - so that when we're saving / loading data, we can populate *
* a tabbed form properly. All of the children are stored in $this->children * Implements sequentialisation - so that when we're saving / loading data, we
* can populate a tabbed form properly. All of the children are stored in
* $this->children
*
* @package forms * @package forms
* @subpackage fields-structural * @subpackage fields-structural
*/ */
@ -33,11 +36,6 @@ class CompositeField extends FormField {
*/ */
protected $tag = 'div'; protected $tag = 'div';
/**
* @var string
*/
protected $template = "CompositeField";
/** /**
* @var String Optional description for this set of fields. * @var String Optional description for this set of fields.
* If the {@link $tag} property is set to use a 'fieldset', this will be * If the {@link $tag} property is set to use a 'fieldset', this will be
@ -152,32 +150,6 @@ class CompositeField extends FormField {
); );
} }
public function Field($properties = array()) {
$props = $this->customise($properties);
return $props->renderWith($this->getTemplate());
}
/**
* @param array
*/
function FieldHolder($properties = array()) {
$props = $this->customise($properties);
return $props->renderWith($this->getTemplate());
}
/**
* Returns the fields in the restricted field holder.
*
* @param array
*/
function SmallFieldHolder($properties = array()) {
$obj = ($properties) ? $this->customise($properties) : $this;
return $obj->renderWith($this->getTemplate());
}
/** /**
* Add all of the non-composite fields contained within this field to the * Add all of the non-composite fields contained within this field to the
* list. * list.

View File

@ -76,8 +76,6 @@
*/ */
class DropdownField extends FormField { class DropdownField extends FormField {
protected $template = 'DropdownField';
/** /**
* @var boolean $source Associative or numeric array of all dropdown items, * @var boolean $source Associative or numeric array of all dropdown items,
* with array key as the submitted field value, and the array value as a * with array key as the submitted field value, and the array value as a
@ -158,7 +156,7 @@ class DropdownField extends FormField {
$properties = array_merge($properties, array('Options' => new ArrayList($options))); $properties = array_merge($properties, array('Options' => new ArrayList($options)));
return $this->customise($properties)->renderWith($this->getTemplate()); return parent::Field($properties);
} }
function getAttributes() { function getAttributes() {

View File

@ -85,29 +85,6 @@ class FieldGroup extends CompositeField {
return preg_replace("/[^a-zA-Z0-9]+/", "", $this->title); return preg_replace("/[^a-zA-Z0-9]+/", "", $this->title);
} }
/**
* Generates the field HTML with the HTML for child {@link FormField}
*
* @param array $properties custom properties for the template
*/
function Field($properties = array()) {
$props = $this->customise(new ArrayData($properties));
return $props->renderWith('FieldGroupField');
}
/**
* Generates the field HTML with the HTML for child {@link FormField}
*
* @param array $properties custom properties for the template
*/
function FieldHolder($properties = array()) {
$props = $this->customise(new ArrayData($properties));
return $props->renderWith('FieldGroupHolder');
}
/** /**
* Set an odd/even class * Set an odd/even class
* *

View File

@ -43,8 +43,6 @@
*/ */
class FileField extends FormField { class FileField extends FormField {
protected $template = 'FileField';
/** /**
* Restrict filesize for either all filetypes * Restrict filesize for either all filetypes
* or a specific extension, with extension-name * or a specific extension, with extension-name
@ -112,8 +110,11 @@ class FileField extends FormField {
} }
public function Field($properties = array()) { public function Field($properties = array()) {
$properties = array_merge($properties, array('MaxFileSize' => $this->getValidator()->getAllowedMaxFileSize())); $properties = array_merge($properties, array(
return $this->customise($properties)->renderWith($this->getTemplate()); 'MaxFileSize' => $this->getValidator()->getAllowedMaxFileSize()
));
return parent::Field($properties);
} }
function getAttributes() { function getAttributes() {

View File

@ -12,8 +12,6 @@
*/ */
class FileIFrameField extends FileField { class FileIFrameField extends FileField {
protected $template = 'FileIFrameField';
public static $allowed_actions = array ( public static $allowed_actions = array (
'iframe', 'iframe',
'EditFileForm', 'EditFileForm',

View File

@ -20,8 +20,6 @@
*/ */
class FormAction extends FormField { class FormAction extends FormField {
protected $template = 'FormAction';
protected $action; protected $action;
/** /**
@ -36,12 +34,14 @@ class FormAction extends FormField {
/** /**
* Create a new action button. * Create a new action button.
*
* @param action The method to call when the button is clicked * @param action The method to call when the button is clicked
* @param title The label on the button * @param title The label on the button
* @param form The parent form, auto-set when the field is placed inside a form * @param form The parent form, auto-set when the field is placed inside a form
*/ */
function __construct($action, $title = "", $form = null) { function __construct($action, $title = "", $form = null) {
$this->action = "action_$action"; $this->action = "action_$action";
parent::__construct($this->action, $title, null, $form); parent::__construct($this->action, $title, null, $form);
} }
@ -67,7 +67,8 @@ class FormAction extends FormField {
'UseButtonTag' => $this->useButtonTag 'UseButtonTag' => $this->useButtonTag
) )
); );
return $this->customise($properties)->renderWith($this->getTemplate());
return parent::Field($properties);
} }
function FieldHolder($properties = array()) { function FieldHolder($properties = array()) {

View File

@ -57,30 +57,34 @@ class FormField extends RequestHandler {
protected $containerFieldSet; protected $containerFieldSet;
/** /**
* @var $readonly boolean * @var boolean
*/ */
protected $readonly = false; protected $readonly = false;
/** /**
* @var $disabled boolean * @var boolean
*/ */
protected $disabled = false; protected $disabled = false;
/** /**
* @var String * @var string custom validation message for the Field
*/
protected $template = 'FormField';
/**
* @var Custom Validation Message for the Field
*/ */
protected $customValidationMessage = ""; protected $customValidationMessage = "";
/** /**
* Template name to render this FormField field holder into. * Name of the template used to render this form field. If not set, then
* will look up the class ancestry for the first matching template where
* the template name equals the class name.
*
* To explicitly use a custom template or one named other than the form
* field see {@link setTemplate()}, {@link setFieldHolderTemplate()}
*
* @var string * @var string
*/ */
protected $fieldHolderTemplate = 'FieldHolder'; protected
$template,
$fieldHolderTemplate,
$smallFieldHolderTemplate;
/** /**
* @var array All attributes on the form field (not the field holder). * @var array All attributes on the form field (not the field holder).
@ -268,7 +272,7 @@ class FormField extends RequestHandler {
* Uses {@link Message()} and {@link MessageType()} to add validatoin * Uses {@link Message()} and {@link MessageType()} to add validatoin
* error classes which can be used to style the contained tags. * error classes which can be used to style the contained tags.
* *
* @return String CSS-classnames * @return string CSS-classnames
*/ */
function extraClass() { function extraClass() {
$classes = array(); $classes = array();
@ -323,8 +327,8 @@ class FormField extends RequestHandler {
* CreditCardField, CurrencyField, DateField, DatetimeField, FieldGroup, GridField, HtmlEditorField, * CreditCardField, CurrencyField, DateField, DatetimeField, FieldGroup, GridField, HtmlEditorField,
* ImageField, ImageFormAction, InlineFormAction, ListBoxField, etc. * ImageField, ImageFormAction, InlineFormAction, ListBoxField, etc.
* *
* @param String * @param string
* @param String * @param string
*/ */
function setAttribute($name, $value) { function setAttribute($name, $value) {
$this->attributes[$name] = $value; $this->attributes[$name] = $value;
@ -335,7 +339,7 @@ class FormField extends RequestHandler {
* Get an HTML attribute defined by the field, or added through {@link setAttribute()}. * Get an HTML attribute defined by the field, or added through {@link setAttribute()}.
* Caution: Doesn't work on all fields, see {@link setAttribute()}. * Caution: Doesn't work on all fields, see {@link setAttribute()}.
* *
* @return String * @return string
*/ */
function getAttribute($name) { function getAttribute($name) {
$attrs = $this->getAttributes(); $attrs = $this->getAttributes();
@ -355,13 +359,14 @@ class FormField extends RequestHandler {
'disabled' => $this->isDisabled(), 'disabled' => $this->isDisabled(),
'title' => $this->getDescription(), 'title' => $this->getDescription(),
); );
return array_merge($attrs, $this->attributes); return array_merge($attrs, $this->attributes);
} }
/** /**
* @param Array Custom attributes to process. Falls back to {@link getAttributes()}. * @param Array Custom attributes to process. Falls back to {@link getAttributes()}.
* If at least one argument is passed as a string, all arguments act as excludes by name. * If at least one argument is passed as a string, all arguments act as excludes by name.
* @return String HTML attributes, ready for insertion into an HTML tag * @return string HTML attributes, ready for insertion into an HTML tag
*/ */
function getAttributesHTML($attrs = null) { function getAttributesHTML($attrs = null) {
$exclude = (is_string($attrs)) ? func_get_args() : null; $exclude = (is_string($attrs)) ? func_get_args() : null;
@ -433,7 +438,75 @@ class FormField extends RequestHandler {
} }
/** /**
* @return String * Return TRUE if security token protection is enabled on the parent {@link Form}.
*
* @return bool
*/
public function securityTokenEnabled() {
$form = $this->getForm();
if(!$form) return false;
return $form->getSecurityToken()->isEnabled();
}
/**
* Sets the error message to be displayed on the form field
* Set by php validation of the form
*/
function setError($message, $messageType) {
$this->message = $message;
$this->messageType = $messageType;
return $this;
}
/**
* Set the custom error message to show instead of the default
* format of Please Fill In XXX. Different from setError() as
* that appends it to the standard error messaging
*
* @param string Message for the error
*/
public function setCustomValidationMessage($msg) {
$this->customValidationMessage = $msg;
return $this;
}
/**
* Get the custom error message for this form field. If a custom
* message has not been defined then just return blank. The default
* error is defined on {@link Validator}.
*
* @todo Should the default error message be stored here instead
* @return string
*/
public function getCustomValidationMessage() {
return $this->customValidationMessage;
}
/**
* Set name of template (without path or extension).
* Caution: Not consistently implemented in all subclasses,
* please check the {@link Field()} method on the subclass for support.
*
* @param string
*/
function setTemplate($template) {
$this->template = $template;
return $this;
}
/**
* @return string
*/
function getTemplate() {
return $this->template;
}
/**
* @return string
*/ */
public function getFieldHolderTemplate() { public function getFieldHolderTemplate() {
return $this->fieldHolderTemplate; return $this->fieldHolderTemplate;
@ -446,75 +519,34 @@ class FormField extends RequestHandler {
* Caution: Not consistently implemented in all subclasses, * Caution: Not consistently implemented in all subclasses,
* please check the {@link Field()} method on the subclass for support. * please check the {@link Field()} method on the subclass for support.
* *
* @param String * @param string
*/ */
public function setFieldHolderTemplate($template) { public function setFieldHolderTemplate($template) {
$this->fieldHolderTemplate = $template; $this->fieldHolderTemplate = $template;
return $this; return $this;
} }
/** /**
* Return TRUE if security token protection is enabled on the parent {@link Form}. * @return string
*/
public function getSmallFieldHolderTemplate() {
return $this->smallFieldHolderTemplate;
}
/**
* Set name of template (without path or extension) for the small holder,
* which in turn is responsible for rendering {@link Field()}.
* *
* @return bool
*/
public function securityTokenEnabled() {
$form = $this->getForm();
if(!$form) return false;
return $form->getSecurityToken()->isEnabled();
}
/**
* Sets the error message to be displayed on the form field
* Set by php validation of the form
*/
function setError($message, $messageType) {
$this->message = $message;
$this->messageType = $messageType;
return $this;
}
/**
* Set the custom error message to show instead of the default
* format of Please Fill In XXX. Different from setError() as
* that appends it to the standard error messaging
*
* @param String Message for the error
*/
public function setCustomValidationMessage($msg) {
$this->customValidationMessage = $msg;
return $this;
}
/**
* Get the custom error message for this form field. If a custom
* message has not been defined then just return blank. The default
* error is defined on {@link Validator}.
*
* @todo Should the default error message be stored here instead
* @return String
*/
public function getCustomValidationMessage() {
return $this->customValidationMessage;
}
/**
* Set name of template (without path or extension).
* Caution: Not consistently implemented in all subclasses, * Caution: Not consistently implemented in all subclasses,
* please check the {@link Field()} method on the subclass for support. * please check the {@link Field()} method on the subclass for support.
* *
* @param String * @param string
*/ */
function setTemplate($template) { public function setSmallFieldHolderTemplate($template) {
$this->template = $template; $this->smallFieldHolderTemplate = $template;
return $this;
}
/** return $this;
* @return String
*/
function getTemplate() {
return $this->template;
} }
/** /**
@ -529,7 +561,8 @@ class FormField extends RequestHandler {
*/ */
function Field($properties = array()) { function Field($properties = array()) {
$obj = ($properties) ? $this->customise($properties) : $this; $obj = ($properties) ? $this->customise($properties) : $this;
return $obj->renderWith($this->getTemplate());
return $obj->renderWith($this->getTemplates());
} }
/** /**
@ -544,26 +577,78 @@ class FormField extends RequestHandler {
*/ */
function FieldHolder($properties = array()) { function FieldHolder($properties = array()) {
$obj = ($properties) ? $this->customise($properties) : $this; $obj = ($properties) ? $this->customise($properties) : $this;
return $obj->renderWith($this->getFieldHolderTemplate());
return $obj->renderWith($this->getFieldHolderTemplates());
} }
/** /**
* Returns a restricted field holder used within things like FieldGroups. * Returns a restricted field holder used within things like FieldGroups.
*
* @param array $properties
*
* @return string
*/ */
function SmallFieldHolder() { function SmallFieldHolder($properties = array()) {
$result = ''; $obj = ($properties) ? $this->customise($properties) : $this;
// set label
if($title = $this->RightTitle()){ return $obj->renderWith($this->getSmallFieldHolderTemplates());
$result .= "<label class=\"right\" for=\"" . $this->id() . "\">{$title}</label>\n";
} elseif($title = $this->LeftTitle()) {
$result .= "<label class=\"left\" for=\"" . $this->id() . "\">{$title}</label>\n";
} elseif($title = $this->Title()) {
$result .= "<label for=\"" . $this->id() . "\">{$title}</label>\n";
} }
$result .= $this->Field(); /**
* Returns an array of templates to use for rendering {@link FieldH}
*
* @return array
*/
public function getTemplates() {
return $this->_templates($this->getTemplate());
}
return $result; /**
* Returns an array of templates to use for rendering {@link FieldHolder}
*
* @return array
*/
public function getFieldHolderTemplates() {
return $this->_templates(
$this->getFieldHolderTemplate(),
'_holder'
);
}
/**
* Returns an array of templates to use for rendering {@link SmallFieldHolder}
*
* @return array
*/
public function getSmallFieldHolderTemplates() {
return $this->_templates(
$this->getSmallFieldHolderTemplate(),
'_holder_small'
);
}
/**
* Generate an array of classname strings to use for rendering this form
* field into HTML
*
* @param string $custom custom template (if set)
* @param string $suffix template suffix
*
* @return array $stack a stack of
*/
private function _templates($custom = null, $suffix = null) {
$matches = array();
foreach(array_reverse(ClassInfo::ancestry($this)) as $className) {
$matches[] = $className . $suffix;
if($className == "FormField") break;
}
if($custom) array_unshift($matches, $custom);
return $matches;
} }
/** /**
@ -722,7 +807,7 @@ class FormField extends RequestHandler {
} }
/** /**
* @return String * @return string
*/ */
function getDescription() { function getDescription() {
return $this->description; return $this->description;

View File

@ -1,14 +1,14 @@
<?php <?php
/** /**
* Field that generates a heading tag. * Field that generates a heading tag.
*
* This can be used to add extra text in your forms. * This can be used to add extra text in your forms.
*
* @package forms * @package forms
* @subpackage fields-dataless * @subpackage fields-dataless
*/ */
class HeaderField extends DatalessField { class HeaderField extends DatalessField {
protected $template = 'HeaderField';
/** /**
* @var int $headingLevel The level of the <h1> to <h6> HTML tag. Default: 2 * @var int $headingLevel The level of the <h1> to <h6> HTML tag. Default: 2
*/ */
@ -53,5 +53,4 @@ class HeaderField extends DatalessField {
function Type() { function Type() {
return null; return null;
} }
} }

View File

@ -1,13 +1,12 @@
<?php <?php
/** /**
* Hidden field. * Hidden field.
*
* @package forms * @package forms
* @subpackage fields-dataless * @subpackage fields-dataless
*/ */
class HiddenField extends FormField { class HiddenField extends FormField {
protected $template = 'HiddenField';
function FieldHolder($properties = array()) { function FieldHolder($properties = array()) {
return $this->Field($properties); return $this->Field($properties);
} }

View File

@ -9,8 +9,6 @@
*/ */
class LabelField extends DatalessField { class LabelField extends DatalessField {
protected $template = 'LabelField';
/** /**
* @param string $name * @param string $name
* @param string $title * @param string $title

View File

@ -64,6 +64,7 @@ class ListboxField extends DropdownField {
function __construct($name, $title = '', $source = array(), $value = '', $size = null, $multiple = false) { function __construct($name, $title = '', $source = array(), $value = '', $size = null, $multiple = false) {
if($size) $this->size = $size; if($size) $this->size = $size;
if($multiple) $this->multiple = $multiple; if($multiple) $this->multiple = $multiple;
parent::__construct($name, $title, $source, $value); parent::__construct($name, $title, $source, $value);
} }
@ -96,8 +97,12 @@ class ListboxField extends DropdownField {
)); ));
} }
} }
$properties = array_merge($properties, array('Options' => new ArrayList($options)));
return $this->customise($properties)->renderWith($this->getTemplate()); $properties = array_merge($properties, array(
'Options' => new ArrayList($options)
));
return $this->customise($properties)->renderWith($this->getTemplates());
} }
function getAttributes() { function getAttributes() {

View File

@ -56,8 +56,6 @@
*/ */
class OptionsetField extends DropdownField { class OptionsetField extends DropdownField {
protected $template = 'OptionsetField';
/** /**
* @var Array * @var Array
*/ */
@ -67,6 +65,7 @@ class OptionsetField extends DropdownField {
$source = $this->getSource(); $source = $this->getSource();
$odd = 0; $odd = 0;
$options = array(); $options = array();
if($source) { if($source) {
foreach($source as $value => $title) { foreach($source as $value => $title) {
$itemID = $this->ID() . '_' . preg_replace('/[^a-zA-Z0-9]/', '', $value); $itemID = $this->ID() . '_' . preg_replace('/[^a-zA-Z0-9]/', '', $value);
@ -86,9 +85,13 @@ class OptionsetField extends DropdownField {
} }
} }
$properties = array_merge($properties, array('Options' => new ArrayList($options))); $properties = array_merge($properties, array(
'Options' => new ArrayList($options)
));
return $this->customise($properties)->renderWith($this->getTemplate()); return $this->customise($properties)->renderWith(
$this->getTemplates()
);
} }
function performReadonlyTransformation() { function performReadonlyTransformation() {
@ -97,6 +100,7 @@ class OptionsetField extends DropdownField {
$field = new LookupField($this->name, $this->title ? $this->title : '', $items, $this->value); $field = new LookupField($this->name, $this->title ? $this->title : '', $items, $this->value);
$field->setForm($this->form); $field->setForm($this->form);
$field->setReadonly(true); $field->setReadonly(true);
return $field; return $field;
} }

View File

@ -1,15 +1,15 @@
<?php <?php
/** /**
* SelectionGroup represents a number of fields that are selectable by a radio button that appears at * SelectionGroup represents a number of fields that are selectable by a radio
* the beginning of each item. Using CSS, you can configure the field to only display its contents if * button that appears at the beginning of each item. Using CSS, you can
* the corresponding radio button is selected. * configure the field to only display its contents if the corresponding radio
* button is selected.
*
* @package forms * @package forms
* @subpackage fields-structural * @subpackage fields-structural
*/ */
class SelectionGroup extends CompositeField { class SelectionGroup extends CompositeField {
protected $template = "SelectionGroup";
/** /**
* Create a new selection group. * Create a new selection group.
* @param name The field name of the selection group. * @param name The field name of the selection group.
@ -59,6 +59,7 @@ class SelectionGroup extends CompositeField {
$firstSelected = $checked =""; $firstSelected = $checked ="";
} }
return new ArrayList($newItems); return new ArrayList($newItems);
} }
@ -73,7 +74,7 @@ class SelectionGroup extends CompositeField {
$obj = $properties ? $this->customise($properties) : $this; $obj = $properties ? $this->customise($properties) : $this;
return $obj->renderWith($this->template); return $obj->renderWith($this->getFieldHolderTemplates());
} }
} }

View File

@ -27,8 +27,6 @@
*/ */
class TabSet extends CompositeField { class TabSet extends CompositeField {
protected $template = "TabSetFieldHolder";
/** /**
* @param string $name Identifier * @param string $name Identifier
* @param string $title (Optional) Natural language title of the tabset * @param string $title (Optional) Natural language title of the tabset
@ -81,7 +79,8 @@ class TabSet extends CompositeField {
Requirements::javascript(SAPPHIRE_DIR . '/javascript/TabSet.js'); Requirements::javascript(SAPPHIRE_DIR . '/javascript/TabSet.js');
$obj = $properties ? $this->customise($properties) : $this; $obj = $properties ? $this->customise($properties) : $this;
return $obj->renderWith($this->template);
return $obj->renderWith($this->getFieldHolderTemplates());
} }
/** /**
@ -90,6 +89,7 @@ class TabSet extends CompositeField {
public function Tabs() { public function Tabs() {
return $this->children; return $this->children;
} }
public function setTabs($children){ public function setTabs($children){
$this->children = $children; $this->children = $children;
} }

View File

@ -1,15 +1,14 @@
<?php <?php
/** /**
* Text input field. * Text input field.
*
* @package forms * @package forms
* @subpackage fields-basic * @subpackage fields-basic
*/ */
class TextField extends FormField { class TextField extends FormField {
protected $template = 'TextField';
/** /**
* @var Int * @var int
*/ */
protected $maxLength; protected $maxLength;
@ -23,15 +22,16 @@ class TextField extends FormField {
} }
/** /**
* @param Int $length * @param int $length
*/ */
function setMaxLength($length) { function setMaxLength($length) {
$this->maxLength = $length; $this->maxLength = $length;
return $this; return $this;
} }
/** /**
* @return Int * @return int
*/ */
function getMaxLength() { function getMaxLength() {
return $this->maxLength; return $this->maxLength;
@ -51,5 +51,4 @@ class TextField extends FormField {
if(!$this->value) $this->value = $this->Title(); if(!$this->value) $this->value = $this->Title();
return $this->Field(); return $this->Field();
} }
} }

View File

@ -22,15 +22,13 @@
*/ */
class TextareaField extends FormField { class TextareaField extends FormField {
protected $template = 'TextareaField';
/** /**
* @var Int Visible number of text lines. * @var int Visible number of text lines.
*/ */
protected $rows = 5; protected $rows = 5;
/** /**
* @var Int Width of the text area (in average character widths) * @var int Width of the text area (in average character widths)
*/ */
protected $cols = 20; protected $cols = 20;
@ -60,13 +58,14 @@ class TextareaField extends FormField {
} }
function getTemplate() { function getTemplate() {
return ($this->isReadonly()) ? "{$this->template}_Readonly" : $this->template; return ($this->isReadonly()) ? "{$this->template}_readonly" : $this->template;
} }
/** /**
* Performs a readonly transformation on this field. You should still be able * Performs a readonly transformation on this field. You should still be
* to copy from this field, and it should still send when you submit * able to copy from this field, and it should still send when you submit
* the form it's attached to. * the form it's attached to.
*
* The element shouldn't be both disabled and readonly at the same time. * The element shouldn't be both disabled and readonly at the same time.
*/ */
function performReadonlyTransformation() { function performReadonlyTransformation() {
@ -80,6 +79,7 @@ class TextareaField extends FormField {
* Performs a disabled transformation on this field. You shouldn't be able to * Performs a disabled transformation on this field. You shouldn't be able to
* copy from this field, and it should not send any data when you submit the * copy from this field, and it should not send any data when you submit the
* form it's attached to. * form it's attached to.
*
* The element shouldn't be both disabled and readonly at the same time. * The element shouldn't be both disabled and readonly at the same time.
*/ */
function performDisabledTransformation() { function performDisabledTransformation() {

View File

@ -1,13 +1,12 @@
<?php <?php
/** /**
* Allows visibility of a group of fields to be toggled using '+' and '-' icons * Allows visibility of a group of fields to be toggled using '+' and '-' icons
*
* @package forms * @package forms
* @subpackage fields-structural * @subpackage fields-structural
*/ */
class ToggleCompositeField extends CompositeField { class ToggleCompositeField extends CompositeField {
protected $template = "ToggleCompositeField";
/** /**
* @var $headingLevel int * @var $headingLevel int
*/ */
@ -28,7 +27,8 @@ class ToggleCompositeField extends CompositeField {
Requirements::javascript(SAPPHIRE_DIR . "/javascript/ToggleCompositeField.js"); Requirements::javascript(SAPPHIRE_DIR . "/javascript/ToggleCompositeField.js");
$obj = $properties ? $this->customise($properties) : $this; $obj = $properties ? $this->customise($properties) : $this;
return $obj->renderWith($this->template);
return $obj->renderWith($this->getTemplates());
} }
/** /**
@ -41,7 +41,7 @@ class ToggleCompositeField extends CompositeField {
} }
/** /**
* @return String * @return string
*/ */
public function HeadingLevel() { public function HeadingLevel() {
return $this->headingLevel; return $this->headingLevel;

View File

@ -44,11 +44,6 @@ class UploadField extends FileField {
'$Action!' => '$Action', '$Action!' => '$Action',
); );
/**
* @var String
*/
protected $template = 'UploadField';
/** /**
* @var String * @var String
*/ */
@ -375,13 +370,15 @@ class UploadField extends FileField {
if (is_numeric($config['maxNumberOfFiles']) && $this->getItems()->count()) { if (is_numeric($config['maxNumberOfFiles']) && $this->getItems()->count()) {
$configOverwrite['maxNumberOfFiles'] = $config['maxNumberOfFiles'] - $this->getItems()->count(); $configOverwrite['maxNumberOfFiles'] = $config['maxNumberOfFiles'] - $this->getItems()->count();
} }
$config = array_merge($config, $this->ufConfig, $configOverwrite); $config = array_merge($config, $this->ufConfig, $configOverwrite);
return $this->customise(array( return $this->customise(array(
'configString' => str_replace('"', "'", Convert::raw2json($config)), 'configString' => str_replace('"', "'", Convert::raw2json($config)),
'config' => new ArrayData($config), 'config' => new ArrayData($config),
'multiple' => $config['maxNumberOfFiles'] !== 1, 'multiple' => $config['maxNumberOfFiles'] !== 1,
'displayInput' => (!isset($configOverwrite['maxNumberOfFiles']) || $configOverwrite['maxNumberOfFiles']) 'displayInput' => (!isset($configOverwrite['maxNumberOfFiles']) || $configOverwrite['maxNumberOfFiles'])
))->renderWith($this->getTemplate()); ))->renderWith($this->getTemplates());
} }
/** /**

View File

@ -12,8 +12,6 @@
*/ */
class GridFieldDetailForm implements GridField_URLHandler { class GridFieldDetailForm implements GridField_URLHandler {
/** /**
* @var String * @var String
*/ */

View File

@ -375,8 +375,8 @@ $gf_grid_x: 16px;
} }
&.ss-gridfield-button-filter.ss-ui-button{ &.ss-gridfield-button-filter.ss-ui-button{
position:absolute; position:absolute;
right:5px; //positions filter button in correct position on top of input field top: 0;
top:-28px; right: 0;
display:block; display:block;
text-indent:-9999em; text-indent:-9999em;
width:30px; width:30px;
@ -412,8 +412,8 @@ $gf_grid_x: 16px;
} }
&.ss-gridfield-button-reset.ss-ui-button{ &.ss-gridfield-button-reset.ss-ui-button{
position:absolute; position:absolute;
right:34px; //positions reset button in correct position on top of input field and to the left of the filter button right: 29px;
top:-28px; top: 0;
display:block; display:block;
text-indent:-9999em; text-indent:-9999em;
width:30px; width:30px;

View File

@ -0,0 +1,5 @@
<% if $Title %>
<label class="checkboxfield-small" <% if ID %>for="$ID"<% end_if %>>$Title</label>
<% end_if %>
$Field

View File

@ -1,11 +0,0 @@
<%-- Renders a CheckboxField with $multiple=true as a select element which can save into relations.--%>
<%-- TODO Make relation saving available on ListboxField --%>
<select id="$ID" class="$extraClass" name="$Name[]" multiple="true">
<% if Options.Count %>
<% control Options %>
<option class="$Class" value="$Value"<% if isChecked %> selected="selected"<% end_if %>>
$Title
</option>
<% end_control %>
<% end_if %>
</select>

View File

@ -1,4 +1,4 @@
<$Tag class="CompositeField $extraClass <% if ColumnCount %>multi-column<% end_if %>"> <$Tag class="CompositeField $extraClass <% if ColumnCount %>multicolumn<% end_if %>">
<% if $Tag == 'fieldset' && $Legend %> <% if $Tag == 'fieldset' && $Legend %>
<legend>$Legend</legend> <legend>$Legend</legend>
<% end_if %> <% end_if %>
@ -6,10 +6,10 @@
<% loop FieldList %> <% loop FieldList %>
<% if ColumnCount %> <% if ColumnCount %>
<div class="column-{$ColumnCount} $FirstLast"> <div class="column-{$ColumnCount} $FirstLast">
$FieldHolder $Field
</div> </div>
<% else %> <% else %>
$FieldHolder $Field
<% end_if %> <% end_if %>
<% end_loop %> <% end_loop %>
</$Tag> </$Tag>

View File

@ -0,0 +1,15 @@
<$Tag class="CompositeField $extraClass <% if ColumnCount %>multicolumn<% end_if %>">
<% if $Tag == 'fieldset' && $Legend %>
<legend>$Legend</legend>
<% end_if %>
<% loop FieldList %>
<% if ColumnCount %>
<div class="column-{$ColumnCount} $FirstLast">
$FieldHolder
</div>
<% else %>
$FieldHolder
<% end_if %>
<% end_loop %>
</$Tag>

View File

@ -0,0 +1,15 @@
<$Tag class="field CompositeField $extraClass <% if ColumnCount %>multicolumn<% end_if %>">
<% if $Tag == 'fieldset' && $Legend %>
<legend>$Legend</legend>
<% end_if %>
<% loop FieldList %>
<% if ColumnCount %>
<div class="column-{$ColumnCount} $FirstLast">
$SmallFieldHolder
</div>
<% else %>
$SmallFieldHolder
<% end_if %>
<% end_loop %>
</$Tag>

View File

@ -1,7 +1,7 @@
<div class="fieldgroup <% if Zebra %>fieldgroup-zebra<% end_if %>" <% if ID %>id="$ID"<% end_if %>> <div class="fieldgroup <% if Zebra %>fieldgroup-zebra<% end_if %>" <% if ID %>id="$ID"<% end_if %>>
<% loop FieldList %> <% loop FieldList %>
<div class="fieldgroup-field $FirstLast $EvenOdd"> <div class="fieldgroup-field $FirstLast $EvenOdd">
SmallFieldHolder $SmallFieldHolder
</div> </div>
<% end_loop %> <% end_loop %>
</div> </div>

View File

@ -0,0 +1,11 @@
<div class="fieldholder-small">
<% if $RightTitle %>
<label class="right fieldholder-small-label" <% if ID %>for="$ID"<% end_if %>>$RightTitle</label>
<% else_if $LeftTitle %>
<label class="left fieldholder-small-label" <% if ID %>for="$ID"<% end_if %>>$LeftTitle</label>
<% else_if $Title %>
<label class="fieldholder-small-label" <% if ID %>for="$ID"<% end_if %>>$Title</label>
<% end_if %>
$Field
</div>