From ea7163f02efc9eae46f011cc1ebd126b1309a39e Mon Sep 17 00:00:00 2001 From: Kirk Mayo Date: Fri, 20 Dec 2013 14:23:13 +1300 Subject: [PATCH 1/2] BUG: Fixes #179 broken unit tests caused by tests not having classes for ExtendedEditableFormField --- tests/EditableFormFieldTest.php | 10 +-- tests/EditableFormFieldTest.yml | 135 ++++++++++++++++++++++++++++++++ tests/UserDefinedFormTest.yml | 8 -- 3 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 tests/EditableFormFieldTest.yml diff --git a/tests/EditableFormFieldTest.php b/tests/EditableFormFieldTest.php index faedfc7..6ff7004 100644 --- a/tests/EditableFormFieldTest.php +++ b/tests/EditableFormFieldTest.php @@ -6,12 +6,12 @@ class EditableFormFieldTest extends FunctionalTest { - static $fixture_file = 'userforms/tests/UserDefinedFormTest.yml'; + static $fixture_file = 'userforms/tests/EditableFormFieldTest.yml'; - protected $extraDataObjects = array( - 'ExtendedEditableFormField', - 'EditableFormFieldExtension' - ); + protected $extraDataObjects = array( + 'ExtendedEditableFormField', + 'EditableFormFieldExtension' + ); function testFormFieldPermissions() { $text = $this->objFromFixture('EditableTextField', 'basic-text'); diff --git a/tests/EditableFormFieldTest.yml b/tests/EditableFormFieldTest.yml new file mode 100644 index 0000000..5b82e25 --- /dev/null +++ b/tests/EditableFormFieldTest.yml @@ -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 + + diff --git a/tests/UserDefinedFormTest.yml b/tests/UserDefinedFormTest.yml index 5b82e25..7b95324 100644 --- a/tests/UserDefinedFormTest.yml +++ b/tests/UserDefinedFormTest.yml @@ -103,14 +103,6 @@ EditableRadioField: 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 From 07c159cd61f6fad3ded2093935ab1b37b025a616 Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Fri, 20 Dec 2013 21:07:35 +1300 Subject: [PATCH 2/2] NEW Allow EditableFileField to define destination folder. (Fixes #20, #177) --- code/formfields/FieldEditor.php | 115 ++++++++++++++---- .../formfields/UserformsTreeDropdownField.php | 20 +++ code/model/UserDefinedForm.php | 3 +- code/model/formfields/EditableFileField.php | 31 ++++- 4 files changed, 141 insertions(+), 28 deletions(-) create mode 100644 code/formfields/UserformsTreeDropdownField.php diff --git a/code/formfields/FieldEditor.php b/code/formfields/FieldEditor.php index 92d726f..97767a5 100755 --- a/code/formfields/FieldEditor.php +++ b/code/formfields/FieldEditor.php @@ -8,37 +8,51 @@ class FieldEditor extends FormField { + private static $url_handlers = array( + '$Action!/$ID' => '$Action' + ); + private static $allowed_actions = array( 'addfield', - 'addoptionfield' + 'addoptionfield', + 'handleField' ); /** - * Field Editor Template + * @param array $properties * - * @return String + * @return HTML */ 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"); } /** - * Returns whether a user can edit the form + * Returns whether a user can edit the form. + * + * @param Member $member * * @return boolean */ public function canEdit($member = null) { - if($this->readonly) return false; + if($this->readonly) { + return false; + } return $this->form->getRecord()->canEdit(); } /** - * Returns whether a user delete a field in the form. The {@link EditableFormField}s - * check if they can delete themselves but this counts as an {@link self::canEdit()} - * function rather than a delete + * Returns whether a user delete a field in the form. The + * {@link EditableFormField} instances check if they can delete themselves + * but this counts as an {@link self::canEdit()} function rather than a + * delete. * + * @param Member $member * @return boolean */ public function canDelete($member = null) { @@ -56,20 +70,24 @@ class FieldEditor extends FormField { $clone = clone $this; $clone->readonly = true; $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() { - // 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) { $relationName = $this->name; $fields = $this->form->getRecord()->getComponents($relationName); @@ -88,10 +106,10 @@ class FieldEditor extends FormField { } /** - * Return a DataObjectSet of all the addable fields to populate - * the add field menu + * Return a {@link ArrayList} of all the addable fields to populate the add + * field menu. * - * @return DataObjectSet + * @return ArrayList */ public function CreatableFields() { $fields = ClassInfo::subclassesFor('EditableFormField'); @@ -99,13 +117,16 @@ class FieldEditor extends FormField { if($fields) { array_shift($fields); // get rid of subclass 0 asort($fields); // get in order + $output = new ArrayList(); + foreach($fields as $field => $title) { // get the nice title and strip out field $niceTitle = _t( $field.'.SINGULARNAME', $title ); + if($niceTitle) { $output->push(new ArrayData(array( 'ClassName' => $field, @@ -113,16 +134,18 @@ class FieldEditor extends FormField { ))); } } + return $output; } + return false; } /** - * Handles saving the page. Needs to keep an eye on fields - * and options which have been removed / added + * Handles saving the page. Needs to keep an eye on fields and options which + * have been removed / added * - * @param DataObject Record to Save it In + * @param DataObject $record */ public function saveInto(DataObjectInterface $record) { $name = $this->name; @@ -166,15 +189,15 @@ class FieldEditor extends FormField { if($this->canEdit()) { foreach($missingFields as $removedField) { if(is_numeric($removedField->ID)) { - // check we can edit this - $removedField->delete(); - } + // check we can edit this + $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 */ @@ -257,4 +280,46 @@ class FieldEditor extends FormField { 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\d+)\]\[CustomSettings\]\[(?P