From 9e548f501e558748f43c0d63e08cd496b00312ed Mon Sep 17 00:00:00 2001 From: Sean Harvey Date: Wed, 23 Mar 2011 17:12:25 +1300 Subject: [PATCH] API CHANGE FormField::Field() and FormField::FieldHolder() now render into templates on each FormField instead of creating HTML from PHP --- forms/CheckboxField.php | 82 +-------- forms/CheckboxSetField.php | 60 +++---- forms/DatalessField.php | 4 +- forms/DropdownField.php | 80 ++++----- forms/EmailField.php | 16 +- forms/FileField.php | 24 +-- forms/FileIFrameField.php | 12 +- forms/FormAction.php | 91 +++------- forms/FormField.php | 159 ++++++++---------- forms/HeaderField.php | 22 +-- forms/HiddenField.php | 14 +- forms/LabelField.php | 18 +- forms/LiteralField.php | 5 +- forms/NullableField.php | 1 + forms/OptionsetField.php | 78 ++++----- forms/ReadonlyField.php | 3 +- forms/ResetFormAction.php | 27 +-- forms/TextField.php | 32 ++-- forms/TextareaField.php | 61 ++----- forms/TreeDropdownField.php | 36 ++-- ...rameField.ss => FileIFrameField_iframe.ss} | 0 templates/forms/CheckboxField.ss | 1 + templates/forms/CheckboxFieldHolder.ss | 5 + templates/forms/CheckboxSetField.ss | 8 + templates/forms/DropdownField.ss | 5 + templates/forms/FieldHolder.ss | 6 + templates/forms/FileField.ss | 2 + templates/forms/FormAction.ss | 5 + templates/forms/FormField.ss | 2 + templates/forms/HeaderField.ss | 1 + templates/forms/HiddenField.ss | 1 + templates/forms/LabelField.ss | 1 + templates/forms/OptionsetField.ss | 8 + templates/forms/TextField.ss | 1 + templates/forms/TextareaField.ss | 5 + templates/forms/TreeDropdownField.ss | 3 + tests/forms/CheckboxSetFieldTest.php | 8 - tests/forms/DropdownFieldTest.php | 8 - tests/forms/FormFieldTest.php | 20 --- tests/model/LabelFieldTest.php | 2 +- 40 files changed, 346 insertions(+), 571 deletions(-) rename templates/{FileIFrameField.ss => FileIFrameField_iframe.ss} (100%) create mode 100644 templates/forms/CheckboxField.ss create mode 100644 templates/forms/CheckboxFieldHolder.ss create mode 100644 templates/forms/CheckboxSetField.ss create mode 100644 templates/forms/DropdownField.ss create mode 100644 templates/forms/FieldHolder.ss create mode 100644 templates/forms/FileField.ss create mode 100644 templates/forms/FormAction.ss create mode 100644 templates/forms/FormField.ss create mode 100644 templates/forms/HeaderField.ss create mode 100644 templates/forms/HiddenField.ss create mode 100644 templates/forms/LabelField.ss create mode 100644 templates/forms/OptionsetField.ss create mode 100644 templates/forms/TextField.ss create mode 100644 templates/forms/TextareaField.ss create mode 100644 templates/forms/TreeDropdownField.ss diff --git a/forms/CheckboxField.php b/forms/CheckboxField.php index 5bb562e81..f99d6b941 100644 --- a/forms/CheckboxField.php +++ b/forms/CheckboxField.php @@ -5,8 +5,6 @@ * @subpackage fields-basic */ class CheckboxField extends FormField { - - protected $disabled; function setValue($value) { $this->value = ($value) ? 1 : 0; @@ -15,54 +13,18 @@ class CheckboxField extends FormField { function dataValue() { return ($this->value) ? 1 : NULL; } - + function Value() { return ($this->value) ? 1 : 0; } - - function Field() { - $attributes = array( - 'type' => 'checkbox', - 'class' => ($this->extraClass() ? $this->extraClass() : ''), - 'id' => $this->id(), - 'name' => $this->getName(), - 'value' => 1, - 'checked' => $this->value ? 'checked' : '', - 'tabindex' => $this->getTabIndex() - ); - - if($this->disabled) $attributes['disabled'] = 'disabled'; - - return $this->createTag('input', $attributes); + + function Field($properties = array()) { + return $this->customise($properties)->renderWith('CheckboxField'); } - /** - * Checkboxes use the RightLabelledFieldHolder template, to put the field on the left - * and the label on the right. See {@link FormField::FieldHolder} for more information about - * how FieldHolder works. - */ function FieldHolder() { - if($this->labelLeft) { - return parent::FieldHolder(); - } else { - extract($this->getXMLValues(array( 'Name', 'Field', 'Title', 'Message', 'MessageType' )), - EXTR_SKIP); - $messageBlock = isset($Message) ? "$Message" : ''; - $Type = $this->XML_val('Type'); - $extraClass = $this->XML_val('extraClass'); - return << - $Field - - $messageBlock - -HTML; - - } - } - - function useLabelLeft( $labelLeft = true ) { - $this->labelLeft = $labelLeft; + $this->setFieldHolderTemplate(($this->fieldHolderTemplate) ? $this->fieldHolderTemplate : 'CheckboxFieldHolder'); + return parent::FieldHolder(); } /** @@ -79,7 +41,6 @@ HTML; /** * Returns a readonly version of this field */ - function performReadonlyTransformation() { $field = new CheckboxField_Readonly($this->name, $this->title, $this->value ? _t('CheckboxField.YES', 'Yes') : _t('CheckboxField.NO', 'No')); $field->setForm($this->form); @@ -91,6 +52,7 @@ HTML; $clone->setDisabled(true); return $clone; } + } /** @@ -99,6 +61,7 @@ HTML; * @subpackage fields-basic */ class CheckboxField_Readonly extends ReadonlyField { + function performReadonlyTransformation() { return clone $this; } @@ -106,32 +69,5 @@ class CheckboxField_Readonly extends ReadonlyField { function setValue($val) { $this->value = (int)($val) ? _t('CheckboxField.YES', 'Yes') : _t('CheckboxField.NO', 'No'); } -} -/** - * Single checkbox field, disabled - * @package forms - * @subpackage fields-basic - */ -class CheckboxField_Disabled extends CheckboxField { - - protected $disabled = true; - - /** - * Returns a single checkbox field - used by templates. - */ - function Field() { - $attributes = array( - 'type' => 'checkbox', - 'class' => ($this->extraClass() ? $this->extraClass() : ''), - 'id' => $this->id(), - 'name' => $this->getName(), - 'tabindex' => $this->getTabIndex(), - 'checked' => ($this->value) ? 'checked' : false, - 'disabled' => 'disabled' - ); - - return $this->createTag('input', $attributes); - } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/forms/CheckboxSetField.php b/forms/CheckboxSetField.php index db389695d..b982cc746 100644 --- a/forms/CheckboxSetField.php +++ b/forms/CheckboxSetField.php @@ -29,9 +29,6 @@ * array. Is it also appropriate to accept so many different * types of data when just using an array would be appropriate? * - * @todo Make use of FormField->createTag() to generate the - * HTML tag(s) for this field. - * * @package forms * @subpackage fields-basic */ @@ -47,14 +44,13 @@ class CheckboxSetField extends OptionsetField { /** * @todo Explain different source data that can be used with this field, * e.g. SQLMap, ArrayList or an array. - * - * @todo Should use CheckboxField FieldHolder rather than constructing own markup. */ - function Field() { + function Field($properties = array()) { Requirements::css(SAPPHIRE_DIR . '/css/CheckboxSetField.css'); $source = $this->source; $values = $this->value; + $items = array(); // Get values from the join, if available if(is_object($this->form)) { @@ -109,30 +105,35 @@ class CheckboxSetField extends OptionsetField { $options = "
  • No options available
  • "; } - if($source) foreach($source as $index => $item) { - if($item instanceof DataObject) { - $key = $item->ID; - $value = $item->Title; - } else { - $key = $index; - $value = $item; - } - - $odd = ($odd + 1) % 2; - $extraClass = $odd ? 'odd' : 'even'; - $extraClass .= ' val' . str_replace(' ', '', $key); - $itemID = $this->id() . '_' . ereg_replace('[^a-zA-Z0-9]+', '', $key); - $checked = ''; - - if(isset($items)) { - $checked = (in_array($key, $items) || in_array($key, $this->defaultItems)) ? ' checked="checked"' : ''; - } + if($source) { + foreach($source as $value => $item) { + if($item instanceof DataObject) { + $value = $item->ID; + $title = $item->Title; + } else { + $title = $item; + } - $disabled = ($this->disabled || in_array($key, $this->disabledItems)) ? $disabled = ' disabled="disabled"' : ''; - $options .= "
  • name[$key]\" type=\"checkbox\" value=\"$key\"$checked $disabled class=\"checkbox\" />
  • \n"; + $itemID = $this->ID() . '_' . preg_replace('/[^a-zA-Z0-9]/', '', $value); + $odd = ($odd + 1) % 2; + $extraClass = $odd ? 'odd' : 'even'; + $extraClass .= ' val' . preg_replace('/[^a-zA-Z0-9\-\_]/', '_', $value); + + $options[] = new ArrayData(array( + 'ID' => $itemID, + 'Class' => $extraClass, + 'Name' => $this->name, + 'Value' => $value, + 'Title' => $title, + 'isChecked' => in_array($value, $items) || in_array($value, $this->defaultItems), + 'isDisabled' => $this->disabled || in_array($value, $this->disabledItems) + )); + } } - - return "\n"; + + $properties = array_merge($properties, array('Options' => new ArrayList($options))); + + return $this->customise($properties)->renderWith('CheckboxSetField'); } function setDisabled($val) { @@ -287,5 +288,4 @@ class CheckboxSetField extends OptionsetField { return FormField::ExtraOptions(); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/forms/DatalessField.php b/forms/DatalessField.php index 75b85058d..bef57bc94 100644 --- a/forms/DatalessField.php +++ b/forms/DatalessField.php @@ -57,5 +57,5 @@ class DatalessField extends FormField { function getAllowHTML() { return $this->allowHTML; } -} -?> \ No newline at end of file + +} \ No newline at end of file diff --git a/forms/DropdownField.php b/forms/DropdownField.php index 5f8f066dc..839bca967 100644 --- a/forms/DropdownField.php +++ b/forms/DropdownField.php @@ -130,67 +130,45 @@ class DropdownField extends FormField { parent::__construct($name, ($title===null) ? $name : $title, $value, $form); } - /** - * Returns a - * tag and option elements inside is as the content of the id() . "\" name=\"{$this->name}\" value=\"" . $this->attrValue() . "\" />"; + + function Field($properties = array()) { + return $this->customise($properties)->renderWith('HiddenField'); } + function FieldHolder() { return $this->Field(); } + function performReadonlyTransformation() { $clone = clone $this; $clone->setReadonly(true); return $clone; } - + function IsHidden() { return true; } diff --git a/forms/LabelField.php b/forms/LabelField.php index 875c0a396..c160e6f7b 100644 --- a/forms/LabelField.php +++ b/forms/LabelField.php @@ -26,20 +26,12 @@ class LabelField extends DatalessField { parent::__construct($name, $title, $form); } - + /** * Returns a label containing the title, and an HTML class if given. */ - function Field() { - $attributes = array( - 'class' => $this->extraClass(), - 'id' => $this->id() - ); - return $this->createTag( - 'label', - $attributes, - ($this->getAllowHTML() ? $this->title : Convert::raw2xml($this->title)) - ); + function Field($properties = array()) { + return $this->customise($properties)->renderWith('LabelField'); } -} -?> \ No newline at end of file + +} \ No newline at end of file diff --git a/forms/LiteralField.php b/forms/LiteralField.php index 294a4a617..0ffc66b58 100644 --- a/forms/LiteralField.php +++ b/forms/LiteralField.php @@ -30,11 +30,11 @@ class LiteralField extends DatalessField { function FieldHolder() { return is_object($this->content) ? $this->content->forTemplate() : $this->content; } - + function Field() { return $this->FieldHolder(); } - + /** * Sets the content of this field to a new value * @@ -63,4 +63,5 @@ class LiteralField extends DatalessField { $clone->setReadonly(true); return $clone; } + } \ No newline at end of file diff --git a/forms/NullableField.php b/forms/NullableField.php index 04e15397d..52ea6edd0 100644 --- a/forms/NullableField.php +++ b/forms/NullableField.php @@ -82,6 +82,7 @@ class NullableField extends FormField { $nullableCheckbox = new CheckboxField($this->getIsNullId()); } $nullableCheckbox->setValue(is_null($this->dataValue())); + return $this->valueField->Field() . ' ' . $nullableCheckbox->Field() . ' ' . $this->getIsNullLabel().''; } diff --git a/forms/OptionsetField.php b/forms/OptionsetField.php index 31746a4f5..66f88e548 100644 --- a/forms/OptionsetField.php +++ b/forms/OptionsetField.php @@ -60,59 +60,39 @@ class OptionsetField extends DropdownField { * @var Array */ protected $disabledItems = array(); - - /** - * Creates a new optionset field. - * @param name The field name - * @param title The field title - * @param source An map of the dropdown items - * @param value The current value - * @param form The parent form - */ - function __construct($name, $title = "", $source = array(), $value = "", $form = null) { - parent::__construct($name, $title, $source, $value, $form); + + function Field($properties = array()) { + $source = $this->getSource(); + $odd = 0; + $options = array(); + if($source) { + foreach($source as $value => $title) { + $itemID = $this->ID() . '_' . preg_replace('/[^a-zA-Z0-9]/', '', $value); + $odd = ($odd + 1) % 2; + $extraClass = $odd ? 'odd' : 'even'; + $extraClass .= ' val' . preg_replace('/[^a-zA-Z0-9\-\_]/', '_', $value); + + $options[] = new ArrayData(array( + 'ID' => $itemID, + 'Class' => $extraClass, + 'Name' => $this->name, + 'Value' => $value, + 'Title' => $title, + 'isChecked' => $value == $this->value, + 'isDisabled' => $this->disabled || in_array($value, $this->disabledItems), + )); + } + } + + $properties = array_merge($properties, array('Options' => new ArrayList($options))); + + return $this->customise($properties)->renderWith('OptionsetField'); } - /** - * Create a UL tag containing sets of radio buttons and labels. The IDs are set to - * FieldID_ItemKey, where ItemKey is the key with all non-alphanumerics removed. - * - * @todo Should use CheckboxField FieldHolder rather than constructing own markup. - */ - function Field() { - $options = ''; - $odd = 0; - $source = $this->getSource(); - foreach($source as $key => $value) { - $itemID = $this->id() . "_" . ereg_replace('[^a-zA-Z0-9]+','',$key); - - if($key == $this->value/* || $useValue */) { - $useValue = false; - $checked = " checked=\"checked\""; - } else { - $checked=""; - } - - $odd = ($odd + 1) % 2; - $extraClass = $odd ? "odd" : "even"; - $extraClass .= " val" . preg_replace('/[^a-zA-Z0-9\-\_]/','_', $key); - $disabled = ($this->disabled || in_array($key, $this->disabledItems)) ? 'disabled="disabled"' : ''; - - $options .= "
  • name\" type=\"radio\" value=\"$key\"$checked $disabled class=\"radio\" />
  • \n"; - } - $id = $this->id(); - return "\n"; - } - - protected $disabled = false; - function setDisabled($val) { - $this->disabled = $val; - } - function performReadonlyTransformation() { // Source and values are DataObject sets. $items = $this->getSource(); - $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->setReadonly(true); return $field; @@ -138,5 +118,5 @@ class OptionsetField extends DropdownField { function ExtraOptions() { return new ArrayList(); } + } -?> \ No newline at end of file diff --git a/forms/ReadonlyField.php b/forms/ReadonlyField.php index 4681d9772..920deee73 100644 --- a/forms/ReadonlyField.php +++ b/forms/ReadonlyField.php @@ -14,5 +14,4 @@ class ReadonlyField extends FormField { function performReadonlyTransformation() { return clone $this; } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/forms/ResetFormAction.php b/forms/ResetFormAction.php index e2f7cba31..6490ad8ee 100644 --- a/forms/ResetFormAction.php +++ b/forms/ResetFormAction.php @@ -6,28 +6,9 @@ * @subpackage actions */ class ResetFormAction extends FormAction { - - function Field() { - $attributes = array( - 'class' => 'action' . ($this->extraClass() ? $this->extraClass() : ''), - 'id' => $this->id(), - 'type' => 'reset', - 'name' => $this->action, - ); - - if($this->isReadonly()) { - $attributes['disabled'] = 'disabled'; - $attributes['class'] = $attributes['class'] . ' disabled'; - } - - $attributes['title'] = ($this->description) ? $this->description : ($this->dontEscape) ? $this->Title() : $this->attrTitle(); - - if($this->useButtonTag) { - return $this->createTag('button', $attributes, $this->attrTitle()); - } - return $this->createTag('input', $attributes); + public function Type() { + return 'reset'; } - -} -?> \ No newline at end of file + +} \ No newline at end of file diff --git a/forms/TextField.php b/forms/TextField.php index fa06f6459..7c372adac 100644 --- a/forms/TextField.php +++ b/forms/TextField.php @@ -14,7 +14,7 @@ class TextField extends FormField { /** * Returns an input field, class="text" and type="text" with an optional maxlength */ - function __construct($name, $title = null, $value = "", $maxLength = null, $form = null){ + function __construct($name, $title = null, $value = '', $maxLength = null, $form = null) { $this->maxLength = $maxLength; parent::__construct($name, $title, $value, $form); @@ -33,28 +33,22 @@ class TextField extends FormField { function getMaxLength() { return $this->maxLength; } - - function Field() { - $attributes = array( - 'type' => 'text', - 'class' => 'text' . ($this->extraClass() ? $this->extraClass() : ''), - 'id' => $this->id(), - 'name' => $this->getName(), - 'value' => $this->Value(), - 'tabindex' => $this->getTabIndex(), - 'maxlength' => ($this->maxLength) ? $this->maxLength : null, - 'size' => ($this->maxLength) ? min( $this->maxLength, 30 ) : null + + function Field($properties = array()) { + $properties = array_merge( + $properties, + array( + 'MaxLength' => ($this->getMaxLength()) ? $this->getMaxLength() : null, + 'Size' => ($this->getMaxLength()) ? min($this->getMaxLength(), 30) : null + ) ); - - if($this->disabled) $attributes['disabled'] = 'disabled'; - - return $this->createTag('input', $attributes); + + return $this->customise($properties)->renderWith('TextField'); } - + function InternallyLabelledField() { if(!$this->value) $this->value = $this->Title(); return $this->Field(); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/forms/TextareaField.php b/forms/TextareaField.php index 45f267d30..461951f4d 100644 --- a/forms/TextareaField.php +++ b/forms/TextareaField.php @@ -21,8 +21,9 @@ * @subpackage fields-basic */ class TextareaField extends FormField { - protected $rows, $cols, $disabled = false, $readonly = false; - + + protected $rows, $cols; + /** * Create a new textarea field. * @@ -38,7 +39,7 @@ class TextareaField extends FormField { $this->cols = $cols; parent::__construct($name, $title, $value, $form); } - + /** * Create the +<% end_if %> \ No newline at end of file diff --git a/templates/forms/TreeDropdownField.ss b/templates/forms/TreeDropdownField.ss new file mode 100644 index 000000000..cfa688843 --- /dev/null +++ b/templates/forms/TreeDropdownField.ss @@ -0,0 +1,3 @@ +
    data-metadata="$Metadata"<% end_if %>> + +
    \ No newline at end of file diff --git a/tests/forms/CheckboxSetFieldTest.php b/tests/forms/CheckboxSetFieldTest.php index 994b0e04d..69d281e7a 100644 --- a/tests/forms/CheckboxSetFieldTest.php +++ b/tests/forms/CheckboxSetFieldTest.php @@ -47,14 +47,6 @@ class CheckboxSetFieldTest extends SapphireTest { ); } - function testAddExtraClass() { - /* CheckboxSetField has an extra class name and is in the HTML the field returns */ - $cboxSetField = new CheckboxSetField('FeelingOk', 'Are you feeling ok?', array(0 => 'No', 1 => 'Yes'), '', null, '(Select one)'); - $cboxSetField->addExtraClass('thisIsMyExtraClassForCheckboxSetField'); - preg_match('/thisIsMyExtraClassForCheckboxSetField/', $cboxSetField->Field(), $matches); - $this->assertTrue($matches[0] == 'thisIsMyExtraClassForCheckboxSetField'); - } - function testSaveWithNothingSelected() { $article = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithouttags'); diff --git a/tests/forms/DropdownFieldTest.php b/tests/forms/DropdownFieldTest.php index 45ffab61b..b00e300b3 100644 --- a/tests/forms/DropdownFieldTest.php +++ b/tests/forms/DropdownFieldTest.php @@ -5,14 +5,6 @@ */ class DropdownFieldTest extends SapphireTest { - function testAddExtraClass() { - /* DropdownField has an extra class name and is in the HTML the field returns */ - $dropdownField = new DropdownField('FeelingOk', 'Are you feeling ok?', array(0 => 'No', 1 => 'Yes'), '', null, '(Select one)'); - $dropdownField->addExtraClass('thisIsMyExtraClassForDropdownField'); - preg_match('/thisIsMyExtraClassForDropdownField/', $dropdownField->Field(), $matches); - $this->assertEquals($matches[0], 'thisIsMyExtraClassForDropdownField'); - } - function testGetSource() { $source = array(1=>'one'); $field = new DropdownField('Field', null, $source); diff --git a/tests/forms/FormFieldTest.php b/tests/forms/FormFieldTest.php index dbdf8c7ef..4105040d8 100644 --- a/tests/forms/FormFieldTest.php +++ b/tests/forms/FormFieldTest.php @@ -5,26 +5,6 @@ */ class FormFieldTest extends SapphireTest { - function testFieldHasExtraClass() { - /* TextField has an extra class name and is in the HTML the field returns */ - $textField = new TextField('Name'); - $textField->addExtraClass('thisIsMyClassNameForTheFormField'); - preg_match('/thisIsMyClassNameForTheFormField/', $textField->Field(), $matches); - $this->assertTrue($matches[0] == 'thisIsMyClassNameForTheFormField'); - - /* EmailField has an extra class name and is in the HTML the field returns */ - $emailField = new EmailField('Email'); - $emailField->addExtraClass('thisIsMyExtraClassForEmailField'); - preg_match('/thisIsMyExtraClassForEmailField/', $emailField->Field(), $matches); - $this->assertTrue($matches[0] == 'thisIsMyExtraClassForEmailField'); - - /* OptionsetField has an extra class name and is in the HTML the field returns */ - $optionsetField = new OptionsetField('FeelingOk', 'Are you feeling ok?', array(0 => 'No', 1 => 'Yes'), '', null, '(Select one)'); - $optionsetField->addExtraClass('thisIsMyExtraClassForOptionsetField'); - preg_match('/thisIsMyExtraClassForOptionsetField/', $optionsetField->Field(), $matches); - $this->assertTrue($matches[0] == 'thisIsMyExtraClassForOptionsetField'); - } - function testEveryFieldTransformsReadonlyAsClone() { $fieldClasses = ClassInfo::subclassesFor('FormField'); foreach($fieldClasses as $fieldClass) { diff --git a/tests/model/LabelFieldTest.php b/tests/model/LabelFieldTest.php index 4e51b831f..1d420c288 100644 --- a/tests/model/LabelFieldTest.php +++ b/tests/model/LabelFieldTest.php @@ -8,6 +8,6 @@ class LabelFieldTest extends SapphireTest { function testFieldHasNoNameAttribute() { $field = new LabelField('MyName', 'MyTitle'); - $this->assertEquals($field->Field(), ''); + $this->assertEquals($field->Field(), ''); } }