mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
ENHANCEMENT Allowing custom attributes in (most) FormField implementations, which allows for HTML5 data attributes
This commit is contained in:
parent
c77f4e8421
commit
b5421d9598
@ -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,
|
||||
|
@ -22,8 +22,6 @@ class CheckboxField extends FormField {
|
||||
return ($this->value) ? 1 : 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a restricted field holder used within things like FieldGroups
|
||||
*/
|
||||
@ -35,6 +33,18 @@ class CheckboxField extends FormField {
|
||||
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
|
||||
*/
|
||||
|
@ -98,12 +98,9 @@ class CheckboxSetField extends OptionsetField {
|
||||
}
|
||||
|
||||
$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 @@ class CheckboxSetField extends OptionsetField {
|
||||
$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),
|
||||
@ -284,6 +281,10 @@ class CheckboxSetField extends OptionsetField {
|
||||
return $field;
|
||||
}
|
||||
|
||||
function Type() {
|
||||
return 'optionset checkboxset';
|
||||
}
|
||||
|
||||
function ExtraOptions() {
|
||||
return FormField::ExtraOptions();
|
||||
}
|
||||
|
@ -83,15 +83,25 @@ class CompositeField extends FormField {
|
||||
$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 @@ class CompositeField extends FormField {
|
||||
$content .= "\n" . $subfield->FieldHolder() . "\n";
|
||||
}
|
||||
}
|
||||
$content .= "</div>\n";
|
||||
|
||||
return $content;
|
||||
$this->createTag('div', $this->getAttributes(), $content);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,13 +23,13 @@ class CountryDropdownField extends DropdownField {
|
||||
$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();
|
||||
}
|
||||
|
||||
}
|
@ -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) . " /> - " .
|
||||
|
@ -27,6 +27,11 @@ class CurrencyField extends TextField {
|
||||
return 0.00;
|
||||
}
|
||||
}
|
||||
|
||||
function Type() {
|
||||
return 'currency text';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new class for this field
|
||||
*/
|
||||
|
@ -19,6 +19,15 @@ class DatalessField extends FormField {
|
||||
*/
|
||||
function hasData() { return false; }
|
||||
|
||||
function getAttributes() {
|
||||
return array_merge(
|
||||
parent::getAttributes(),
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field's representation in the form.
|
||||
* For dataless fields, this defaults to $Field.
|
||||
@ -58,4 +67,8 @@ class DatalessField extends FormField {
|
||||
return $this->allowHTML;
|
||||
}
|
||||
|
||||
function Type() {
|
||||
return 'readonly';
|
||||
}
|
||||
|
||||
}
|
@ -175,6 +175,10 @@ class DateField extends TextField {
|
||||
return $html;
|
||||
}
|
||||
|
||||
function Type() {
|
||||
return 'date text';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the internal value to ISO date format.
|
||||
*
|
||||
|
@ -162,6 +162,13 @@ class DropdownField extends FormField {
|
||||
return $this->customise($properties)->renderWith($this->getTemplate());
|
||||
}
|
||||
|
||||
function getAttributes() {
|
||||
return array_merge(
|
||||
parent::getAttributes(),
|
||||
array('type' => null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
@ -230,12 +237,6 @@ class DropdownField extends FormField {
|
||||
return $field;
|
||||
}
|
||||
|
||||
function extraClass() {
|
||||
$ret = parent::extraClass();
|
||||
if($this->extraClass) $ret .= " $this->extraClass";
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set form being disabled
|
||||
*/
|
||||
|
@ -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.');
|
||||
@ -40,14 +44,6 @@ if(typeof fromAnOnBlur != 'undefined'){
|
||||
JS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field type - used by templates.
|
||||
* @return string
|
||||
*/
|
||||
function Type() {
|
||||
return 'text';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates for RFC 2822 compliant email adresses.
|
||||
*
|
||||
|
@ -117,6 +117,13 @@ class FileField extends FormField {
|
||||
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));
|
||||
|
@ -91,7 +91,22 @@ class FormAction extends FormField {
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,6 +89,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.
|
||||
@ -253,21 +259,22 @@ class FormField extends RequestHandler {
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -288,6 +295,73 @@ class FormField extends RequestHandler {
|
||||
if(isset($this->extraClasses) && array_key_exists($class, $this->extraClasses)) unset($this->extraClasses[$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
|
||||
*/
|
||||
@ -555,15 +629,13 @@ class FormField extends RequestHandler {
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 @@ class GroupedDropdownField extends DropdownField {
|
||||
}
|
||||
}
|
||||
|
||||
$id = $this->id();
|
||||
|
||||
return "<select $classAttr name=\"$this->name\" id=\"$id\">$options</select>";
|
||||
return $this->createTag('select', $this->getAttributes(), $options);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,4 +36,18 @@ class HeaderField extends DatalessField {
|
||||
return $this->headingLevel;
|
||||
}
|
||||
|
||||
function getAttributes() {
|
||||
return array_merge(
|
||||
array(
|
||||
'id' => $this->ID(),
|
||||
'class' => $this->extraClass()
|
||||
),
|
||||
$this->attributes
|
||||
);
|
||||
}
|
||||
|
||||
function Type() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -22,6 +22,13 @@ class HiddenField extends FormField {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getAttributes() {
|
||||
return array_merge(
|
||||
parent::getAttributes(),
|
||||
array('type' => 'hidden')
|
||||
);
|
||||
}
|
||||
|
||||
static function create($name) {
|
||||
return new HiddenField($name);
|
||||
}
|
||||
|
@ -22,8 +22,6 @@ class HtmlEditorField extends TextareaField {
|
||||
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,19 +45,22 @@ class HtmlEditorField extends TextareaField {
|
||||
|
||||
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') {
|
||||
throw new Exception (
|
||||
|
@ -60,18 +60,12 @@ class ListboxField extends DropdownField {
|
||||
/**
|
||||
* 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 @@ class ListboxField extends DropdownField {
|
||||
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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,6 +14,10 @@ class NumericField extends TextField{
|
||||
return $html;
|
||||
}
|
||||
|
||||
function Type() {
|
||||
return 'numeric text';
|
||||
}
|
||||
|
||||
function jsValidation() {
|
||||
$formID = $this->form->FormName();
|
||||
$error = _t('NumericField.VALIDATIONJS', 'is not a number, only numbers can be accepted for this field');
|
||||
|
@ -24,8 +24,11 @@ class PasswordField extends TextField {
|
||||
}
|
||||
|
||||
|
||||
function Type() {
|
||||
return 'password';
|
||||
function getAttributes() {
|
||||
return array_merge(
|
||||
parent::getAttributes(),
|
||||
array('type' => 'password')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,6 +42,10 @@ class PasswordField extends TextField {
|
||||
$field->setReadonly(true);
|
||||
return $field;
|
||||
}
|
||||
|
||||
function Type() {
|
||||
return 'text password';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -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';
|
||||
}
|
||||
}
|
@ -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';
|
||||
}
|
||||
|
||||
}
|
@ -36,16 +36,14 @@ class TextField extends FormField {
|
||||
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() {
|
||||
|
@ -42,24 +42,16 @@ class TextareaField extends FormField {
|
||||
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 @@ class TextareaField extends FormField {
|
||||
function setColumns($cols) {
|
||||
$this->cols = $cols;
|
||||
}
|
||||
|
||||
function Value() {
|
||||
return htmlentities($this->value, ENT_COMPAT, 'UTF-8');
|
||||
}
|
||||
}
|
@ -72,6 +72,10 @@ class TimeField extends TextField {
|
||||
return parent::Field();
|
||||
}
|
||||
|
||||
function Type() {
|
||||
return 'time text';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the internal value to ISO date format.
|
||||
*
|
||||
|
@ -164,13 +164,17 @@ class TreeDropdownField extends FormField {
|
||||
$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.
|
||||
*
|
||||
|
@ -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 %>
|
@ -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>
|
@ -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 %>
|
||||
|
@ -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>
|
||||
|
@ -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 %>
|
||||
|
@ -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>
|
@ -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">
|
||||
|
@ -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 %>
|
@ -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>
|
||||
|
@ -1 +1 @@
|
||||
<h$HeadingLevel id="$ID" class="header$extraClass">$Title</h$HeadingLevel>
|
||||
<h$HeadingLevel $AttributesHTML>$Title</h$HeadingLevel>
|
@ -1 +1 @@
|
||||
<input class="hidden$extraClass" type="hidden" id="$ID" name="$Name" value="$Value">
|
||||
<input $AttributesHTML>
|
||||
|
@ -1 +1 @@
|
||||
<label id="$ID" class="label$extraClass">$Title</label>
|
||||
<label id="$ID" class="$extraClass">$Title</label>
|
@ -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 %>>
|
||||
|
@ -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 />
|
@ -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>
|
@ -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>
|
@ -5,6 +5,50 @@
|
||||
*/
|
||||
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');
|
||||
foreach($fieldClasses as $fieldClass) {
|
||||
|
@ -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>');
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user