Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

ENHANCEMENT Allowing custom attributes in (most) FormField implementa…

…tions, which allows for HTML5 data attributes
  • Loading branch information...
commit b5421d9598570cc9e96d434900aad66842a0786c 1 parent c77f4e8
@chillu chillu authored
Showing with 407 additions and 137 deletions.
  1. +21 −0 docs/en/changelogs/3.0.0.md
  2. +12 −2 forms/CheckboxField.php
  3. +7 −6 forms/CheckboxSetField.php
  4. +15 −6 forms/CompositeField.php
  5. +6 −6 forms/CountryDropdownField.php
  6. +2 −0  forms/CreditCardField.php
  7. +5 −0 forms/CurrencyField.php
  8. +13 −0 forms/DatalessField.php
  9. +4 −0 forms/DateField.php
  10. +7 −6 forms/DropdownField.php
  11. +4 −8 forms/EmailField.php
  12. +7 −0 forms/FileField.php
  13. +16 −1 forms/FormAction.php
  14. +85 −13 forms/FormField.php
  15. +1 −10 forms/GroupedDropdownField.php
  16. +14 −0 forms/HeaderField.php
  17. +7 −0 forms/HiddenField.php
  18. +12 −11 forms/HtmlEditorField.php
  19. +25 −13 forms/ListboxField.php
  20. +4 −0 forms/NumericField.php
  21. +9 −2 forms/PasswordField.php
  22. +19 −0 forms/ReadonlyField.php
  23. +9 −2 forms/ResetFormAction.php
  24. +5 −7 forms/TextField.php
  25. +11 −15 forms/TextareaField.php
  26. +4 −0 forms/TimeField.php
  27. +5 −1 forms/TreeDropdownField.php
  28. +2 −2 templates/SelectionGroup.ss
  29. +1 −1  templates/forms/CheckboxField.ss
  30. +1 −1  templates/forms/CheckboxFieldHolder.ss
  31. +11 −7 templates/forms/CheckboxSetField.ss
  32. +1 −1  templates/forms/DropdownField.ss
  33. +4 −2 templates/forms/FieldHolder.ss
  34. +1 −1  templates/forms/FileField.ss
  35. +2 −2 templates/forms/FormAction.ss
  36. +2 −2 templates/forms/FormField.ss
  37. +1 −1  templates/forms/HeaderField.ss
  38. +1 −1  templates/forms/HiddenField.ss
  39. +1 −1  templates/forms/LabelField.ss
  40. +1 −1  templates/forms/OptionsetField.ss
  41. +1 −1  templates/forms/TextField.ss
  42. +1 −1  templates/forms/TextareaField.ss
  43. +2 −2 templates/forms/TreeDropdownField.ss
  44. +44 −0 tests/forms/FormFieldTest.php
  45. +1 −1  tests/model/LabelFieldTest.php
View
21 docs/en/changelogs/3.0.0.md
@@ -63,6 +63,27 @@ not when simply using the CMS or developing other CMS functionality.
If you want to extend the CMS stylesheets for your own projects without SCSS,
please create a new CSS file and link it into the CMS via `[api:LeftAndMain::require_css()]`.
+### FormField consistently adds classes to HTML elements ###
+
+The [api:FormField] API has been refactored to use SilverStripe templates
+for constructing the field HTML, as well as new accessors for HTML attributes.
+This change makes the HTML a bit more predictable, but it also means that
+you need to check any code (CSS, JavaScript, etc) relying on the old inconsistencies.
+Particularly, CSS class names applied through [api:FormField->addExtraClass()]
+and the "type" class are now consistently added to the container `<div>`
+as well as the HTML form element itself.
+
+ :::html
+ Before (abbreviated):
+ <div class="field checkbox extraClass"...>
+ <input type="checkbox".../>
+ </div>
+
+ After (abbreviated):
+ <div class="field checkbox extraClass"...>
+ <input type="checkbox" class="checkbox extraClass".../>
+ </div>
+
### Restructured files and folders ###
In order to make the `sapphire` framework useable without the `cms` module,
View
14 forms/CheckboxField.php
@@ -22,8 +22,6 @@ function Value() {
return ($this->value) ? 1 : 0;
}
- }
-
/**
* Returns a restricted field holder used within things like FieldGroups
*/
@@ -35,6 +33,18 @@ function SmallFieldHolder() {
return $result;
}
+ function getAttributes() {
+ $attrs = parent::getAttributes();
+ $attrs['value'] = 1;
+ return array_merge(
+ $attrs,
+ array(
+ 'checked' => ($this->Value()) ? 'checked' : null,
+ 'type' => 'checkbox',
+ )
+ );
+ }
+
/**
* Returns a readonly version of this field
*/
View
13 forms/CheckboxSetField.php
@@ -98,12 +98,9 @@ function Field($properties = array()) {
}
$odd = 0;
- $options = '';
+ $options = array();
- if ($source == null) {
- $source = array();
- $options = "<li>No options available</li>";
- }
+ if ($source == null) $source = array();
if($source) {
foreach($source as $value => $item) {
@@ -122,7 +119,7 @@ function Field($properties = array()) {
$options[] = new ArrayData(array(
'ID' => $itemID,
'Class' => $extraClass,
- 'Name' => $this->name,
+ 'Name' => "{$this->name}[{$value}]",
'Value' => $value,
'Title' => $title,
'isChecked' => in_array($value, $items) || in_array($value, $this->defaultItems),
@@ -283,6 +280,10 @@ function performReadonlyTransformation() {
return $field;
}
+
+ function Type() {
+ return 'optionset checkboxset';
+ }
function ExtraOptions() {
return FormField::ExtraOptions();
View
21 forms/CompositeField.php
@@ -83,15 +83,25 @@ public function setChildren($children) {
$this->children = $children;
}
+ function extraClasses() {
+ $classes = array('field', 'CompositeField', parent::extraClasses());
+ if($this->columnCount) $classes[] = 'multicolumn';
+ return implode(' ', $classes);
+ }
+
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array('tabindex' => null, 'type' => null, 'value' => null, 'type' => null)
+ );
+ }
+
/**
* Returns the fields nested inside another DIV
*/
function FieldHolder() {
+ $content = '';
$fs = $this->FieldList();
- $idAtt = isset($this->id) ? " id=\"{$this->id}\"" : '';
- $className = ($this->columnCount) ? "field CompositeField {$this->extraClass()} multicolumn" : "field CompositeField {$this->extraClass()}";
- $content = "<div class=\"$className\"$idAtt>\n";
-
foreach($fs as $subfield) {
if($this->columnCount) {
$className = "column{$this->columnCount}";
@@ -101,9 +111,8 @@ function FieldHolder() {
$content .= "\n" . $subfield->FieldHolder() . "\n";
}
}
- $content .= "</div>\n";
- return $content;
+ $this->createTag('div', $this->getAttributes(), $content);
}
/**
View
12 forms/CountryDropdownField.php
@@ -22,14 +22,14 @@ function __construct($name, $title = null, $source = null, $value = "", $form=nu
function defaultToVisitorCountry($val) {
$this->defaultToVisitorCountry = $val;
}
-
- function Field() {
+
+ function Value() {
$source = $this->getSource();
-
if($this->defaultToVisitorCountry && !$this->value || !isset($source[$this->value])) {
- $this->value = ($vc = Geoip::visitor_country()) ? $vc : Geoip::get_default_country_code();
+ return ($vc = Geoip::visitor_country()) ? $vc : Geoip::get_default_country_code();
+ } else {
+ return $this->value;
}
-
- return parent::Field();
}
+
}
View
2  forms/CreditCardField.php
@@ -9,6 +9,8 @@ class CreditCardField extends TextField {
function Field() {
$parts = explode("\n", chunk_split($this->value,4,"\n"));
$parts = array_pad($parts, 4, "");
+
+ // TODO Mark as disabled/readonly
$field = "<span id=\"{$this->name}_Holder\" class=\"creditCardField\">" .
"<input autocomplete=\"off\" name=\"{$this->name}[0]\" value=\"$parts[0]\" maxlength=\"4\"" . $this->getTabIndexHTML(0) . " /> - " .
"<input autocomplete=\"off\" name=\"{$this->name}[1]\" value=\"$parts[1]\" maxlength=\"4\"" . $this->getTabIndexHTML(1) . " /> - " .
View
5 forms/CurrencyField.php
@@ -27,6 +27,11 @@ function dataValue() {
return 0.00;
}
}
+
+ function Type() {
+ return 'currency text';
+ }
+
/**
* Create a new class for this field
*/
View
13 forms/DatalessField.php
@@ -18,6 +18,15 @@ class DatalessField extends FormField {
* Always returns false.
*/
function hasData() { return false; }
+
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array(
+ 'type' => 'hidden',
+ )
+ );
+ }
/**
* Returns the field's representation in the form.
@@ -58,4 +67,8 @@ function getAllowHTML() {
return $this->allowHTML;
}
+ function Type() {
+ return 'readonly';
+ }
+
}
View
4 forms/DateField.php
@@ -174,6 +174,10 @@ function Field() {
return $html;
}
+
+ function Type() {
+ return 'date text';
+ }
/**
* Sets the internal value to ISO date format.
View
13 forms/DropdownField.php
@@ -162,6 +162,13 @@ function Field($properties = array()) {
return $this->customise($properties)->renderWith($this->getTemplate());
}
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array('type' => null)
+ );
+ }
+
/**
* @return boolean
*/
@@ -230,12 +237,6 @@ function performReadonlyTransformation() {
return $field;
}
- function extraClass() {
- $ret = parent::extraClass();
- if($this->extraClass) $ret .= " $this->extraClass";
- return $ret;
- }
-
/**
* Set form being disabled
*/
View
12 forms/EmailField.php
@@ -6,6 +6,10 @@
*/
class EmailField extends TextField {
+ function Type() {
+ return 'email text';
+ }
+
function jsValidation() {
$formID = $this->form->FormName();
$error = _t('EmailField.VALIDATIONJS', 'Please enter an email address.');
@@ -41,14 +45,6 @@ function jsValidation() {
}
/**
- * Returns the field type - used by templates.
- * @return string
- */
- function Type() {
- return 'text';
- }
-
- /**
* Validates for RFC 2822 compliant email adresses.
*
* @see http://www.regular-expressions.info/email.html
View
7 forms/FileField.php
@@ -117,6 +117,13 @@ public function Field($properties = array()) {
return $this->customise($properties)->renderWith($this->getTemplate());
}
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array('type' => 'file')
+ );
+ }
+
public function saveInto(DataObject $record) {
if(!isset($_FILES[$this->name])) return false;
$fileClass = File::get_class_for_file_extension(pathinfo($_FILES[$this->name]['name'], PATHINFO_EXTENSION));
View
17 forms/FormAction.php
@@ -91,7 +91,22 @@ function Field($properties = array()) {
}
public function Type() {
- return ($this->useButtonTag) ? 'button' : 'submit';
+ return 'action';
+ }
+
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array(
+ 'disabled' => ($this->isReadonly() || $this->isDisabled()),
+ 'value' => $this->Title(),
+ 'type' => ($this->useButtonTag) ? null : 'submit'
+ )
+ );
+ }
+
+ function extraClass() {
+ return 'action ' . parent::extraClass();
}
/**
View
98 forms/FormField.php
@@ -90,6 +90,12 @@ class FormField extends RequestHandler {
protected $fieldHolderTemplate = 'FieldHolder';
/**
+ * @var array All attributes on the form field (not the field holder).
+ * Partially determined based on other instance properties, please use {@link getAttributes()}.
+ */
+ protected $attributes = array();
+
+ /**
* Create a new field.
* @param name The internal field name, passed to forms.
* @param title The field label.
@@ -253,21 +259,22 @@ protected function getTabIndexHTML($increment = 0) {
* @return String CSS-classnames
*/
function extraClass() {
- $output = "";
- if(is_array($this->extraClasses)) {
- $output = " " . implode($this->extraClasses, " ");
- }
+ $classes = array();
+
+ $classes[] = $this->Type();
+
+ if($this->extraClasses) $classes = array_merge($classes, array_values($this->extraClasses));
// Allow customization of label and field tag positioning
- if(!$this->Title()) $output .= " nolabel";
+ if(!$this->Title()) $classes[] = "nolabel";
// Allow custom styling of any element in the container based
// on validation errors, e.g. red borders on input tags.
// CSS-Class needs to be different from the one rendered
// through {@link FieldHolder()}
- if($this->Message()) $output .= " holder-" . $this->MessageType();
+ if($this->Message()) $classes[] .= "holder-" . $this->MessageType();
- return $output;
+ return implode(' ', $classes);
}
/**
@@ -289,6 +296,73 @@ function removeExtraClass($class) {
}
/**
+ * Set an HTML attribute on the field element, mostly an <input> tag.
+ *
+ * CAUTION Doesn't work on most fields which are composed of more than one HTML form field:
+ * AjaxUniqueTextField, CheckboxSetField, ComplexTableField, CompositeField, ConfirmedPasswordField, CountryDropdownField,
+ * CreditCardField, CurrencyField, DateField, DatetimeField, FieldGroup, GridField, HtmlEditorField,
+ * ImageField, ImageFormAction, InlineFormAction, ListBoxField, etc.
+ *
+ * @param String
+ * @param String
+ */
+ function setAttribute($name, $value) {
+ $this->attributes[$name] = $value;
+ }
+
+ /**
+ * Get an HTML attribute defined by the field, or added through {@link setAttribute()}.
+ * Caution: Doesn't work on all fields, see {@link setAttribute()}.
+ *
+ * @return String
+ */
+ function getAttribute($name) {
+ $attrs = $this->getAttributes();
+ return @$attrs[$name];
+ }
+
+ /**
+ * @return array
+ */
+ function getAttributes() {
+ $attrs = array(
+ 'type' => 'text',
+ 'name' => $this->getName(),
+ 'value' => $this->Value(),
+ 'class' => $this->extraClass(),
+ 'id' => $this->ID(),
+ 'tabindex' => $this->getTabIndex(),
+ 'disabled' => $this->isDisabled(),
+ );
+ return array_merge($attrs, $this->attributes);
+ }
+
+ /**
+ * @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.
+ * @return String HTML attributes, ready for insertion into an HTML tag
+ */
+ function getAttributesHTML($attrs = null) {
+ $exclude = (is_string($attrs)) ? func_get_args() : null;
+
+ if(!$attrs || is_string($attrs)) $attrs = $this->getAttributes();
+
+ // Remove empty
+ $attrs = array_filter((array)$attrs, create_function('$v', 'return ($v || $v === 0);')); ;
+
+ // Remove excluded
+ if($exclude) $attrs = array_diff_key($attrs, array_flip($exclude));
+
+ // Create markkup
+ $parts = array();
+ foreach($attrs as $name => $value) {
+ $parts[] = ($value === true) ? "{$name}=\"{$name}\"" : "{$name}=\"" . Convert::raw2att($value) . "\"";
+ }
+
+ return implode(' ', $parts);
+ }
+
+ /**
* Returns a version of a title suitable for insertion into an HTML attribute
*/
function attrTitle() {
@@ -555,15 +629,13 @@ function hasClass($class){
/**
* Returns the field type - used by templates.
* The field type is the class name with the word Field dropped off the end, all lowercase.
- * It's handy for assigning HTML classes.
+ * It's handy for assigning HTML classes. Doesn't signify the <input type> attribute,
+ * see {link getAttributes()}.
+ *
* @return string
*/
function Type() {
- if(get_class($this) == 'FormField') {
- return 'hidden';
- } else {
- return strtolower(ereg_replace('Field$', '', $this->class));
- }
+ return strtolower(ereg_replace('Field$', '', $this->class));
}
/**
View
11 forms/GroupedDropdownField.php
@@ -40,14 +40,7 @@
class GroupedDropdownField extends DropdownField {
function Field() {
- // Initialisations
$options = '';
- $classAttr = '';
-
- if($extraClass = trim($this->extraClass())) {
- $classAttr = "class=\"$extraClass\"";
- }
-
foreach($this->getSource() as $value => $title) {
if(is_array($title)) {
$options .= "<optgroup label=\"$value\">";
@@ -62,9 +55,7 @@ function Field() {
}
}
- $id = $this->id();
-
- return "<select $classAttr name=\"$this->name\" id=\"$id\">$options</select>";
+ return $this->createTag('select', $this->getAttributes(), $options);
}
}
View
14 forms/HeaderField.php
@@ -36,4 +36,18 @@ public function getHeadingLevel() {
return $this->headingLevel;
}
+ function getAttributes() {
+ return array_merge(
+ array(
+ 'id' => $this->ID(),
+ 'class' => $this->extraClass()
+ ),
+ $this->attributes
+ );
+ }
+
+ function Type() {
+ return null;
+ }
+
}
View
7 forms/HiddenField.php
@@ -22,6 +22,13 @@ function IsHidden() {
return true;
}
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array('type' => 'hidden')
+ );
+ }
+
static function create($name) {
return new HiddenField($name);
}
View
23 forms/HtmlEditorField.php
@@ -22,8 +22,6 @@ public static function include_js() {
public function __construct($name, $title = null, $rows = 30, $cols = 20, $value = '', $form = null) {
parent::__construct($name, $title, $rows, $cols, $value, $form);
- $this->addExtraClass('htmleditor');
-
self::include_js();
}
@@ -47,18 +45,21 @@ function Field() {
return $this->createTag (
'textarea',
- array (
- 'class' => $this->extraClass(),
- 'rows' => $this->rows,
- 'cols' => $this->cols,
- 'style' => 'width: 97%; height: ' . ($this->rows * 16) . 'px', // prevents horizontal scrollbars
- 'tinymce' => 'true',
- 'id' => $this->id(),
- 'name' => $this->name
- ),
+ $this->getAttributes(),
htmlentities($value->getContent(), ENT_COMPAT, 'UTF-8')
);
}
+
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array(
+ 'tinymce' => 'true',
+ 'style' => 'width: 97%; height: ' . ($this->rows * 16) . 'px', // prevents horizontal scrollbars
+ 'value' => null,
+ )
+ );
+ }
public function saveInto($record) {
if($record->escapeTypeForField($this->name) != 'xml') {
View
38 forms/ListboxField.php
@@ -60,18 +60,12 @@ function __construct($name, $title = '', $source = array(), $value = '', $size =
/**
* Returns a <select> tag containing all the appropriate <option> tags
*/
- function Field() {
- $size = '';
- $multiple = '';
-
- if($this->size) $size = "size=\"$this->size\"";
-
+ function Field($properties = array()) {
if($this->multiple) {
- $multiple = "multiple=\"multiple\"";
$this->name .= '[]';
}
- $options = "";
+ $options = array();
// We have an array of values
if(is_array($this->value)){
@@ -86,18 +80,36 @@ function Field() {
break;
}
}
- $options .= "<option$selected value=\"$value\">$title</option>\n";
+ $options[] = new ArrayData(array(
+ 'Title' => $title,
+ 'Value' => $value,
+ 'Selected' => $selected,
+ ));
}
- }else{
+ } else {
// Listbox was based a singlular value, so treat it like a dropdown.
foreach($this->getSource() as $value => $title) {
$selected = $value == $this->value ? " selected=\"selected\"" : "";
- $options .= "<option$selected value=\"$value\">$title</option>";
+ $options[] = new ArrayData(array(
+ 'Title' => $title,
+ 'Value' => $value,
+ 'Selected' => $selected,
+ ));
}
}
- $id = $this->id();
- return "<select $size $multiple name=\"$this->name\" id=\"$id\">$options</select>";
+ $properties = array_merge($properties, array('Options' => new ArrayList($options)));
+ return $this->customise($properties)->renderWith($this->getTemplate());
+ }
+
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array(
+ 'multiple' => $this->multiple,
+ 'size' => $this->size
+ )
+ );
}
/**
View
4 forms/NumericField.php
@@ -13,6 +13,10 @@ function Field() {
return $html;
}
+
+ function Type() {
+ return 'numeric text';
+ }
function jsValidation() {
$formID = $this->form->FormName();
View
11 forms/PasswordField.php
@@ -24,8 +24,11 @@ function __construct($name, $title = null, $value = "", $maxLength = null) {
}
- function Type() {
- return 'password';
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array('type' => 'password')
+ );
}
/**
@@ -39,6 +42,10 @@ function performReadonlyTransformation() {
$field->setReadonly(true);
return $field;
}
+
+ function Type() {
+ return 'text password';
+ }
}
?>
View
19 forms/ReadonlyField.php
@@ -14,4 +14,23 @@ class ReadonlyField extends FormField {
function performReadonlyTransformation() {
return clone $this;
}
+
+ function Value() {
+ if($this->value) return $this->dontEscape ? $this->value : Convert::raw2xml($this->value);
+ else return '<i>(' . _t('FormField.NONE', 'none') . ')</i>';
+ }
+
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array(
+ 'type' => 'hidden',
+ 'value' => null,
+ )
+ );
+ }
+
+ function Type() {
+ return 'readonly';
+ }
}
View
11 forms/ResetFormAction.php
@@ -7,8 +7,15 @@
*/
class ResetFormAction extends FormAction {
- public function Type() {
- return 'reset';
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
+ array('type' => 'reset')
+ );
+ }
+
+ function Type() {
+ return 'resetformaction';
}
}
View
12 forms/TextField.php
@@ -36,16 +36,14 @@ function getMaxLength() {
return $this->maxLength;
}
- function Field($properties = array()) {
- $properties = array_merge(
- $properties,
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
array(
- 'MaxLength' => ($this->getMaxLength()) ? $this->getMaxLength() : null,
- 'Size' => ($this->getMaxLength()) ? min($this->getMaxLength(), 30) : null
+ 'maxlength' => $this->getMaxLength(),
+ 'size' => ($this->getMaxLength()) ? min($this->getMaxLength(), 30) : null
)
);
-
- return parent::Field($properties);
}
function InternallyLabelledField() {
View
26 forms/TextareaField.php
@@ -42,24 +42,16 @@ function __construct($name, $title = null, $rows = 5, $cols = 20, $value = "", $
parent::__construct($name, $title, $value, $form);
}
- /**
- * Create the <textarea> or <span> HTML tag with the
- * attributes for this instance of TextareaField. This
- * makes use of {@link FormField->createTag()} functionality.
- *
- * @return HTML code for the textarea OR span element
- */
- function Field($properties = array()) {
- $properties = array_merge(
- $properties,
+ function getAttributes() {
+ return array_merge(
+ parent::getAttributes(),
array(
- 'Rows' => $this->rows,
- 'Cols' => $this->cols,
- 'Value' => htmlentities($this->value, ENT_COMPAT, 'UTF-8')
+ 'rows' => $this->rows,
+ 'cols' => $this->cols,
+ 'value' => null,
+ 'type' => null
)
);
-
- return parent::Field($properties);
}
function getTemplate() {
@@ -113,4 +105,8 @@ function setRows($rows) {
function setColumns($cols) {
$this->cols = $cols;
}
+
+ function Value() {
+ return htmlentities($this->value, ENT_COMPAT, 'UTF-8');
+ }
}
View
4 forms/TimeField.php
@@ -72,6 +72,10 @@ function Field() {
return parent::Field();
}
+ function Type() {
+ return 'time text';
+ }
+
/**
* Sets the internal value to ISO date format.
*
View
6 forms/TreeDropdownField.php
@@ -164,12 +164,16 @@ public function Field($properties = array()) {
$properties,
array(
'Title' => $title,
- 'Metadata' => ($metadata) ? Convert::raw2json($metadata) : null
+ 'Metadata' => ($metadata) ? Convert::raw2att(Convert::raw2json($metadata)) : null
)
);
return $this->customise($properties)->renderWith('TreeDropdownField');
}
+
+ function extraClass() {
+ return implode(' ', array(parent::extraClass(), ($this->showSearch ? "searchable" : null)));
+ }
/**
* Get the whole tree of a part of the tree via an AJAX request.
View
4 templates/SelectionGroup.ss
@@ -1,5 +1,5 @@
<% if IsReadonly %>
- <ul class="SelectionGroup$extraClass">
+ <ul class="SelectionGroup<% if extraClass %> $extraClass<% end_if %>">
<% control FieldSet %>
<% if Selected %>
<li$Selected>
@@ -10,5 +10,5 @@
<% end_if %>
<% end_control %>
<% else %>
- <ul class="SelectionGroup$extraClass"><% control FieldSet %><li$Selected>{$RadioButton}{$RadioLabel}{$FieldHolder}</li><% end_control %></ul>
+ <ul class="SelectionGroup<% if extraClass %> $extraClass<% end_if %>"><% control FieldSet %><li$Selected>{$RadioButton}{$RadioLabel}{$FieldHolder}</li><% end_control %></ul>
<% end_if %>
View
2  templates/forms/CheckboxField.ss
@@ -1 +1 @@
-<input id="$ID" class="checkbox$extraClass" type="$Type" value="1" name="$Name"<% if TabIndex %> tabindex="$TabIndex"<% end_if %><% if isDisabled %> disabled<% end_if %><% if Value %> checked<% end_if %>>
+<input $AttributesHTML>
View
2  templates/forms/CheckboxFieldHolder.ss
@@ -1,4 +1,4 @@
-<div id="$Name" class="field $Type<% if extraClass %>$extraClass<% end_if %>">
+<div id="$Name" class="field<% if extraClass %> $extraClass<% end_if %>">
$Field
<label class="right" for="$ID">$Title</label>
<% if Message %><span class="message $MessageType">$messageBlock</span><% end_if %>
View
18 templates/forms/CheckboxSetField.ss
@@ -1,8 +1,12 @@
-<ul id="$ID" class="optionset checkboxset$extraClass">
- <% control Options %>
- <li class="$Class">
- <input id="$ID" class="checkbox" name="$Name" type="checkbox" value="$Value"<% if isChecked %> checked<% end_if %><% if isDisabled %> disabled<% end_if %>>
- <label for="$ID">$Title</label>
- </li>
- <% end_control %>
+<ul id="$ID" class="$extraClass">
+ <% if Options.Count %>
+ <% control Options %>
+ <li class="$Class">
+ <input id="$ID" class="checkbox" name="$Name" type="checkbox" value="$Value"<% if isChecked %> checked="checked"<% end_if %><% if isDisabled %> disabled="disabled"<% end_if %>>
+ <label for="$ID">$Title</label>
+ </li>
+ <% end_control %>
+ <% else %>
+ <li>No options available</li>
+ <% end_if %>
</ul>
View
2  templates/forms/DropdownField.ss
@@ -1,4 +1,4 @@
-<select id="$ID" class="dropdown$extraClass" name="$Name"<% if TabIndex %> tabindex="$TabIndex"<% end_if %><% if isDisabled %> disabled<% end_if %>>
+<select $AttributesHTML>
<% control Options %>
<option value="$Value"<% if Selected %> selected<% end_if %>>$Title</option>
<% end_control %>
View
6 templates/forms/FieldHolder.ss
@@ -1,6 +1,8 @@
-<div id="$Name" class="field $Type<% if extraClass %>$extraClass<% end_if %>">
+<div id="$Name" class="field<% if extraClass %> $extraClass<% end_if %>">
<% if Title %><label class="left" for="$ID">$Title</label><% end_if %>
- <div class="middleColumn">$Field</div>
+ <div class="middleColumn">
+ $Field
+ </div>
<% if RightTitle %><label class="right" for="$ID">$RightTitle</label><% end_if %>
<% if Message %><span class="message $MessageType">$Message</span><% end_if %>
</div>
View
2  templates/forms/FileField.ss
@@ -1,2 +1,2 @@
-<input id="$ID" class="file$extraClass" type="file" name="$Name"<% if TabIndex %> tabindex="$TabIndex"<% end_if %>>
+<input $AttributesHTML>
<input type="hidden" name="MAX_FILE_SIZE" value="$MaxFileSize">
View
4 templates/forms/FormAction.ss
@@ -1,5 +1,5 @@
<% if UseButtonTag %>
- <button id="$ID" class="action$extraClass" type="$Type" title="$Title" value="$Title" name="$Name"<% if TabIndex %> $TabIndex<% end_if %><% if isDisabled %> disabled<% end_if %>></button>
+ <button $AttributesHTML></button>
<% else %>
- <input id="$ID" class="action$extraClass" type="$Type" title="$Title" value="$Title" name="$Name"<% if TabIndex %> $TabIndex<% end_if %><% if isDisabled %> disabled<% end_if %>>
+ <input $AttributesHTML>
<% end_if %>
View
4 templates/forms/FormField.ss
@@ -1,2 +1,2 @@
-<span id="$ID" class="field$extraClass">$NiceValue</span>
-<hidden type="hidden" name="$Name" value="$Value"<% if TabIndex %> tabindex="$TabIndex"<% end_if %>>
+<span id="$ID"<% if extraClass %> class="$extraClass"<% end_if %>>$Value</span>
+<input $AttributesHTML>
View
2  templates/forms/HeaderField.ss
@@ -1 +1 @@
-<h$HeadingLevel id="$ID" class="header$extraClass">$Title</h$HeadingLevel>
+<h$HeadingLevel $AttributesHTML>$Title</h$HeadingLevel>
View
2  templates/forms/HiddenField.ss
@@ -1 +1 @@
-<input class="hidden$extraClass" type="hidden" id="$ID" name="$Name" value="$Value">
+<input $AttributesHTML>
View
2  templates/forms/LabelField.ss
@@ -1 +1 @@
-<label id="$ID" class="label$extraClass">$Title</label>
+<label id="$ID" class="$extraClass">$Title</label>
View
2  templates/forms/OptionsetField.ss
@@ -1,4 +1,4 @@
-<ul id="$ID" class="optionset$extraClass">
+<ul id="$ID" class="$extraClass">
<% control Options %>
<li class="$Class">
<input id="$ID" class="radio" name="$Name" type="radio" value="$Value"<% if isChecked %> checked<% end_if %><% if isDisabled %> disabled<% end_if %>>
View
2  templates/forms/TextField.ss
@@ -1 +1 @@
-<input id="$ID" class="text$extraClass" type="$Type" value="$Value" name="$Name"<% if TabIndex %> tabindex="$TabIndex"<% end_if %><% if MaxLength %> maxlength="$MaxLength"<% end_if %><% if Size %> size="$Size"<% end_if %><% if isDisabled %> disabled<% end_if %> />
+<input $AttributesHTML />
View
2  templates/forms/TextareaField.ss
@@ -1 +1 @@
-<textarea id="$ID" class="textarea$extraClass" name="$Name" rows="$Rows" cols="$Cols"<% if isDisabled %> disabled<% end_if %>>$Value</textarea>
+<textarea $AttributesHTML>$Value</textarea>
View
4 templates/forms/TreeDropdownField.ss
@@ -1,3 +1,3 @@
-<div id="TreeDropdownField_$ID" class="TreeDropdownField single$extraClass<% if ShowSearch %> searchable<% end_if %>" data-url-tree="$Link(tree)" data-tile="$Title"<% if Metadata %> data-metadata="$Metadata"<% end_if %>>
- <input id="$ID" type="hidden" name="$Name" value="$Value">
+<div id="TreeDropdownField_$ID" class="TreeDropdownField single<% if extraClass %> $extraClass<% end_if %><% if ShowSearch %> searchable<% end_if %>" data-url-tree="$Link(tree)" data-title="$Title"<% if Metadata %> data-metadata="$Metadata"<% end_if %>>
+ <input id="$ID" type="hidden" name="$Name" value="$Value" />
</div>
View
44 tests/forms/FormFieldTest.php
@@ -4,6 +4,50 @@
* @subpackage tests
*/
class FormFieldTest extends SapphireTest {
+
+ function testAttributes() {
+ $field = new FormField('MyField');
+ $field->setAttribute('foo', 'bar');
+ $this->assertEquals('bar', $field->getAttribute('foo'));
+ $attrs = $field->getAttributes();
+ $this->assertArrayHasKey('foo', $attrs);
+ $this->assertEquals('bar', $attrs['foo']);
+ }
+
+ function testAttributesHTML() {
+ $field = new FormField('MyField');
+
+ $field->setAttribute('foo', 'bar');
+ $this->assertContains('foo="bar"', $field->getAttributesHTML());
+
+ $field->setAttribute('foo', null);
+ $this->assertNotContains('foo=', $field->getAttributesHTML());
+
+ $field->setAttribute('foo', '');
+ $this->assertNotContains('foo=', $field->getAttributesHTML());
+
+ $field->setAttribute('foo', false);
+ $this->assertNotContains('foo=', $field->getAttributesHTML());
+
+ $field->setAttribute('foo', true);
+ $this->assertContains('foo="foo"', $field->getAttributesHTML());
+
+ $field->setAttribute('foo', 'false');
+ $this->assertContains('foo="false"', $field->getAttributesHTML());
+
+ $field->setAttribute('foo', 'true');
+ $this->assertContains('foo="true"', $field->getAttributesHTML());
+
+ $field->setAttribute('foo', 0);
+ $this->assertContains('foo="0"', $field->getAttributesHTML());
+
+ $field->setAttribute('one', 1);
+ $field->setAttribute('two', 2);
+ $field->setAttribute('three', 3);
+ $this->assertNotContains('one="1"', $field->getAttributesHTML('one', 'two'));
+ $this->assertNotContains('two="2"', $field->getAttributesHTML('one', 'two'));
+ $this->assertContains('three="3"', $field->getAttributesHTML('one', 'two'));
+ }
function testEveryFieldTransformsReadonlyAsClone() {
$fieldClasses = ClassInfo::subclassesFor('FormField');
View
2  tests/model/LabelFieldTest.php
@@ -8,6 +8,6 @@ class LabelFieldTest extends SapphireTest {
function testFieldHasNoNameAttribute() {
$field = new LabelField('MyName', 'MyTitle');
- $this->assertEquals($field->Field(), '<label id="MyName" class="label">MyTitle</label>');
+ $this->assertEquals($field->Field(), '<label id="MyName" class="readonly">MyTitle</label>');
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.