mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 17:05:42 +02:00
Merge pull request #19 from tractorcow/pulls/field-groups
API Frontend form fields for nested composite fields
This commit is contained in:
commit
2c93124fb1
@ -40,19 +40,14 @@ class UserFormFieldEditorExtension extends DataExtension {
|
|||||||
$fieldClasses = $this->getEditableFieldClasses();
|
$fieldClasses = $this->getEditableFieldClasses();
|
||||||
$editableColumns->setDisplayFields(array(
|
$editableColumns->setDisplayFields(array(
|
||||||
'ClassName' => function($record, $column, $grid) use ($fieldClasses) {
|
'ClassName' => function($record, $column, $grid) use ($fieldClasses) {
|
||||||
if($record instanceof EditableFormStep) {
|
if($record instanceof EditableFormField) {
|
||||||
return new LabelField($column, _t('UserFormFieldEditorExtension.PAGE_BREAK', 'Page Break'));
|
return $record->getInlineClassnameField($column, $fieldClasses);
|
||||||
} elseif($record instanceof EditableFieldGroup) {
|
|
||||||
return new LabelField($column, _t('UserFormFieldEditorExtension.FIELD_GROUP_START', 'Field Group (start)'));
|
|
||||||
} else if($record instanceof EditableFieldGroupEnd) {
|
|
||||||
return new LabelField($column, _t('UserFormFieldEditorExtension.FIELD_GROUP_END', 'Field Group (end)'));
|
|
||||||
} else {
|
|
||||||
return DropdownField::create($column, '', $fieldClasses);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Title' => function($record, $column, $grid) {
|
'Title' => function($record, $column, $grid) {
|
||||||
return TextField::create($column, ' ')
|
if($record instanceof EditableFormField) {
|
||||||
->setAttribute('placeholder', _t('UserDefinedForm.TITLE', 'Title'));
|
return $record->getInlineTitleField($column);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
|
47
code/formfields/UserFormsCompositeField.php
Normal file
47
code/formfields/UserFormsCompositeField.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a composite field group, which may contain other groups
|
||||||
|
*/
|
||||||
|
abstract class UserFormsCompositeField extends CompositeField implements UserFormsFieldContainer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent field
|
||||||
|
*
|
||||||
|
* @var UserFormsFieldContainer
|
||||||
|
*/
|
||||||
|
protected $parent = null;
|
||||||
|
|
||||||
|
public function getParent() {
|
||||||
|
return $this->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setParent(UserFormsFieldContainer $parent) {
|
||||||
|
$this->parent = $parent;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processNext(EditableFormField $field) {
|
||||||
|
// When we find a step, bubble up to the top
|
||||||
|
if($field instanceof EditableFormStep) {
|
||||||
|
return $this->getParent()->processNext($field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip over fields that don't generate formfields
|
||||||
|
$formField = $field->getFormField();
|
||||||
|
if(!$formField) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save this field
|
||||||
|
$this->push($formField);
|
||||||
|
|
||||||
|
// Nest fields that are containers
|
||||||
|
if($formField instanceof UserFormsFieldContainer) {
|
||||||
|
return $formField->setParent($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add any subsequent fields to this
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
30
code/formfields/UserFormsFieldContainer.php
Normal file
30
code/formfields/UserFormsFieldContainer.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a field container which can iteratively process nested fields, converting it into a fieldset
|
||||||
|
*/
|
||||||
|
interface UserFormsFieldContainer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the next field in the list, returning the container to add the next field to.
|
||||||
|
*
|
||||||
|
* @param EditableFormField $field
|
||||||
|
* @return EditableContainerField
|
||||||
|
*/
|
||||||
|
public function processNext(EditableFormField $field);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the parent
|
||||||
|
*
|
||||||
|
* @param UserFormsFieldContainer $parent
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setParent(UserFormsFieldContainer $parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the parent
|
||||||
|
*
|
||||||
|
* @return UserFormsFieldContainer
|
||||||
|
*/
|
||||||
|
public function getParent();
|
||||||
|
}
|
32
code/formfields/UserFormsFieldList.php
Normal file
32
code/formfields/UserFormsFieldList.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of formfields which allows for iterative processing of nested composite fields
|
||||||
|
*/
|
||||||
|
class UserFormsFieldList extends FieldList implements UserFormsFieldContainer {
|
||||||
|
|
||||||
|
public function processNext(EditableFormField $field) {
|
||||||
|
$formField = $field->getFormField();
|
||||||
|
if(!$formField) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->push($formField);
|
||||||
|
|
||||||
|
if($formField instanceof UserFormsFieldContainer) {
|
||||||
|
return $formField->setParent($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParent() {
|
||||||
|
// Field list does not have a parent
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setParent(UserFormsFieldContainer $parent) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
code/formfields/UserFormsGroupField.php
Normal file
27
code/formfields/UserFormsGroupField.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Front end composite field for userforms
|
||||||
|
*/
|
||||||
|
class UserFormsGroupField extends UserFormsCompositeField {
|
||||||
|
|
||||||
|
public function __construct($children = null) {
|
||||||
|
parent::__construct($children);
|
||||||
|
$this->setTag('fieldset');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLegend() {
|
||||||
|
// Legend defaults to title
|
||||||
|
return parent::getLegend() ?: $this->Title();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processNext(EditableFormField $field) {
|
||||||
|
// When ending a group, jump up one level
|
||||||
|
if($field instanceof EditableFieldGroupEnd) {
|
||||||
|
return $this->getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise behave as per normal composite field
|
||||||
|
return parent::processNext($field);
|
||||||
|
}
|
||||||
|
}
|
7
code/formfields/UserFormsStepField.php
Normal file
7
code/formfields/UserFormsStepField.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a page step in a form, which may contain form fields or other groups
|
||||||
|
*/
|
||||||
|
class UserFormsStepField extends UserFormsCompositeField {
|
||||||
|
}
|
@ -75,31 +75,11 @@ class UserForm extends Form {
|
|||||||
* @return FieldList
|
* @return FieldList
|
||||||
*/
|
*/
|
||||||
public function getFormFields() {
|
public function getFormFields() {
|
||||||
$fields = new FieldList();
|
$fields = new UserFormsFieldList();
|
||||||
$emptyStep = null; // Last empty step, which may or may not later have children
|
$target = $fields;
|
||||||
|
|
||||||
foreach ($this->controller->Fields() as $field) {
|
foreach ($this->controller->Fields() as $field) {
|
||||||
// When we encounter a step, save it
|
$target = $target->processNext($field);
|
||||||
if ($field instanceof EditableFormStep) {
|
|
||||||
$emptyStep = $field->getFormField();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the last field is a step
|
|
||||||
if($emptyStep) {
|
|
||||||
// When we reach the first non-step field, any empty step will no longer be empty
|
|
||||||
$fields->push($emptyStep);
|
|
||||||
$emptyStep = null;
|
|
||||||
|
|
||||||
} elseif(! $fields->last()) {
|
|
||||||
// If no steps have been saved yet, warn
|
|
||||||
trigger_error('Missing first step in form', E_USER_WARNING);
|
|
||||||
$fields->push(singleton('EditableFormStep')->getFormField());
|
|
||||||
}
|
|
||||||
|
|
||||||
$fields->last()->push($field->getFormField());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->extend('updateFormFields', $fields);
|
$this->extend('updateFormFields', $fields);
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
@ -12,5 +12,42 @@ class EditableFieldGroup extends EditableFormField {
|
|||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private static $hidden = true;
|
private static $hidden = true;
|
||||||
|
|
||||||
|
public function getCMSFields() {
|
||||||
|
$fields = parent::getCMSFields();
|
||||||
|
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'DisplayRules'));
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInlineClassnameField($column, $fieldClasses) {
|
||||||
|
return new LabelField(
|
||||||
|
$column,
|
||||||
|
_t('EditableFieldGroup.FIELD_GROUP_START', 'Field Group (start)')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showInReports() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormField() {
|
||||||
|
$field = UserFormsGroupField::create()
|
||||||
|
->setTitle($this->EscapedTitle ?: false);
|
||||||
|
$this->doUpdateFormField($field);
|
||||||
|
return $field;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function updateFormField($field) {
|
||||||
|
// set the right title on this field
|
||||||
|
if($this->RightTitle) {
|
||||||
|
// Since this field expects raw html, safely escape the user data prior
|
||||||
|
$field->setRightTitle(Convert::raw2xml($this->RightTitle));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this field has an extra class
|
||||||
|
if($field->ExtraClass) {
|
||||||
|
$field->addExtraClass($field->ExtraClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,5 +12,34 @@ class EditableFieldGroupEnd extends EditableFormField {
|
|||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private static $hidden = true;
|
private static $hidden = true;
|
||||||
|
|
||||||
|
public function getCMSFields() {
|
||||||
|
$fields = parent::getCMSFields();
|
||||||
|
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'DisplayRules'));
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInlineClassnameField($column, $fieldClasses) {
|
||||||
|
return new LabelField(
|
||||||
|
$column,
|
||||||
|
_t('EditableFieldGroupEnd.FIELD_GROUP_END', 'Field Group (end)')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInlineTitleField($column) {
|
||||||
|
return HiddenField::create($column);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormField() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showInReports() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canEdit($member = null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -624,4 +624,27 @@ class EditableFormField extends DataObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the formfield to use when editing this inline in gridfield
|
||||||
|
*
|
||||||
|
* @param string $column name of column
|
||||||
|
* @param array $fieldClasses List of allowed classnames if this formfield has a selectable class
|
||||||
|
* @return FormField
|
||||||
|
*/
|
||||||
|
public function getInlineClassnameField($column, $fieldClasses) {
|
||||||
|
return DropdownField::create($column, false, $fieldClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the formfield to use when editing the title inline
|
||||||
|
*
|
||||||
|
* @param string $column
|
||||||
|
* @return FormField
|
||||||
|
*/
|
||||||
|
public function getInlineTitleField($column) {
|
||||||
|
return TextField::create($column, false)
|
||||||
|
->setAttribute('placeholder', _t('EditableFormField.TITLE', 'Title'))
|
||||||
|
->setAttribute('data-placeholder', _t('EditableFormField.TITLE', 'Title'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,7 @@ class EditableFormStep extends EditableFormField {
|
|||||||
public function getCMSFields() {
|
public function getCMSFields() {
|
||||||
$fields = parent::getCMSFields();
|
$fields = parent::getCMSFields();
|
||||||
|
|
||||||
$fields->removeByName('MergeField');
|
$fields->removeByName(array('MergeField', 'Default', 'Validation', 'DisplayRules'));
|
||||||
$fields->removeByName('Default');
|
|
||||||
$fields->removeByName('Validation');
|
|
||||||
$fields->removeByName('CustomRules');
|
|
||||||
|
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
@ -44,7 +41,7 @@ class EditableFormStep extends EditableFormField {
|
|||||||
* @return FormField
|
* @return FormField
|
||||||
*/
|
*/
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
$field = CompositeField::create()
|
$field = UserFormsStepField::create()
|
||||||
->setTitle($this->EscapedTitle);
|
->setTitle($this->EscapedTitle);
|
||||||
$this->doUpdateFormField($field);
|
$this->doUpdateFormField($field);
|
||||||
return $field;
|
return $field;
|
||||||
@ -63,4 +60,11 @@ class EditableFormStep extends EditableFormField {
|
|||||||
public function showInReports() {
|
public function showInReports() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getInlineClassnameField($column, $fieldClasses) {
|
||||||
|
return new LabelField(
|
||||||
|
$column,
|
||||||
|
_t('EditableFieldGroupEnd.PAGE_BREAK', 'Page Break')
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user