API CHANGE FormField::Field() and FormField::FieldHolder() now render into templates on each FormField instead of creating HTML from PHP

This commit is contained in:
Sean Harvey 2011-03-23 17:12:25 +13:00 committed by Ingo Schommer
parent b3c08dba12
commit 9e548f501e
40 changed files with 346 additions and 571 deletions

View File

@ -6,8 +6,6 @@
*/ */
class CheckboxField extends FormField { class CheckboxField extends FormField {
protected $disabled;
function setValue($value) { function setValue($value) {
$this->value = ($value) ? 1 : 0; $this->value = ($value) ? 1 : 0;
} }
@ -20,49 +18,13 @@ class CheckboxField extends FormField {
return ($this->value) ? 1 : 0; return ($this->value) ? 1 : 0;
} }
function Field() { function Field($properties = array()) {
$attributes = array( return $this->customise($properties)->renderWith('CheckboxField');
'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);
} }
/**
* 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() { function FieldHolder() {
if($this->labelLeft) { $this->setFieldHolderTemplate(($this->fieldHolderTemplate) ? $this->fieldHolderTemplate : 'CheckboxFieldHolder');
return parent::FieldHolder(); return parent::FieldHolder();
} else {
extract($this->getXMLValues(array( 'Name', 'Field', 'Title', 'Message', 'MessageType' )),
EXTR_SKIP);
$messageBlock = isset($Message) ? "<span class=\"message $MessageType\">$Message</span>" : '';
$Type = $this->XML_val('Type');
$extraClass = $this->XML_val('extraClass');
return <<<HTML
<div id="$Name" class="field $Type $extraClass">
$Field
<label class="right" for="{$this->id()}">$Title</label>
$messageBlock
</div>
HTML;
}
}
function useLabelLeft( $labelLeft = true ) {
$this->labelLeft = $labelLeft;
} }
/** /**
@ -79,7 +41,6 @@ HTML;
/** /**
* Returns a readonly version of this field * Returns a readonly version of this field
*/ */
function performReadonlyTransformation() { function performReadonlyTransformation() {
$field = new CheckboxField_Readonly($this->name, $this->title, $this->value ? _t('CheckboxField.YES', 'Yes') : _t('CheckboxField.NO', 'No')); $field = new CheckboxField_Readonly($this->name, $this->title, $this->value ? _t('CheckboxField.YES', 'Yes') : _t('CheckboxField.NO', 'No'));
$field->setForm($this->form); $field->setForm($this->form);
@ -91,6 +52,7 @@ HTML;
$clone->setDisabled(true); $clone->setDisabled(true);
return $clone; return $clone;
} }
} }
/** /**
@ -99,6 +61,7 @@ HTML;
* @subpackage fields-basic * @subpackage fields-basic
*/ */
class CheckboxField_Readonly extends ReadonlyField { class CheckboxField_Readonly extends ReadonlyField {
function performReadonlyTransformation() { function performReadonlyTransformation() {
return clone $this; return clone $this;
} }
@ -106,32 +69,5 @@ class CheckboxField_Readonly extends ReadonlyField {
function setValue($val) { function setValue($val) {
$this->value = (int)($val) ? _t('CheckboxField.YES', 'Yes') : _t('CheckboxField.NO', 'No'); $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);
}
}
?>

View File

@ -29,9 +29,6 @@
* array. Is it also appropriate to accept so many different * array. Is it also appropriate to accept so many different
* types of data when just using an array would be appropriate? * 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 * @package forms
* @subpackage fields-basic * @subpackage fields-basic
*/ */
@ -47,14 +44,13 @@ class CheckboxSetField extends OptionsetField {
/** /**
* @todo Explain different source data that can be used with this field, * @todo Explain different source data that can be used with this field,
* e.g. SQLMap, ArrayList or an array. * 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'); Requirements::css(SAPPHIRE_DIR . '/css/CheckboxSetField.css');
$source = $this->source; $source = $this->source;
$values = $this->value; $values = $this->value;
$items = array();
// Get values from the join, if available // Get values from the join, if available
if(is_object($this->form)) { if(is_object($this->form)) {
@ -109,30 +105,35 @@ class CheckboxSetField extends OptionsetField {
$options = "<li>No options available</li>"; $options = "<li>No options available</li>";
} }
if($source) foreach($source as $index => $item) { if($source) {
if($item instanceof DataObject) { foreach($source as $value => $item) {
$key = $item->ID; if($item instanceof DataObject) {
$value = $item->Title; $value = $item->ID;
} else { $title = $item->Title;
$key = $index; } else {
$value = $item; $title = $item;
}
$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)
));
} }
$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"' : '';
}
$disabled = ($this->disabled || in_array($key, $this->disabledItems)) ? $disabled = ' disabled="disabled"' : '';
$options .= "<li class=\"$extraClass\"><input id=\"$itemID\" name=\"$this->name[$key]\" type=\"checkbox\" value=\"$key\"$checked $disabled class=\"checkbox\" /> <label for=\"$itemID\">$value</label></li>\n";
} }
return "<ul id=\"{$this->id()}\" class=\"optionset checkboxsetfield{$this->extraClass()}\">\n$options</ul>\n"; $properties = array_merge($properties, array('Options' => new ArrayList($options)));
return $this->customise($properties)->renderWith('CheckboxSetField');
} }
function setDisabled($val) { function setDisabled($val) {
@ -288,4 +289,3 @@ class CheckboxSetField extends OptionsetField {
} }
} }
?>

View File

@ -57,5 +57,5 @@ class DatalessField extends FormField {
function getAllowHTML() { function getAllowHTML() {
return $this->allowHTML; return $this->allowHTML;
} }
} }
?>

View File

@ -130,67 +130,45 @@ class DropdownField extends FormField {
parent::__construct($name, ($title===null) ? $name : $title, $value, $form); parent::__construct($name, ($title===null) ? $name : $title, $value, $form);
} }
/** function Field($properties = array()) {
* Returns a <select> tag containing all the appropriate <option> tags.
* Makes use of {@link FormField->createTag()} to generate the <select>
* tag and option elements inside is as the content of the <select>.
*
* @return string HTML tag for this dropdown field
*/
function Field() {
$options = '';
$source = $this->getSource(); $source = $this->getSource();
$options = array();
if($source) { if($source) {
// For SQLMap sources, the empty string needs to be added specially // SQLMap needs this to add an empty value to the options
if(is_object($source) && $this->emptyString) { if(is_object($source) && $this->emptyString) {
$options .= $this->createTag('option', array('value' => ''), $this->emptyString); $options[] = new ArrayData(array(
'Value' => $this->emptyString,
'Title' => '',
));
} }
foreach($source as $value => $title) { foreach($source as $value => $title) {
$selected = false;
// Blank value of field and source (e.g. "" => "(Any)")
if($value === '' && ($this->value === '' || $this->value === null)) { if($value === '' && ($this->value === '' || $this->value === null)) {
$selected = 'selected'; $selected = true;
} else { } else {
// Normal value from the source // check against value, fallback to a type check comparison when !value
if($value) { $selected = ($value) ? $value == $this->value : $value === $this->value;
$selected = ($value == $this->value) ? 'selected' : null; $this->isSelected = $selected;
} else {
// Do a type check comparison, we might have an array key of 0
$selected = ($value === $this->value) ? 'selected' : null;
}
$this->isSelected = ($selected) ? true : false;
} }
$options .= $this->createTag( $options[] = new ArrayData(array(
'option', 'Title' => $title,
array( 'Value' => $value,
'selected' => $selected, 'Selected' => $selected,
'value' => $value ));
),
Convert::raw2xml($title)
);
} }
} }
$attributes = array( $properties = array_merge($properties, array('Options' => new ArrayList($options)));
'class' => ($this->extraClass() ? $this->extraClass() : ''),
'id' => $this->id(),
'name' => $this->name,
'tabindex' => $this->getTabIndex()
);
if($this->disabled) $attributes['disabled'] = 'disabled'; return $this->customise($properties)->renderWith('DropdownField');
return $this->createTag('select', $attributes, $options);
} }
/** /**
* @return boolean * @return boolean
*/ */
function isSelected(){ function isSelected() {
return $this->isSelected; return $this->isSelected;
} }
@ -255,7 +233,7 @@ class DropdownField extends FormField {
return $field; return $field;
} }
function extraClass(){ function extraClass() {
$ret = parent::extraClass(); $ret = parent::extraClass();
if($this->extraClass) $ret .= " $this->extraClass"; if($this->extraClass) $ret .= " $this->extraClass";
return $ret; return $ret;

View File

@ -40,6 +40,18 @@ if(typeof fromAnOnBlur != 'undefined'){
JS; JS;
} }
public function Field($properties = array()) {
return $this->customise($properties)->renderWith('TextField');
}
/**
* Returns the field type - used by templates.
* @return string
*/
function Type() {
return 'text';
}
/** /**
* Validates for RFC 2822 compliant email adresses. * Validates for RFC 2822 compliant email adresses.
* *
@ -69,5 +81,5 @@ JS;
return true; return true;
} }
} }
} }
?>

View File

@ -110,25 +110,9 @@ class FileField extends FormField {
parent::__construct($name, $title, $value, $form, $rightTitle); parent::__construct($name, $title, $value, $form, $rightTitle);
} }
public function Field() { public function Field($properties = array()) {
return $this->createTag( $properties = array_merge($properties, array('MaxFileSize' => $this->getValidator()->getAllowedMaxFileSize()));
'input', return $this->customise($properties)->renderWith('FileField');
array(
"type" => "file",
"name" => $this->name,
"id" => $this->id(),
"tabindex" => $this->getTabIndex()
)
) .
$this->createTag(
'input',
array(
"type" => "hidden",
"name" => "MAX_FILE_SIZE",
"value" => $this->getValidator()->getAllowedMaxFileSize(),
"tabindex" => $this->getTabIndex()
)
);
} }
public function saveInto(DataObject $record) { public function saveInto(DataObject $record) {

View File

@ -89,13 +89,11 @@ class FileIFrameField extends FileField {
'value' => $this->attrValue() 'value' => $this->attrValue()
) )
); );
} else {
return sprintf(_t (
'FileIFrameField.ATTACHONCESAVED', '%ss can be attached once you have saved the record for the first time.'
), $this->FileTypeName());
} }
$this->setValue(sprintf(_t (
'FileIFrameField.ATTACHONCESAVED', '%ss can be attached once you have saved the record for the first time.'
), $this->FileTypeName()));
return FormField::field();
} }
/** /**
@ -119,7 +117,7 @@ class FileIFrameField extends FileField {
Requirements::css('sapphire/css/FileIFrameField.css'); Requirements::css('sapphire/css/FileIFrameField.css');
return $this->renderWith($this->template); return $this->renderWith('FileIframeField_iframe');
} }
/** /**

View File

@ -15,10 +15,6 @@
* ) * )
* </code> * </code>
* *
* <b>Labels</b>
*
* By default, FormAction will use the title as the label for the left margin. This can look redundant on the form. If you'd rather have just the button alone with as pictured above try using {@link FormAction_WithoutLabel} instead.
*
* @package forms * @package forms
* @subpackage actions * @subpackage actions
*/ */
@ -53,22 +49,19 @@ class FormAction extends FormField {
* @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
* @param extraData A piece of extra data that can be extracted with $this->extraData. Useful for * @param extraData A piece of extra data that can be extracted with $this->extraData. Useful for
* calling $form->buttonClicked()->extraData() * calling $form->buttonClicked()->extraData()
* @param extraClass A CSS class to apply to the button in addition to 'action'
*/ */
function __construct($action, $title = "", $form = null, $extraData = null, $extraClass = '') { function __construct($action, $title = "", $form = null, $extraData = null) {
$this->extraData = $extraData; $this->extraData = $extraData;
$this->addExtraClass($extraClass);
$this->action = "action_$action"; $this->action = "action_$action";
parent::__construct($this->action, $title, null, $form); parent::__construct($this->action, $title, null, $form);
} }
static function create($action, $title = "", $extraData = null, $extraClass = null) { static function create($action, $title = "", $extraData = null) {
return new FormAction($action, $title, null, $extraData, $extraClass); return new FormAction($action, $title, null, $extraData);
} }
function actionName() { function actionName() {
return substr($this->name,7); return substr($this->name, 7);
} }
/** /**
@ -83,44 +76,20 @@ class FormAction extends FormField {
return $this->extraData; return $this->extraData;
} }
/** function Field($properties = array()) {
* Create a submit input, or button tag $properties = array_merge(
* using {@link FormField->createTag()} functionality. $properties,
* array(
* @return HTML code for the input OR button element 'Name' => $this->action,
*/ 'Title' => ($this->description) ? $this->description : $this->Title(),
function Field() { 'UseButtonTag' => $this->useButtonTag
if($this->useButtonTag) { )
$attributes = array( );
'class' => 'action' . ($this->extraClass() ? $this->extraClass() : ''), return $this->customise($properties)->renderWith('FormAction');
'id' => $this->id(), }
'type' => 'submit',
'name' => $this->action,
'tabindex' => $this->getTabIndex()
);
if($this->isReadonly()) {
$attributes['disabled'] = 'disabled';
$attributes['class'] = $attributes['class'] . ' disabled';
}
return $this->createTag('button', $attributes, $this->buttonContent ? $this->buttonContent : $this->Title()); public function Type() {
} else { return ($this->useButtonTag) ? 'button' : 'submit';
$attributes = array(
'class' => 'action' . ($this->extraClass() ? $this->extraClass() : ''),
'id' => $this->id(),
'type' => 'submit',
'name' => $this->action,
'value' => $this->Title(),
'tabindex' => $this->getTabIndex()
);
if($this->isReadonly()) {
$attributes['disabled'] = 'disabled';
$attributes['class'] = $attributes['class'] . ' disabled';
}
$attributes['title'] = ($this->description) ? $this->description : $this->Title();
return $this->createTag('input', $attributes);
}
} }
/** /**
@ -133,18 +102,4 @@ class FormAction extends FormField {
return $clone; return $clone;
} }
function readonlyField() {
return $this;
}
} }
/**
* @package forms
* @subpackage actions
*/
class FormAction_WithoutLabel extends FormAction {
function Title(){
return null;
}
}
?>

View File

@ -18,7 +18,12 @@
* @subpackage core * @subpackage core
*/ */
class FormField extends RequestHandler { class FormField extends RequestHandler {
/**
* @var Form
*/
protected $form; protected $form;
protected $name, $title, $value ,$message, $messageType, $extraClass; protected $name, $title, $value ,$message, $messageType, $extraClass;
/** /**
@ -78,6 +83,12 @@ class FormField extends RequestHandler {
*/ */
protected $customValidationMessage = ""; protected $customValidationMessage = "";
/**
* Template name to render this FormField field holder into.
* @var string
*/
protected $fieldHolderTemplate;
/** /**
* Create a new field. * Create a new field.
* @param name The internal field name, passed to forms. * @param name The internal field name, passed to forms.
@ -108,7 +119,7 @@ class FormField extends RequestHandler {
* The ID is generated as FormName_FieldName. All Field functions should ensure * The ID is generated as FormName_FieldName. All Field functions should ensure
* that this ID is included in the field. * that this ID is included in the field.
*/ */
function id() { function ID() {
$name = ereg_replace('(^-)|(-$)','',ereg_replace('[^A-Za-z0-9_-]+','-',$this->name)); $name = ereg_replace('(^-)|(-$)','',ereg_replace('[^A-Za-z0-9_-]+','-',$this->name));
if($this->form) return $this->form->FormName() . '_' . $name; if($this->form) return $this->form->FormName() . '_' . $name;
else return $name; else return $name;
@ -131,10 +142,6 @@ class FormField extends RequestHandler {
return $this->getName(); return $this->getName();
} }
function attrName() {
return $this->name;
}
/** /**
* Returns the field message, used by form validation. * Returns the field message, used by form validation.
* Use {@link setError()} to set this property. * Use {@link setError()} to set this property.
@ -220,7 +227,6 @@ class FormField extends RequestHandler {
/** /**
* Get tabindex (if previously set) * Get tabindex (if previously set)
*
* @return int * @return int
*/ */
public function getTabIndex() { public function getTabIndex() {
@ -328,6 +334,14 @@ class FormField extends RequestHandler {
return $this->form; return $this->form;
} }
public function getFieldHolderTemplate() {
return $this->fieldHolderTemplate;
}
public function setFieldHolderTemplate($template) {
$this->fieldHolderTemplate = $template;
}
/** /**
* Return TRUE if security token protection is enabled on the parent {@link Form}. * Return TRUE if security token protection is enabled on the parent {@link Form}.
* *
@ -343,7 +357,7 @@ class FormField extends RequestHandler {
* Sets the error message to be displayed on the form field * Sets the error message to be displayed on the form field
* Set by php validation of the form * Set by php validation of the form
*/ */
function setError($message,$messageType){ function setError($message, $messageType) {
$this->message = $message; $this->message = $message;
$this->messageType = $messageType; $this->messageType = $messageType;
} }
@ -394,67 +408,33 @@ class FormField extends RequestHandler {
* representation of the field on the form, whereas Field will give you the core editing widget, * representation of the field on the form, whereas Field will give you the core editing widget,
* such as an input tag. * such as an input tag.
* *
* Our base FormField class just returns a span containing the value. This should be overridden! * @param array $properties key value pairs of template variables
* @return string
*/ */
function Field() { function Field($properties = array()) {
if($this->value) $value = $this->dontEscape ? $this->value : Convert::raw2xml($this->value); return $this->customise($properties)->renderWith('FormField');
else $value = '<i>(' . _t('FormField.NONE', 'none') . ')</i>';
$attributes = array(
'id' => $this->id(),
'class' => 'readonly' . ($this->extraClass() ? $this->extraClass() : '')
);
$hiddenAttributes = array(
'type' => 'hidden',
'name' => $this->name,
'value' => $this->value,
'tabindex' => $this->getTabIndex()
);
$containerSpan = $this->createTag('span', $attributes, $value);
$hiddenInput = $this->createTag('input', $hiddenAttributes);
return $containerSpan . "\n" . $hiddenInput;
}
/**
* Returns a "Field Holder" for this field - used by templates.
* Forms are constructed from by concatenating a number of these field holders. The default
* field holder is a label and form field inside a paragraph tag.
*
* Composite fields can override FieldHolder to create whatever visual effects you like. It's
* a good idea to put the actual HTML for field holders into templates. The default field holder
* is the DefaultFieldHolder template. This lets you override the HTML for specific sites, if it's
* necessary.
*
* @todo Add "validationError" if needed.
*/
function FieldHolder() {
$Title = $this->XML_val('Title');
$Message = $this->XML_val('Message');
$MessageType = $this->XML_val('MessageType');
$RightTitle = $this->XML_val('RightTitle');
$Type = $this->XML_val('Type');
$extraClass = $this->XML_val('extraClass');
$Name = $this->XML_val('Name');
$Field = $this->XML_val('Field');
// Only of the the following titles should apply
$titleBlock = (!empty($Title)) ? "<label class=\"left\" for=\"{$this->id()}\">$Title</label>" : "";
$rightTitleBlock = (!empty($RightTitle)) ? "<label class=\"right\" for=\"{$this->id()}\">$RightTitle</label>" : "";
// $MessageType is also used in {@link extraClass()} with a "holder-" prefix
$messageBlock = (!empty($Message)) ? "<span class=\"message $MessageType\">$Message</span>" : "";
return <<<HTML
<div id="$Name" class="field $Type $extraClass">$titleBlock<div class="middleColumn">$Field</div>$rightTitleBlock$messageBlock</div>
HTML;
} }
/** /**
* Returns a restricted field holder used within things like FieldGroups. * Returns a "field holder" for this field - used by templates.
*
* Forms are constructed by concatenating a number of these field holders.
* The default field holder is a label and a form field inside a div.
* @see FieldHolder.ss
*
* @param array $properties key value pairs of template variables
* @return string
*/ */
function SmallFieldHolder() { function FieldHolder($properties = array()) {
return $this->customise($properties)->renderWith(
($this->fieldHolderTemplate) ? $this->fieldHolderTemplate : 'FieldHolder'
);
}
/**
* Returns a restricted field holder used within things like FieldGroups.
*/
function SmallFieldHolder() {
$result = ''; $result = '';
// set label // set label
if($title = $this->RightTitle()){ if($title = $this->RightTitle()){
@ -468,14 +448,15 @@ HTML;
$result .= $this->Field(); $result .= $this->Field();
return $result; return $result;
} }
/** /**
* Returns true if this field is a composite field. * Returns true if this field is a composite field.
* To create composite field types, you should subclass {@link CompositeField}. * To create composite field types, you should subclass {@link CompositeField}.
*/ */
function isComposite() { return false; } function isComposite() {
return false;
}
/** /**
* Returns true if this field has its own data. * Returns true if this field has its own data.
@ -485,7 +466,9 @@ HTML;
* *
* @see FieldList::collateDataFields() * @see FieldList::collateDataFields()
*/ */
function hasData() { return true; } function hasData() {
return true;
}
/** /**
* @return boolean * @return boolean
@ -559,13 +542,18 @@ HTML;
* Returns the field type - used by templates. * Returns the field type - used by templates.
* The field type is the class name with the word Field dropped off the end, all lowercase. * 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.
* @return string
*/ */
function Type() {return strtolower(ereg_replace('Field$','',$this->class)); } function Type() {
return strtolower(ereg_replace('Field$', '', $this->class));
}
/** /**
* Construct and return HTML tag. * Construct and return HTML tag.
* *
* @return string HTML tag * @deprecated 3.0 Please define your own FormField template using {@link setFieldTemplate()}
* and/or {@link renderFieldTemplate()}
*
* @todo Transform to static helper method. * @todo Transform to static helper method.
*/ */
function createTag($tag, $attributes, $content = null) { function createTag($tag, $attributes, $content = null) {
@ -671,4 +659,3 @@ HTML;
} }
} }
?>

View File

@ -30,16 +30,12 @@ class HeaderField extends DatalessField {
parent::__construct($name, $title, null, $form); parent::__construct($name, $title, null, $form);
} }
function Field() { public function getHeadingLevel() {
$attributes = array( return $this->headingLevel;
'class' => $this->extraClass(),
'id' => $this->id()
);
return $this->createTag(
"h{$this->headingLevel}",
$attributes,
($this->getAllowHTML() ? $this->title : Convert::raw2xml($this->title))
);
} }
function Field($properties = array()) {
return $this->customise($properties)->renderWith('HeaderField');
}
} }
?>

View File

@ -5,17 +5,15 @@
* @subpackage fields-dataless * @subpackage fields-dataless
*/ */
class HiddenField extends FormField { class HiddenField extends FormField {
/**
* Returns an hidden input field, class="hidden" and type="hidden" function Field($properties = array()) {
*/ return $this->customise($properties)->renderWith('HiddenField');
function Field() {
$extraClass = $this->extraClass();
//if($this->name=="ShowChooseOwn")Debug::show($this->value);
return "<input class=\"hidden$extraClass\" type=\"hidden\" id=\"" . $this->id() . "\" name=\"{$this->name}\" value=\"" . $this->attrValue() . "\" />";
} }
function FieldHolder() { function FieldHolder() {
return $this->Field(); return $this->Field();
} }
function performReadonlyTransformation() { function performReadonlyTransformation() {
$clone = clone $this; $clone = clone $this;
$clone->setReadonly(true); $clone->setReadonly(true);

View File

@ -30,16 +30,8 @@ class LabelField extends DatalessField {
/** /**
* Returns a label containing the title, and an HTML class if given. * Returns a label containing the title, and an HTML class if given.
*/ */
function Field() { function Field($properties = array()) {
$attributes = array( return $this->customise($properties)->renderWith('LabelField');
'class' => $this->extraClass(),
'id' => $this->id()
);
return $this->createTag(
'label',
$attributes,
($this->getAllowHTML() ? $this->title : Convert::raw2xml($this->title))
);
} }
} }
?>

View File

@ -63,4 +63,5 @@ class LiteralField extends DatalessField {
$clone->setReadonly(true); $clone->setReadonly(true);
return $clone; return $clone;
} }
} }

View File

@ -82,6 +82,7 @@ class NullableField extends FormField {
$nullableCheckbox = new CheckboxField($this->getIsNullId()); $nullableCheckbox = new CheckboxField($this->getIsNullId());
} }
$nullableCheckbox->setValue(is_null($this->dataValue())); $nullableCheckbox->setValue(is_null($this->dataValue()));
return $this->valueField->Field() . ' ' . $nullableCheckbox->Field() . '&nbsp;<span>' . $this->getIsNullLabel().'</span>'; return $this->valueField->Field() . ' ' . $nullableCheckbox->Field() . '&nbsp;<span>' . $this->getIsNullLabel().'</span>';
} }

View File

@ -61,58 +61,38 @@ class OptionsetField extends DropdownField {
*/ */
protected $disabledItems = array(); protected $disabledItems = array();
/** function Field($properties = 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);
}
/**
* 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(); $source = $this->getSource();
foreach($source as $key => $value) { $odd = 0;
$itemID = $this->id() . "_" . ereg_replace('[^a-zA-Z0-9]+','',$key); $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);
if($key == $this->value/* || $useValue */) { $options[] = new ArrayData(array(
$useValue = false; 'ID' => $itemID,
$checked = " checked=\"checked\""; 'Class' => $extraClass,
} else { 'Name' => $this->name,
$checked=""; 'Value' => $value,
'Title' => $title,
'isChecked' => $value == $this->value,
'isDisabled' => $this->disabled || in_array($value, $this->disabledItems),
));
} }
$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 .= "<li class=\"".$extraClass."\"><input id=\"$itemID\" name=\"$this->name\" type=\"radio\" value=\"$key\"$checked $disabled class=\"radio\" /> <label for=\"$itemID\">$value</label></li>\n";
} }
$id = $this->id();
return "<ul id=\"$id\" class=\"optionset {$this->extraClass()}\">\n$options</ul>\n";
}
protected $disabled = false; $properties = array_merge($properties, array('Options' => new ArrayList($options)));
function setDisabled($val) {
$this->disabled = $val; return $this->customise($properties)->renderWith('OptionsetField');
} }
function performReadonlyTransformation() { function performReadonlyTransformation() {
// Source and values are DataObject sets. // Source and values are DataObject sets.
$items = $this->getSource(); $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->setForm($this->form);
$field->setReadonly(true); $field->setReadonly(true);
return $field; return $field;
@ -138,5 +118,5 @@ class OptionsetField extends DropdownField {
function ExtraOptions() { function ExtraOptions() {
return new ArrayList(); return new ArrayList();
} }
} }
?>

View File

@ -15,4 +15,3 @@ class ReadonlyField extends FormField {
return clone $this; return clone $this;
} }
} }
?>

View File

@ -7,27 +7,8 @@
*/ */
class ResetFormAction extends FormAction { class ResetFormAction extends FormAction {
function Field() { public function Type() {
$attributes = array( return 'reset';
'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);
} }
} }
?>

View File

@ -14,7 +14,7 @@ class TextField extends FormField {
/** /**
* Returns an input field, class="text" and type="text" with an optional maxlength * 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; $this->maxLength = $maxLength;
parent::__construct($name, $title, $value, $form); parent::__construct($name, $title, $value, $form);
@ -34,21 +34,16 @@ class TextField extends FormField {
return $this->maxLength; return $this->maxLength;
} }
function Field() { function Field($properties = array()) {
$attributes = array( $properties = array_merge(
'type' => 'text', $properties,
'class' => 'text' . ($this->extraClass() ? $this->extraClass() : ''), array(
'id' => $this->id(), 'MaxLength' => ($this->getMaxLength()) ? $this->getMaxLength() : null,
'name' => $this->getName(), 'Size' => ($this->getMaxLength()) ? min($this->getMaxLength(), 30) : null
'value' => $this->Value(), )
'tabindex' => $this->getTabIndex(),
'maxlength' => ($this->maxLength) ? $this->maxLength : null,
'size' => ($this->maxLength) ? min( $this->maxLength, 30 ) : null
); );
if($this->disabled) $attributes['disabled'] = 'disabled'; return $this->customise($properties)->renderWith('TextField');
return $this->createTag('input', $attributes);
} }
function InternallyLabelledField() { function InternallyLabelledField() {
@ -57,4 +52,3 @@ class TextField extends FormField {
} }
} }
?>

View File

@ -21,7 +21,8 @@
* @subpackage fields-basic * @subpackage fields-basic
*/ */
class TextareaField extends FormField { class TextareaField extends FormField {
protected $rows, $cols, $disabled = false, $readonly = false;
protected $rows, $cols;
/** /**
* Create a new textarea field. * Create a new textarea field.
@ -46,45 +47,17 @@ class TextareaField extends FormField {
* *
* @return HTML code for the textarea OR span element * @return HTML code for the textarea OR span element
*/ */
function Field() { function Field($properties = array()) {
if($this->readonly) { $properties = array_merge(
$attributes = array( $properties,
'id' => $this->id(), array(
'class' => 'readonly' . ($this->extraClass() ? $this->extraClass() : ''), 'Rows' => $this->rows,
'name' => $this->name, 'Cols' => $this->cols,
'readonly' => 'readonly' 'Value' => htmlentities($this->value, ENT_COMPAT, 'UTF-8')
); )
);
$value = (($this->value) ? nl2br(htmlentities($this->value, ENT_COMPAT, 'UTF-8')) : '<i>(' . _t('FormField.NONE', 'none') . ')</i>'); return $this->customise($properties)->renderWith('TextareaField');
$hiddenAttributes = array(
'type' => 'hidden',
'name' => $this->name,
'value' => $value
);
$containerSpan = $this->createTag(
'span',
$attributes,
$value
);
$hiddenInput = $this->createTag('input', $hiddenAttributes);
return $containerSpan . "\n" . $hiddenInput;
} else {
$attributes = array(
'id' => $this->id(),
'class' => ($this->extraClass() ? $this->extraClass() : ''),
'name' => $this->name,
'rows' => $this->rows,
'cols' => $this->cols,
'tabindex' => $this->getTabIndex()
);
if($this->disabled) $attributes['disabled'] = 'disabled';
return $this->createTag('textarea', $attributes, htmlentities($this->value, ENT_COMPAT, 'UTF-8'));
}
} }
/** /**
@ -114,7 +87,7 @@ class TextareaField extends FormField {
} }
function Type() { function Type() {
return parent::Type() . ( $this->readonly ? ' readonly' : '' ); return parent::Type() . ($this->readonly ? ' readonly' : '');
} }
/** /**

View File

@ -128,10 +128,14 @@ class TreeDropdownField extends FormField {
$this->searchCallback = $callback; $this->searchCallback = $callback;
} }
public function getShowSearch() {
return $this->showSearch;
}
/** /**
* @return string * @return string
*/ */
public function Field() { public function Field($properties = array()) {
Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang'); Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang');
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery/jquery.js'); Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery/jquery.js');
@ -156,27 +160,15 @@ class TreeDropdownField extends FormField {
'ClassName' => $record ? $record->ClassName : $this->sourceObject 'ClassName' => $record ? $record->ClassName : $this->sourceObject
); );
return $this->createTag( $properties = array_merge(
'div', $properties,
array ( array(
'id' => "TreeDropdownField_{$this->id()}", 'Title' => $title,
'class' => 'TreeDropdownField single' . ($this->extraClass() ? " {$this->extraClass()}" : '') . ($this->showSearch ? " searchable" : ''), 'Metadata' => ($metadata) ? Convert::raw2json($metadata) : null
'data-url-tree' => $this->form ? $this->Link('tree') : "",
'data-title' => $title,
// Any additional data from the selected record
'data-metadata' => ($metadata) ? Convert::raw2json($metadata) : null
),
$this->createTag(
'input',
array (
'id' => $this->id(),
'type' => 'hidden',
'class' => 'text' . ($this->extraClass() ? $this->extraClass() : ''),
'name' => $this->name,
'value' => $this->value
)
) )
); );
return $this->customise($properties)->renderWith('TreeDropdownField');
} }
/** /**

View File

@ -0,0 +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 %>>

View File

@ -0,0 +1,5 @@
<div id="$Name" class="field $Type<% if extraClass %>$extraClass<% end_if %>">
$Field
<label class="right" for="$ID">$Title</label>
<% if Message %><span class="message $MessageType">$messageBlock</span><% end_if %>
</div>

View File

@ -0,0 +1,8 @@
<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>

View File

@ -0,0 +1,5 @@
<select id="$ID" class="dropdown$extraClass" name="$Name"<% if TabIndex %> tabindex="$TabIndex"<% end_if %><% if isDisabled %> disabled<% end_if %>>
<% control Options %>
<option value="$Value"<% if Selected %> selected<% end_if %>>$Title</option>
<% end_control %>
</select>

View File

@ -0,0 +1,6 @@
<div id="$Name" class="field $Type<% if extraClass %>$extraClass<% end_if %>">
<% if Title %><label class="left" for="$ID">$Title</label><% end_if %>
<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 File

@ -0,0 +1,2 @@
<input id="$ID" class="file$extraClass" type="file" name="$Name"<% if TabIndex %> tabindex="$TabIndex"<% end_if %>>
<input type="hidden" name="MAX_FILE_SIZE" value="$MaxFileSize">

View File

@ -0,0 +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>
<% 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 %>>
<% end_if %>

View File

@ -0,0 +1,2 @@
<span id="$ID" class="field$extraClass">$NiceValue</span>
<hidden type="hidden" name="$Name" value="$Value"<% if TabIndex %> tabindex="$TabIndex"<% end_if %>>

View File

@ -0,0 +1 @@
<h$HeadingLevel id="$ID" class="header$extraClass">$Title</h$HeadingLevel>

View File

@ -0,0 +1 @@
<input class="hidden$extraClass" type="hidden" id="$ID" name="$Name" value="$Value">

View File

@ -0,0 +1 @@
<label id="$ID" class="label$extraClass">$Title</label>

View File

@ -0,0 +1,8 @@
<ul id="$ID" class="optionset$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 %>>
<label for="$ID">$Title</label>
</li>
<% end_control %>
</ul>

View File

@ -0,0 +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 %> />

View File

@ -0,0 +1,5 @@
<% if isReadonly %>
<span id="$ID" class="textarea readonly$extraClass"><% if Value %>$Value<% else %><em>(<% _t('NONE', 'none') %>)</em><% end_if %></span>
<% else %>
<textarea id="$ID" class="textarea$extraClass" name="$Name" rows="$Rows" cols="$Cols"<% if isDisabled %> disabled<% end_if %>></textarea>
<% end_if %>

View File

@ -0,0 +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>

View File

@ -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() { function testSaveWithNothingSelected() {
$article = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithouttags'); $article = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithouttags');

View File

@ -5,14 +5,6 @@
*/ */
class DropdownFieldTest extends SapphireTest { 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() { function testGetSource() {
$source = array(1=>'one'); $source = array(1=>'one');
$field = new DropdownField('Field', null, $source); $field = new DropdownField('Field', null, $source);

View File

@ -5,26 +5,6 @@
*/ */
class FormFieldTest extends SapphireTest { 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() { function testEveryFieldTransformsReadonlyAsClone() {
$fieldClasses = ClassInfo::subclassesFor('FormField'); $fieldClasses = ClassInfo::subclassesFor('FormField');
foreach($fieldClasses as $fieldClass) { foreach($fieldClasses as $fieldClass) {

View File

@ -8,6 +8,6 @@ class LabelFieldTest extends SapphireTest {
function testFieldHasNoNameAttribute() { function testFieldHasNoNameAttribute() {
$field = new LabelField('MyName', 'MyTitle'); $field = new LabelField('MyName', 'MyTitle');
$this->assertEquals($field->Field(), '<label id="MyName">MyTitle</label>'); $this->assertEquals($field->Field(), '<label id="MyName" class="label">MyTitle</label>');
} }
} }