mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 17:05:42 +02:00
Merge branch 'master' of git://github.com/silverstripe/silverstripe-userforms into issue69
This commit is contained in:
commit
41b6e57e4c
@ -8,37 +8,51 @@
|
|||||||
|
|
||||||
class FieldEditor extends FormField {
|
class FieldEditor extends FormField {
|
||||||
|
|
||||||
|
private static $url_handlers = array(
|
||||||
|
'$Action!/$ID' => '$Action'
|
||||||
|
);
|
||||||
|
|
||||||
private static $allowed_actions = array(
|
private static $allowed_actions = array(
|
||||||
'addfield',
|
'addfield',
|
||||||
'addoptionfield'
|
'addoptionfield',
|
||||||
|
'handleField'
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Field Editor Template
|
* @param array $properties
|
||||||
*
|
*
|
||||||
* @return String
|
* @return HTML
|
||||||
*/
|
*/
|
||||||
public function FieldHolder($properties = array()) {
|
public function FieldHolder($properties = array()) {
|
||||||
$this->setAttribute('data-add-url', '\''.Controller::join_links($this->Link('addfield')).'\'');
|
$add = Controller::join_links($this->Link('addfield'));
|
||||||
|
|
||||||
|
$this->setAttribute('data-add-url', '\''. $add.'\'');
|
||||||
|
|
||||||
return $this->renderWith("FieldEditor");
|
return $this->renderWith("FieldEditor");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a user can edit the form
|
* Returns whether a user can edit the form.
|
||||||
|
*
|
||||||
|
* @param Member $member
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function canEdit($member = null) {
|
public function canEdit($member = null) {
|
||||||
if($this->readonly) return false;
|
if($this->readonly) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->form->getRecord()->canEdit();
|
return $this->form->getRecord()->canEdit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a user delete a field in the form. The {@link EditableFormField}s
|
* Returns whether a user delete a field in the form. The
|
||||||
* check if they can delete themselves but this counts as an {@link self::canEdit()}
|
* {@link EditableFormField} instances check if they can delete themselves
|
||||||
* function rather than a delete
|
* but this counts as an {@link self::canEdit()} function rather than a
|
||||||
|
* delete.
|
||||||
*
|
*
|
||||||
|
* @param Member $member
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function canDelete($member = null) {
|
public function canDelete($member = null) {
|
||||||
@ -56,20 +70,24 @@ class FieldEditor extends FormField {
|
|||||||
$clone = clone $this;
|
$clone = clone $this;
|
||||||
$clone->readonly = true;
|
$clone->readonly = true;
|
||||||
$fields = $clone->Fields();
|
$fields = $clone->Fields();
|
||||||
if($fields) foreach($fields as $field) {
|
|
||||||
$field->setReadonly();
|
if($fields) {
|
||||||
|
foreach($fields as $field) {
|
||||||
|
$field->setReadonly();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $clone->customise(array('Fields' => $fields));
|
return $clone->customise(array(
|
||||||
|
'Fields' => $fields
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the fields for the user forms
|
* Return the fields.
|
||||||
*
|
*
|
||||||
* @return DataObjectSet
|
* @return RelationList
|
||||||
*/
|
*/
|
||||||
public function Fields() {
|
public function Fields() {
|
||||||
// Don't return any fields unless we actually have the dependent parameters set on the form field
|
|
||||||
if($this->form && $this->form->getRecord() && $this->name) {
|
if($this->form && $this->form->getRecord() && $this->name) {
|
||||||
$relationName = $this->name;
|
$relationName = $this->name;
|
||||||
$fields = $this->form->getRecord()->getComponents($relationName);
|
$fields = $this->form->getRecord()->getComponents($relationName);
|
||||||
@ -88,10 +106,10 @@ class FieldEditor extends FormField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a DataObjectSet of all the addable fields to populate
|
* Return a {@link ArrayList} of all the addable fields to populate the add
|
||||||
* the add field menu
|
* field menu.
|
||||||
*
|
*
|
||||||
* @return DataObjectSet
|
* @return ArrayList
|
||||||
*/
|
*/
|
||||||
public function CreatableFields() {
|
public function CreatableFields() {
|
||||||
$fields = ClassInfo::subclassesFor('EditableFormField');
|
$fields = ClassInfo::subclassesFor('EditableFormField');
|
||||||
@ -99,13 +117,16 @@ class FieldEditor extends FormField {
|
|||||||
if($fields) {
|
if($fields) {
|
||||||
array_shift($fields); // get rid of subclass 0
|
array_shift($fields); // get rid of subclass 0
|
||||||
asort($fields); // get in order
|
asort($fields); // get in order
|
||||||
|
|
||||||
$output = new ArrayList();
|
$output = new ArrayList();
|
||||||
|
|
||||||
foreach($fields as $field => $title) {
|
foreach($fields as $field => $title) {
|
||||||
// get the nice title and strip out field
|
// get the nice title and strip out field
|
||||||
$niceTitle = _t(
|
$niceTitle = _t(
|
||||||
$field.'.SINGULARNAME',
|
$field.'.SINGULARNAME',
|
||||||
$title
|
$title
|
||||||
);
|
);
|
||||||
|
|
||||||
if($niceTitle) {
|
if($niceTitle) {
|
||||||
$output->push(new ArrayData(array(
|
$output->push(new ArrayData(array(
|
||||||
'ClassName' => $field,
|
'ClassName' => $field,
|
||||||
@ -113,16 +134,18 @@ class FieldEditor extends FormField {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles saving the page. Needs to keep an eye on fields
|
* Handles saving the page. Needs to keep an eye on fields and options which
|
||||||
* and options which have been removed / added
|
* have been removed / added
|
||||||
*
|
*
|
||||||
* @param DataObject Record to Save it In
|
* @param DataObject $record
|
||||||
*/
|
*/
|
||||||
public function saveInto(DataObjectInterface $record) {
|
public function saveInto(DataObjectInterface $record) {
|
||||||
$name = $this->name;
|
$name = $this->name;
|
||||||
@ -166,15 +189,15 @@ class FieldEditor extends FormField {
|
|||||||
if($this->canEdit()) {
|
if($this->canEdit()) {
|
||||||
foreach($missingFields as $removedField) {
|
foreach($missingFields as $removedField) {
|
||||||
if(is_numeric($removedField->ID)) {
|
if(is_numeric($removedField->ID)) {
|
||||||
// check we can edit this
|
// check we can edit this
|
||||||
$removedField->delete();
|
$removedField->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a field to the field editor. Called via a ajax get request from the userdefinedform javascript
|
* Add a field to the field editor. Called via a ajax get.
|
||||||
*
|
*
|
||||||
* @return bool|html
|
* @return bool|html
|
||||||
*/
|
*/
|
||||||
@ -257,4 +280,46 @@ class FieldEditor extends FormField {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass sub {@link FormField} requests through the editor. For example,
|
||||||
|
* option fields need to be able to call themselves.
|
||||||
|
*
|
||||||
|
* @param SS_HTTPRequest
|
||||||
|
*/
|
||||||
|
public function handleField(SS_HTTPRequest $request) {
|
||||||
|
if(!SecurityToken::inst()->checkRequest($this->request)) {
|
||||||
|
return $this->httpError(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields = $this->Fields();
|
||||||
|
|
||||||
|
// extract the ID and option field name
|
||||||
|
preg_match(
|
||||||
|
'/Fields\[(?P<ID>\d+)\]\[CustomSettings\]\[(?P<Option>\w+)\]/',
|
||||||
|
$request->param('ID'), $matches
|
||||||
|
);
|
||||||
|
|
||||||
|
if(isset($matches['ID']) && isset($matches['Option'])) {
|
||||||
|
foreach($fields as $field) {
|
||||||
|
$formField = $field->getFormField();
|
||||||
|
|
||||||
|
if($matches['ID'] == $field->ID) {
|
||||||
|
if($field->canEdit()) {
|
||||||
|
// find the option to handle
|
||||||
|
$options = $field->getFieldConfiguration();
|
||||||
|
$optionField = $options->fieldByName($request->param('ID'));
|
||||||
|
|
||||||
|
if($optionField) {
|
||||||
|
return $optionField->handleRequest($request, $optionField);
|
||||||
|
} else {
|
||||||
|
return $this->httpError(404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->httpError(403);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
20
code/formfields/UserformsTreeDropdownField.php
Normal file
20
code/formfields/UserformsTreeDropdownField.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link TreeDropdownField} subclass for handling loading folders through the
|
||||||
|
* nested {@link FormField} instances of the {@link FieldEditor}
|
||||||
|
*
|
||||||
|
* @package userforms
|
||||||
|
*/
|
||||||
|
class UserformsTreeDropdownField extends TreeDropdownField {
|
||||||
|
|
||||||
|
public function Link($action = null) {
|
||||||
|
$form = Controller::curr()->EditForm;
|
||||||
|
|
||||||
|
return Controller::join_links(
|
||||||
|
$form->FormAction(), 'field/Fields/handleField/' . $this->name,
|
||||||
|
$action .
|
||||||
|
'?SecurityID='. $form->getSecurityToken()->getValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -939,13 +939,14 @@ JS
|
|||||||
if(!empty($data[$field->Name])){
|
if(!empty($data[$field->Name])){
|
||||||
if(in_array("EditableFileField", $field->getClassAncestry())) {
|
if(in_array("EditableFileField", $field->getClassAncestry())) {
|
||||||
if(isset($_FILES[$field->Name])) {
|
if(isset($_FILES[$field->Name])) {
|
||||||
|
$foldername = $field->getFormField()->getFolderName();
|
||||||
|
|
||||||
// create the file from post data
|
// create the file from post data
|
||||||
$upload = new Upload();
|
$upload = new Upload();
|
||||||
$file = new File();
|
$file = new File();
|
||||||
$file->ShowInSearch = 0;
|
$file->ShowInSearch = 0;
|
||||||
try {
|
try {
|
||||||
$upload->loadIntoFile($_FILES[$field->Name], $file);
|
$upload->loadIntoFile($_FILES[$field->Name], $file, $foldername);
|
||||||
} catch( ValidationException $e ) {
|
} catch( ValidationException $e ) {
|
||||||
$validationResult = $e->getResult();
|
$validationResult = $e->getResult();
|
||||||
$form->addErrorMessage($field->Name, $validationResult->message(), 'bad');
|
$form->addErrorMessage($field->Name, $validationResult->message(), 'bad');
|
||||||
|
@ -12,9 +12,36 @@ class EditableFileField extends EditableFormField {
|
|||||||
|
|
||||||
private static $plural_names = 'File Fields';
|
private static $plural_names = 'File Fields';
|
||||||
|
|
||||||
|
public function getFieldConfiguration() {
|
||||||
|
$field = parent::getFieldConfiguration();
|
||||||
|
$folder = ($this->getSetting('Folder')) ? $this->getSetting('Folder') : null;
|
||||||
|
|
||||||
|
$tree = UserformsTreeDropdownField::create(
|
||||||
|
$this->getSettingName("Folder"),
|
||||||
|
_t('EditableUploadField.SELECTUPLOADFOLDER', 'Select upload folder'),
|
||||||
|
"Folder"
|
||||||
|
);
|
||||||
|
|
||||||
|
$tree->setValue($folder);
|
||||||
|
|
||||||
|
$field->push($tree);
|
||||||
|
|
||||||
|
return $field;
|
||||||
|
}
|
||||||
|
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
$field = new FileField($this->Name, $this->Title);
|
$field = new FileField($this->Name, $this->Title);
|
||||||
|
|
||||||
|
if($this->getSetting('Folder')) {
|
||||||
|
$folder = Folder::get()->byId($this->getSetting('Folder'));
|
||||||
|
|
||||||
|
if($folder) {
|
||||||
|
$field->setFolderName(
|
||||||
|
preg_replace("/^assets\//","", $folder->Filename)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,12 @@
|
|||||||
|
|
||||||
class EditableFormFieldTest extends FunctionalTest {
|
class EditableFormFieldTest extends FunctionalTest {
|
||||||
|
|
||||||
static $fixture_file = 'userforms/tests/UserDefinedFormTest.yml';
|
static $fixture_file = 'userforms/tests/EditableFormFieldTest.yml';
|
||||||
|
|
||||||
protected $extraDataObjects = array(
|
protected $extraDataObjects = array(
|
||||||
'ExtendedEditableFormField',
|
'ExtendedEditableFormField',
|
||||||
'EditableFormFieldExtension'
|
'EditableFormFieldExtension'
|
||||||
);
|
);
|
||||||
|
|
||||||
function testFormFieldPermissions() {
|
function testFormFieldPermissions() {
|
||||||
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
||||||
|
135
tests/EditableFormFieldTest.yml
Normal file
135
tests/EditableFormFieldTest.yml
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
EditableOption:
|
||||||
|
option-1:
|
||||||
|
Name: Option1
|
||||||
|
Title: Option 1
|
||||||
|
|
||||||
|
option-2:
|
||||||
|
Name: Option2
|
||||||
|
Title: Option 2
|
||||||
|
|
||||||
|
department-1:
|
||||||
|
Name: dept1
|
||||||
|
Title: sales@example.com
|
||||||
|
|
||||||
|
department-2:
|
||||||
|
Name: dept2
|
||||||
|
Title: accounts@example.com
|
||||||
|
|
||||||
|
option-3:
|
||||||
|
Name: Option3
|
||||||
|
Title: Option 3
|
||||||
|
|
||||||
|
option-4:
|
||||||
|
Name: Option4
|
||||||
|
Title: Option 4
|
||||||
|
|
||||||
|
option-5:
|
||||||
|
Name: Option5
|
||||||
|
Title: Option 5
|
||||||
|
|
||||||
|
option-6:
|
||||||
|
Name: Option6
|
||||||
|
Title: Option 6
|
||||||
|
|
||||||
|
UserDefinedForm_EmailRecipient:
|
||||||
|
recipient-1:
|
||||||
|
EmailAddress: test@example.com
|
||||||
|
EmailSubject: Email Subject
|
||||||
|
EmailFrom: no-reply@example.com
|
||||||
|
|
||||||
|
no-html:
|
||||||
|
EmailAddress: nohtml@example.com
|
||||||
|
EmailSubject: Email Subject
|
||||||
|
EmailFrom: no-reply@example.com
|
||||||
|
SendPlain: true
|
||||||
|
|
||||||
|
no-data:
|
||||||
|
EmailAddress: nodata@example.com
|
||||||
|
EmailSubject: Email Subject
|
||||||
|
EmailFrom: no-reply@example.com
|
||||||
|
HideFormData: true
|
||||||
|
|
||||||
|
EditableTextField:
|
||||||
|
basic-text:
|
||||||
|
Name: basic-text-name
|
||||||
|
Title: Basic Text Field
|
||||||
|
|
||||||
|
basic-text-2:
|
||||||
|
Name: basic-text-name
|
||||||
|
Title: Basic Text Field
|
||||||
|
|
||||||
|
required-text:
|
||||||
|
Name: required-text-field
|
||||||
|
Title: Required Text Field
|
||||||
|
CustomErrorMessage: Custom Error Message
|
||||||
|
Required: true
|
||||||
|
|
||||||
|
EditableDropdown:
|
||||||
|
basic-dropdown:
|
||||||
|
Name: basic-dropdown
|
||||||
|
Title: Basic Dropdown Field
|
||||||
|
Options: =>EditableOption.option-1, =>EditableOption.option-2
|
||||||
|
|
||||||
|
department-dropdown:
|
||||||
|
Name: department
|
||||||
|
Title: Department
|
||||||
|
Options: =>EditableOption.department-1, =>EditableOption.department-2
|
||||||
|
|
||||||
|
EditableCheckbox:
|
||||||
|
checkbox-1:
|
||||||
|
Name: checkbox-1
|
||||||
|
Title: Checkbox 1
|
||||||
|
|
||||||
|
checkbox-2:
|
||||||
|
Name: checkbox-1
|
||||||
|
Title: Checkbox 1
|
||||||
|
|
||||||
|
EditableCheckboxGroupField:
|
||||||
|
checkbox-group:
|
||||||
|
Name: check-box-group
|
||||||
|
Title: Check box group
|
||||||
|
Options: =>EditableOption.option-3, =>EditableOption.option-4
|
||||||
|
|
||||||
|
EditableEmailField:
|
||||||
|
email-field:
|
||||||
|
Name: email-field
|
||||||
|
Title: Email
|
||||||
|
|
||||||
|
|
||||||
|
EditableRadioField:
|
||||||
|
radio-field:
|
||||||
|
Name: radio-option
|
||||||
|
Title: Radio Option
|
||||||
|
Options: =>EditableOption.option-5, =>EditableOption.option-6
|
||||||
|
|
||||||
|
|
||||||
|
ExtendedEditableFormField:
|
||||||
|
extended-field:
|
||||||
|
Name: extended-field
|
||||||
|
Title: Extended Field
|
||||||
|
TestExtraField: Extra Field
|
||||||
|
TestValidationField: Extra Validation Field
|
||||||
|
|
||||||
|
|
||||||
|
UserDefinedForm:
|
||||||
|
basic-form-page:
|
||||||
|
Title: User Defined Form
|
||||||
|
Fields: =>EditableTextField.basic-text
|
||||||
|
EmailRecipients: =>UserDefinedForm_EmailRecipient.recipient-1, =>UserDefinedForm_EmailRecipient.no-html, =>UserDefinedForm_EmailRecipient.no-data
|
||||||
|
|
||||||
|
form-with-reset-and-custom-action:
|
||||||
|
Title: Form with Reset Action
|
||||||
|
SubmitButtonText: Custom Button
|
||||||
|
ShowClearButton: true
|
||||||
|
|
||||||
|
validation-form:
|
||||||
|
Title: Validation Form
|
||||||
|
Fields: =>EditableTextField.required-text
|
||||||
|
|
||||||
|
custom-rules-form:
|
||||||
|
Title: Custom Rules Form
|
||||||
|
Fields: =>EditableCheckbox.checkbox-2, =>EditableTextField.basic-text-2
|
||||||
|
empty-form:
|
||||||
|
Title: Empty Form
|
||||||
|
|
||||||
|
|
@ -103,14 +103,6 @@ EditableRadioField:
|
|||||||
Options: =>EditableOption.option-5, =>EditableOption.option-6
|
Options: =>EditableOption.option-5, =>EditableOption.option-6
|
||||||
|
|
||||||
|
|
||||||
ExtendedEditableFormField:
|
|
||||||
extended-field:
|
|
||||||
Name: extended-field
|
|
||||||
Title: Extended Field
|
|
||||||
TestExtraField: Extra Field
|
|
||||||
TestValidationField: Extra Validation Field
|
|
||||||
|
|
||||||
|
|
||||||
UserDefinedForm:
|
UserDefinedForm:
|
||||||
basic-form-page:
|
basic-form-page:
|
||||||
Title: User Defined Form
|
Title: User Defined Form
|
||||||
|
Loading…
Reference in New Issue
Block a user