mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
API Support composite react formfields
Cleanup and standardise CompositeField API and subclasses
This commit is contained in:
parent
d19955afc8
commit
9e1b12a891
@ -57,10 +57,24 @@ class CompositeField extends FormField {
|
||||
}
|
||||
$this->children->setContainerField($this);
|
||||
|
||||
// Skipping FormField::__construct(), but we have to make sure this
|
||||
// doesn't count as a broken constructor
|
||||
$this->brokenOnConstruct = false;
|
||||
Object::__construct();
|
||||
parent::__construct(null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge child field data into this form
|
||||
*/
|
||||
public function getSchemaDataDefaults() {
|
||||
$defaults = parent::getSchemaDataDefaults();
|
||||
$children = $this->getChildren();
|
||||
if($children && $children->count()) {
|
||||
$childSchema = [];
|
||||
/** @var FormField $child */
|
||||
foreach($children as $child) {
|
||||
$childSchema[] = $child->getSchemaData();
|
||||
}
|
||||
$defaults['children'] = $childSchema;
|
||||
}
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,11 +86,6 @@ class CompositeField extends FormField {
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
public function setID($id) {
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor method for $this->children
|
||||
*
|
||||
@ -88,6 +97,7 @@ class CompositeField extends FormField {
|
||||
|
||||
/**
|
||||
* @param FieldList $children
|
||||
* @return $this
|
||||
*/
|
||||
public function setChildren($children) {
|
||||
$this->children = $children;
|
||||
@ -95,7 +105,8 @@ class CompositeField extends FormField {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @param string $tag
|
||||
* @return $this
|
||||
*/
|
||||
public function setTag($tag) {
|
||||
$this->tag = $tag;
|
||||
@ -111,7 +122,8 @@ class CompositeField extends FormField {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @param string $legend
|
||||
* @return $this
|
||||
*/
|
||||
public function setLegend($legend) {
|
||||
$this->legend = $legend;
|
||||
@ -147,7 +159,6 @@ class CompositeField extends FormField {
|
||||
'tabindex' => null,
|
||||
'type' => null,
|
||||
'value' => null,
|
||||
'type' => null,
|
||||
'title' => ($this->tag == 'fieldset') ? null : $this->legend
|
||||
)
|
||||
);
|
||||
@ -158,38 +169,46 @@ class CompositeField extends FormField {
|
||||
* list.
|
||||
*
|
||||
* Sequentialisation is used when connecting the form to its data source
|
||||
*
|
||||
* @param array $list
|
||||
* @param bool $saveableOnly
|
||||
*/
|
||||
public function collateDataFields(&$list, $saveableOnly = false) {
|
||||
foreach($this->children as $field) {
|
||||
if(is_object($field)) {
|
||||
if($field->isComposite()) $field->collateDataFields($list, $saveableOnly);
|
||||
if($saveableOnly) {
|
||||
$isIncluded = ($field->hasData() && !$field->isReadonly() && !$field->isDisabled());
|
||||
} else {
|
||||
$isIncluded = ($field->hasData());
|
||||
}
|
||||
if($isIncluded) {
|
||||
$name = $field->getName();
|
||||
if($name) {
|
||||
$formName = (isset($this->form)) ? $this->form->FormName() : '(unknown form)';
|
||||
if(isset($list[$name])) {
|
||||
user_error("collateDataFields() I noticed that a field called '$name' appears twice in"
|
||||
. " your form: '{$formName}'. One is a '{$field->class}' and the other is a"
|
||||
. " '{$list[$name]->class}'", E_USER_ERROR);
|
||||
}
|
||||
$list[$name] = $field;
|
||||
if(! $field instanceof FormField) {
|
||||
continue;
|
||||
}
|
||||
if($field instanceof CompositeField) {
|
||||
$field->collateDataFields($list, $saveableOnly);
|
||||
}
|
||||
if($saveableOnly) {
|
||||
$isIncluded = ($field->hasData() && !$field->isReadonly() && !$field->isDisabled());
|
||||
} else {
|
||||
$isIncluded = ($field->hasData());
|
||||
}
|
||||
if($isIncluded) {
|
||||
$name = $field->getName();
|
||||
if($name) {
|
||||
$formName = (isset($this->form)) ? $this->form->FormName() : '(unknown form)';
|
||||
if(isset($list[$name])) {
|
||||
user_error("collateDataFields() I noticed that a field called '$name' appears twice in"
|
||||
. " your form: '{$formName}'. One is a '{$field->class}' and the other is a"
|
||||
. " '{$list[$name]->class}'", E_USER_ERROR);
|
||||
}
|
||||
$list[$name] = $field;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setForm($form) {
|
||||
foreach($this->children as $f)
|
||||
if(is_object($f)) $f->setForm($form);
|
||||
foreach($this->children as $field) {
|
||||
if ($field instanceof FormField) {
|
||||
$field->setForm($form);
|
||||
}
|
||||
}
|
||||
|
||||
parent::setForm($form);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -234,20 +253,23 @@ class CompositeField extends FormField {
|
||||
|
||||
/**
|
||||
* @uses FieldList->insertBefore()
|
||||
*
|
||||
* @param string $insertBefore
|
||||
* @param FormField $field
|
||||
* @return false|FormField
|
||||
*/
|
||||
public function insertBefore($insertBefore, $field) {
|
||||
$ret = $this->children->insertBefore($insertBefore, $field);
|
||||
$this->sequentialSet = null;
|
||||
return $ret;
|
||||
return $this->children->insertBefore($insertBefore, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* @uses FieldList->insertAfter()
|
||||
* @param string $insertAfter
|
||||
* @param FormField $field
|
||||
* @return false|FormField
|
||||
*/
|
||||
public function insertAfter($insertAfter, $field) {
|
||||
$ret = $this->children->insertAfter($insertAfter, $field);
|
||||
$this->sequentialSet = null;
|
||||
return $ret;
|
||||
return $this->children->insertAfter($insertAfter, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -281,9 +303,10 @@ class CompositeField extends FormField {
|
||||
public function performReadonlyTransformation() {
|
||||
$newChildren = new FieldList();
|
||||
$clone = clone $this;
|
||||
if($clone->getChildren()) foreach($clone->getChildren() as $idx => $child) {
|
||||
if(is_object($child)) $child = $child->transform(new ReadonlyTransformation());
|
||||
$newChildren->push($child, $idx);
|
||||
if($clone->getChildren()) foreach($clone->getChildren() as $child) {
|
||||
/** @var FormField $child */
|
||||
$child = $child->transform(new ReadonlyTransformation());
|
||||
$newChildren->push($child);
|
||||
}
|
||||
|
||||
$clone->children = $newChildren;
|
||||
@ -303,9 +326,10 @@ class CompositeField extends FormField {
|
||||
public function performDisabledTransformation() {
|
||||
$newChildren = new FieldList();
|
||||
$clone = clone $this;
|
||||
if($clone->getChildren()) foreach($clone->getChildren() as $idx => $child) {
|
||||
if(is_object($child)) $child = $child->transform(new DisabledTransformation());
|
||||
$newChildren->push($child, $idx);
|
||||
if($clone->getChildren()) foreach($clone->getChildren() as $child) {
|
||||
/** @var FormField $child */
|
||||
$child = $child->transform(new DisabledTransformation());
|
||||
$newChildren->push($child);
|
||||
}
|
||||
|
||||
$clone->children = $newChildren;
|
||||
@ -332,12 +356,19 @@ class CompositeField extends FormField {
|
||||
* be found.
|
||||
*/
|
||||
public function fieldPosition($field) {
|
||||
if(is_string($field)) $field = $this->fieldByName($field);
|
||||
if(!$field) return false;
|
||||
if(is_string($field)) {
|
||||
$field = $this->fieldByName($field);
|
||||
}
|
||||
if(!$field) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
foreach($this->children as $child) {
|
||||
if($child->getName() == $field->getName()) return $i;
|
||||
/** @var FormField $child */
|
||||
if($child->getName() == $field->getName()) {
|
||||
return $i;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
@ -348,25 +379,23 @@ class CompositeField extends FormField {
|
||||
* Transform the named field into a readonly feld.
|
||||
*
|
||||
* @param string|FormField
|
||||
* @return bool
|
||||
*/
|
||||
public function makeFieldReadonly($field) {
|
||||
$fieldName = ($field instanceof FormField) ? $field->getName() : $field;
|
||||
|
||||
// Iterate on items, looking for the applicable field
|
||||
foreach($this->children as $i => $item) {
|
||||
if($item->isComposite()) {
|
||||
$item->makeFieldReadonly($fieldName);
|
||||
} else {
|
||||
// Once it's found, use FormField::transform to turn the field into a readonly version of itself.
|
||||
if($item->getName() == $fieldName) {
|
||||
$this->children->replaceField($fieldName, $item->transform(new ReadonlyTransformation()));
|
||||
|
||||
// Clear an internal cache
|
||||
$this->sequentialSet = null;
|
||||
|
||||
// A true results indicates that the field was found
|
||||
if($item instanceof CompositeField) {
|
||||
if($item->makeFieldReadonly($fieldName)) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} elseif($item instanceof FormField && $item->getName() == $fieldName) {
|
||||
// Once it's found, use FormField::transform to turn the field into a readonly version of itself.
|
||||
$this->children->replaceField($fieldName, $item->transform(new ReadonlyTransformation()));
|
||||
|
||||
// A true results indicates that the field was found
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -389,7 +418,8 @@ class CompositeField extends FormField {
|
||||
*/
|
||||
public function validate($validator) {
|
||||
$valid = true;
|
||||
foreach($this->children as $idx => $child){
|
||||
foreach($this->children as $child){
|
||||
/** @var FormField $child */
|
||||
$valid = ($child && $child->validate($validator) && $valid);
|
||||
}
|
||||
return $valid;
|
||||
|
@ -59,20 +59,42 @@ class FieldGroup extends CompositeField {
|
||||
|
||||
protected $zebra;
|
||||
|
||||
public function __construct($arg1 = null, $arg2 = null) {
|
||||
if(is_array($arg1) || is_a($arg1, 'FieldSet')) {
|
||||
$fields = $arg1;
|
||||
/**
|
||||
* Create a new field group.
|
||||
*
|
||||
* Accepts any number of arguments.
|
||||
*
|
||||
* @param mixed $titleOrField Either the field title, list of fields, or first field
|
||||
* @param mixed ...$otherFields Subsequent fields or field list (if passing in title to $titleOrField)
|
||||
*/
|
||||
public function __construct($titleOrField = null, $otherFields = null) {
|
||||
$title = null;
|
||||
if(is_array($titleOrField) || $titleOrField instanceof FieldList) {
|
||||
$fields = $titleOrField;
|
||||
|
||||
} else if(is_array($arg2) || is_a($arg2, 'FieldList')) {
|
||||
$this->title = $arg1;
|
||||
$fields = $arg2;
|
||||
// This would be discarded otherwise
|
||||
if($otherFields) {
|
||||
throw new InvalidArgumentException(
|
||||
'$otherFields is not accepted if passing in field list to $titleOrField'
|
||||
);
|
||||
}
|
||||
|
||||
} else if(is_array($otherFields) || $otherFields instanceof FieldList) {
|
||||
$title = $titleOrField;
|
||||
$fields = $otherFields;
|
||||
|
||||
} else {
|
||||
$fields = func_get_args();
|
||||
if(!is_object(reset($fields))) $this->title = array_shift($fields);
|
||||
if(!is_object(reset($fields))) {
|
||||
$title = array_shift($fields);
|
||||
}
|
||||
}
|
||||
|
||||
parent::__construct($fields);
|
||||
|
||||
if($title) {
|
||||
$this->setTitle($title);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,12 +102,13 @@ class FieldGroup extends CompositeField {
|
||||
* In some cases the FieldGroup doesn't have a title, but we still want
|
||||
* the ID / name to be set. This code, generates the ID from the nested children
|
||||
*/
|
||||
public function Name(){
|
||||
public function getName(){
|
||||
if(!$this->title) {
|
||||
$fs = $this->FieldList();
|
||||
$compositeTitle = '';
|
||||
$count = 0;
|
||||
foreach($fs as $subfield){
|
||||
/** @var FormField $subfield */
|
||||
$compositeTitle .= $subfield->getName();
|
||||
if($subfield->getName()) $count++;
|
||||
}
|
||||
@ -101,6 +124,7 @@ class FieldGroup extends CompositeField {
|
||||
* Set an odd/even class
|
||||
*
|
||||
* @param string $zebra one of odd or even.
|
||||
* @return $this
|
||||
*/
|
||||
public function setZebra($zebra) {
|
||||
if($zebra == 'odd' || $zebra == 'even') $this->zebra = $zebra;
|
||||
@ -142,8 +166,4 @@ class FieldGroup extends CompositeField {
|
||||
|
||||
return (isset($MessageType)) ? implode(". ", $MessageType) : "";
|
||||
}
|
||||
|
||||
public function php($data) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -651,7 +651,6 @@ class FieldList extends ArrayList {
|
||||
* @return String Rewritten path, based on {@link tabPathRewrites}
|
||||
*/
|
||||
protected function rewriteTabPath($name) {
|
||||
$isRunningTest = (class_exists('SapphireTest', false) && SapphireTest::is_running_test());
|
||||
foreach($this->getTabPathRewrites() as $regex => $replace) {
|
||||
if(preg_match($regex, $name)) {
|
||||
$newName = preg_replace($regex, $replace, $name);
|
||||
|
@ -648,7 +648,8 @@ class FormField extends RequestHandler {
|
||||
*
|
||||
* Caution: this doesn't work on all fields, see {@link setAttribute()}.
|
||||
*
|
||||
* @return null|string
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public function getAttribute($name) {
|
||||
$attributes = $this->getAttributes();
|
||||
@ -1239,8 +1240,7 @@ class FormField extends RequestHandler {
|
||||
*
|
||||
* @todo Make this abstract.
|
||||
*
|
||||
* @param Validator
|
||||
*
|
||||
* @param Validator $validator
|
||||
* @return bool
|
||||
*/
|
||||
public function validate($validator) {
|
||||
@ -1297,7 +1297,7 @@ class FormField extends RequestHandler {
|
||||
* @return bool
|
||||
*/
|
||||
public function Required() {
|
||||
if($this->form && ($validator = $this->form->Validator)) {
|
||||
if($this->form && ($validator = $this->form->getValidator())) {
|
||||
return $validator->fieldIsRequired($this->name);
|
||||
}
|
||||
|
||||
@ -1451,14 +1451,14 @@ class FormField extends RequestHandler {
|
||||
'id' => $this->ID(),
|
||||
'type' => $this->getSchemaDataType(),
|
||||
'component' => $this->getSchemaComponent(),
|
||||
'holder_id' => null,
|
||||
'holder_id' => $this->HolderID(),
|
||||
'title' => $this->Title(),
|
||||
'source' => null,
|
||||
'extraClass' => $this->ExtraClass(),
|
||||
'extraClass' => $this->extraClass(),
|
||||
'description' => $this->getDescription(),
|
||||
'rightTitle' => $this->RightTitle(),
|
||||
'leftTitle' => $this->LeftTitle(),
|
||||
'readOnly' => $this->isReadOnly(),
|
||||
'readOnly' => $this->isReadonly(),
|
||||
'disabled' => $this->isDisabled(),
|
||||
'customValidationMessage' => $this->getCustomValidationMessage(),
|
||||
'attributes' => [],
|
||||
@ -1472,7 +1472,7 @@ class FormField extends RequestHandler {
|
||||
* Any passed keys that are not defined in {@link getSchemaDataDefaults()} are ignored.
|
||||
* If you want to pass around ad hoc data use the `data` array e.g. pass `['data' => ['myCustomKey' => 'yolo']]`.
|
||||
*
|
||||
* @param array $schemaData - The data to be merged with $this->schemaData.
|
||||
* @param array $schemaState The data to be merged with $this->schemaData.
|
||||
* @return FormField
|
||||
*
|
||||
* @todo Add deep merging of arrays like `data` and `attributes`.
|
||||
@ -1514,6 +1514,7 @@ class FormField extends RequestHandler {
|
||||
'type' => $error['messageType']
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}, $errors));
|
||||
|
||||
return [
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
namespace SilverStripe\Forms\Schema;
|
||||
|
||||
use Convert;
|
||||
use Form;
|
||||
use FormField;
|
||||
|
||||
/**
|
||||
* Class FormSchema
|
||||
@ -38,11 +38,12 @@ class FormSchema {
|
||||
];
|
||||
|
||||
foreach ($form->Actions() as $action) {
|
||||
/** @var FormField $action */
|
||||
$schema['actions'][] = $action->getSchemaData();
|
||||
}
|
||||
|
||||
// TODO Implemented nested fields and use Fields() instead
|
||||
foreach ($form->Fields()->dataFields() as $field) {
|
||||
foreach ($form->Fields() as $field) {
|
||||
/** @var FormField $field */
|
||||
$schema['fields'][] = $field->getSchemaData();
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,6 @@ class PhoneNumberField extends FormField {
|
||||
*/
|
||||
public function Field($properties = array()) {
|
||||
$fields = new FieldGroup( $this->name );
|
||||
$fields->setID("{$this->name}_Holder");
|
||||
list($countryCode, $areaCode, $phoneNumber, $extension) = $this->parseValue();
|
||||
|
||||
if ($this->value=="") {
|
||||
|
@ -38,8 +38,6 @@ class SelectionGroup extends CompositeField {
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __construct($name, $items, $value = null) {
|
||||
$this->name = $name;
|
||||
|
||||
if($value !== null) {
|
||||
$this->setValue($value);
|
||||
}
|
||||
@ -62,7 +60,7 @@ class SelectionGroup extends CompositeField {
|
||||
|
||||
parent::__construct($selectionItems);
|
||||
|
||||
Requirements::css(FRAMEWORK_DIR . '/client/dist/styles/SelectionGroup.css');
|
||||
$this->setName($name);
|
||||
}
|
||||
|
||||
public function FieldSet() {
|
||||
@ -138,15 +136,18 @@ class SelectionGroup_Item extends CompositeField {
|
||||
|
||||
/**
|
||||
* @param String $value Form field identifier
|
||||
* @param FormField $field Contents of the option
|
||||
* @param FormField|array $fields Contents of the option
|
||||
* @param String $title Title to show for the radio button option
|
||||
*/
|
||||
function __construct($value, $fields = null, $title = null) {
|
||||
$this->value = $value;
|
||||
$this->title = ($title) ? $title : $value;
|
||||
if($fields && !is_array($fields)) $fields = array($fields);
|
||||
$this->setValue($value);
|
||||
if($fields && !is_array($fields)) {
|
||||
$fields = array($fields);
|
||||
}
|
||||
|
||||
parent::__construct($fields);
|
||||
|
||||
$this->setTitle($title ?: $value);
|
||||
}
|
||||
|
||||
function getTitle() {
|
||||
|
@ -17,55 +17,98 @@
|
||||
* @subpackage fields-structural
|
||||
*/
|
||||
class Tab extends CompositeField {
|
||||
|
||||
/**
|
||||
* @var TabSet
|
||||
*/
|
||||
protected $tabSet;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @uses FormField::name_to_label()
|
||||
*
|
||||
* @param string $name Identifier of the tab, without characters like dots or spaces
|
||||
* @param string $title Natural language title of the tab. If its left out,
|
||||
* the class uses {@link FormField::name_to_label()} to produce a title from the {@link $name} parameter.
|
||||
* @param FormField All following parameters are inserted as children to this tab
|
||||
* @param string|FormField $titleOrField Natural language title of the tabset, or first tab.
|
||||
* If its left out, the class uses {@link FormField::name_to_label()} to produce a title
|
||||
* from the {@link $name} parameter.
|
||||
* @param FormField ...$fields All following parameters are inserted as children to this tab
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$args = func_get_args();
|
||||
|
||||
$name = array_shift($args);
|
||||
if(!is_string($name)) user_error('TabSet::__construct(): $name parameter to a valid string', E_USER_ERROR);
|
||||
$this->name = $name;
|
||||
|
||||
$this->id = preg_replace('/[^0-9A-Za-z]+/', '', $name);
|
||||
|
||||
// Legacy handling: only assume second parameter as title if its a string,
|
||||
// otherwise it might be a formfield instance
|
||||
if(isset($args[0]) && is_string($args[0])) {
|
||||
$title = array_shift($args);
|
||||
public function __construct($name, $titleOrField = null, $fields = null) {
|
||||
if(!is_string($name)) {
|
||||
throw new InvalidArgumentException('Invalid string parameter for $name');
|
||||
}
|
||||
$this->title = (isset($title)) ? $title : FormField::name_to_label($name);
|
||||
|
||||
parent::__construct($args);
|
||||
// Get following arguments
|
||||
$fields = func_get_args();
|
||||
array_shift($fields);
|
||||
|
||||
// Detect title from second argument, if it is a string
|
||||
if($titleOrField && is_string($titleOrField)) {
|
||||
$title = $titleOrField;
|
||||
array_shift($fields);
|
||||
} else {
|
||||
$title = static::name_to_label($name);
|
||||
}
|
||||
|
||||
// Remaining arguments are child fields
|
||||
parent::__construct($fields);
|
||||
|
||||
// Assign name and title (not assigned by parent constructor)
|
||||
$this->setName($name);
|
||||
$this->setTitle($title);
|
||||
$this->setID(Convert::raw2htmlid($name));
|
||||
}
|
||||
|
||||
public function id() {
|
||||
return ($this->tabSet) ? $this->tabSet->id() . '_' . $this->id : $this->id;
|
||||
public function ID() {
|
||||
if($this->tabSet) {
|
||||
return $this->tabSet->ID() . '_' . $this->id;
|
||||
} else {
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom HTML ID to use for this tabset
|
||||
*
|
||||
* @param string $id
|
||||
* @return $this
|
||||
*/
|
||||
public function setID($id) {
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get child fields
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
public function Fields() {
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign to a TabSet instance
|
||||
*
|
||||
* @param TabSet $val
|
||||
* @return $this
|
||||
*/
|
||||
public function setTabSet($val) {
|
||||
$this->tabSet = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the named field
|
||||
* Get parent tabset
|
||||
*
|
||||
* @return TabSet
|
||||
*/
|
||||
public function fieldByName($name) {
|
||||
foreach($this->children as $child) {
|
||||
if($name == $child->getName()) return $child;
|
||||
}
|
||||
public function getTabSet() {
|
||||
return $this->tabSet;
|
||||
}
|
||||
|
||||
public function extraClass() {
|
||||
@ -76,7 +119,7 @@ class Tab extends CompositeField {
|
||||
return array_merge(
|
||||
$this->attributes,
|
||||
array(
|
||||
'id' => $this->id(),
|
||||
'id' => $this->ID(),
|
||||
'class' => 'tab ' . $this->extraClass()
|
||||
)
|
||||
);
|
||||
|
171
forms/TabSet.php
171
forms/TabSet.php
@ -1,4 +1,6 @@
|
||||
<?php
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
|
||||
/**
|
||||
* Defines a set of tabs in a form.
|
||||
* The tabs are build with our standard tabstrip javascript library.
|
||||
@ -28,44 +30,88 @@
|
||||
class TabSet extends CompositeField {
|
||||
|
||||
/**
|
||||
* @param string $name Identifier
|
||||
* @param string $title (Optional) Natural language title of the tabset
|
||||
* @param Tab|TabSet $unknown All further parameters are inserted as children into the TabSet
|
||||
* @var TabSet
|
||||
*/
|
||||
public function __construct($name) {
|
||||
$args = func_get_args();
|
||||
protected $tabSet;
|
||||
|
||||
$name = array_shift($args);
|
||||
if(!is_string($name)) user_error('TabSet::__construct(): $name parameter to a valid string', E_USER_ERROR);
|
||||
$this->name = $name;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
$this->id = $name;
|
||||
|
||||
// Legacy handling: only assume second parameter as title if its a string,
|
||||
// otherwise it might be a formfield instance
|
||||
if(isset($args[0]) && is_string($args[0])) {
|
||||
$title = array_shift($args);
|
||||
}
|
||||
$this->title = (isset($title)) ? $title : FormField::name_to_label($name);
|
||||
|
||||
if($args) foreach($args as $tab) {
|
||||
$isValidArg = (is_object($tab) && (!($tab instanceof Tab) || !($tab instanceof TabSet)));
|
||||
if(!$isValidArg) user_error('TabSet::__construct(): Parameter not a valid Tab instance', E_USER_ERROR);
|
||||
|
||||
$tab->setTabSet($this);
|
||||
/**
|
||||
* @param string $name Identifier
|
||||
* @param string|Tab|TabSet $titleOrTab Natural language title of the tabset, or first tab.
|
||||
* If its left out, the class uses {@link FormField::name_to_label()} to produce a title
|
||||
* from the {@link $name} parameter.
|
||||
* @param Tab|TabSet ...$tabs All further parameters are inserted as children into the TabSet
|
||||
*/
|
||||
public function __construct($name, $titleOrTab = null, $tabs = null) {
|
||||
if(!is_string($name)) {
|
||||
throw new InvalidArgumentException('Invalid string parameter for $name');
|
||||
}
|
||||
|
||||
parent::__construct($args);
|
||||
// Get following arguments
|
||||
$tabs = func_get_args();
|
||||
array_shift($tabs);
|
||||
|
||||
// Detect title from second argument, if it is a string
|
||||
if($titleOrTab && is_string($titleOrTab)) {
|
||||
$title = $titleOrTab;
|
||||
array_shift($tabs);
|
||||
} else {
|
||||
$title = static::name_to_label($name);
|
||||
}
|
||||
|
||||
// Normalise children list
|
||||
if(count($tabs) === 1 && (is_array($tabs[0]) || $tabs[0] instanceof FieldList)) {
|
||||
$tabs = $tabs[0];
|
||||
}
|
||||
|
||||
// Ensure tabs are assigned to this tabset
|
||||
if($tabs) {
|
||||
foreach($tabs as $tab) {
|
||||
if ($tab instanceof Tab || $tab instanceof TabSet) {
|
||||
$tab->setTabSet($this);
|
||||
} else {
|
||||
throw new InvalidArgumentException("TabSet can only contain instances of other Tab or Tabsets");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::__construct($tabs);
|
||||
|
||||
// Assign name and title (not assigned by parent constructor)
|
||||
$this->setName($name);
|
||||
$this->setTitle($title);
|
||||
$this->setID(Convert::raw2htmlid($name));
|
||||
}
|
||||
|
||||
public function id() {
|
||||
if($this->tabSet) return $this->tabSet->id() . '_' . $this->id . '_set';
|
||||
else return $this->id;
|
||||
public function ID() {
|
||||
if($this->tabSet) {
|
||||
return $this->tabSet->ID() . '_' . $this->id . '_set';
|
||||
} else {
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom HTML ID to use for this tabset
|
||||
*
|
||||
* @param string $id
|
||||
* @return $this
|
||||
*/
|
||||
public function setID($id) {
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a tab-strip and the associated tabs.
|
||||
* The HTML is a standardised format, containing a <ul;
|
||||
*
|
||||
* @param array $properties
|
||||
* @return DBHTMLText|string
|
||||
*/
|
||||
public function FieldHolder($properties = array()) {
|
||||
Requirements::javascript(FRAMEWORK_DIR . '/thirdparty/jquery/jquery.js');
|
||||
@ -84,78 +130,73 @@ class TabSet extends CompositeField {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a dataobject set of all this classes tabs
|
||||
* Return a set of all this classes tabs
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
public function Tabs() {
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FieldList $children Assign list of tabs
|
||||
*/
|
||||
public function setTabs($children){
|
||||
$this->children = $children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign to a TabSet instance
|
||||
*
|
||||
* @param TabSet $val
|
||||
* @return $this
|
||||
*/
|
||||
public function setTabSet($val) {
|
||||
$this->tabSet = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent tabset
|
||||
*
|
||||
* @return TabSet
|
||||
*/
|
||||
public function getTabSet() {
|
||||
if(isset($this->tabSet)) return $this->tabSet;
|
||||
return $this->tabSet;
|
||||
}
|
||||
|
||||
public function getAttributes() {
|
||||
return array_merge(
|
||||
$this->attributes,
|
||||
array(
|
||||
'id' => $this->id(),
|
||||
'id' => $this->ID(),
|
||||
'class' => $this->extraClass()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a named field.
|
||||
*
|
||||
* @param string $name Name of the field you want to find. Allows for dot notation.
|
||||
* @return FormField|null
|
||||
*/
|
||||
public function fieldByName($name) {
|
||||
if(strpos($name,'.') !== false) list($name, $remainder) = explode('.',$name,2);
|
||||
else $remainder = null;
|
||||
|
||||
foreach($this->children as $child) {
|
||||
if(trim($name) == trim($child->Name) || $name == $child->id) {
|
||||
if($remainder) {
|
||||
if($child->isComposite()) {
|
||||
return $child->fieldByName($remainder);
|
||||
} else {
|
||||
user_error("Trying to get field '$remainder' from non-composite field $child->class.$name",
|
||||
E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return $child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new child field to the end of the set.
|
||||
*
|
||||
* @param FormField $field
|
||||
*/
|
||||
public function push(FormField $field) {
|
||||
if ($field instanceof Tab || $field instanceof TabSet) {
|
||||
$field->setTabSet($this);
|
||||
}
|
||||
parent::push($field);
|
||||
$field->setTabSet($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new child field to the beginning of the set.
|
||||
*
|
||||
* @param FormField $field
|
||||
*/
|
||||
public function unshift(FormField $field) {
|
||||
if ($field instanceof Tab || $field instanceof TabSet) {
|
||||
$field->setTabSet($this);
|
||||
}
|
||||
parent::unshift($field);
|
||||
$field->setTabSet($this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,10 +204,12 @@ class TabSet extends CompositeField {
|
||||
*
|
||||
* @param string $insertBefore Name of the field to insert before
|
||||
* @param FormField $field The form field to insert
|
||||
* @return FormField|null
|
||||
* @return FormField|null
|
||||
*/
|
||||
public function insertBefore($insertBefore, $field) {
|
||||
if($field instanceof Tab) $field->setTabSet($this);
|
||||
if ($field instanceof Tab || $field instanceof TabSet) {
|
||||
$field->setTabSet($this);
|
||||
}
|
||||
return parent::insertBefore($insertBefore, $field);
|
||||
}
|
||||
|
||||
@ -178,7 +221,9 @@ class TabSet extends CompositeField {
|
||||
* @return FormField|null
|
||||
*/
|
||||
public function insertAfter($insertAfter, $field) {
|
||||
if($field instanceof Tab) $field->setTabSet($this);
|
||||
if ($field instanceof Tab || $field instanceof TabSet) {
|
||||
$field->setTabSet($this);
|
||||
}
|
||||
return parent::insertAfter($insertAfter, $field);
|
||||
}
|
||||
}
|
||||
|
@ -25,10 +25,9 @@ class ToggleCompositeField extends CompositeField {
|
||||
* @param array|FieldList $children
|
||||
*/
|
||||
public function __construct($name, $title, $children) {
|
||||
$this->name = $name;
|
||||
$this->title = $title;
|
||||
|
||||
parent::__construct($children);
|
||||
$this->setName($name);
|
||||
$this->setTitle($title);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user