mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 15:05:42 +00:00
Replace the form editor with GridField
This commit is contained in:
parent
8f92d75975
commit
ae7dd98be3
@ -4,6 +4,5 @@ name: userforms
|
||||
LeftAndMain:
|
||||
extra_requirements_javascript:
|
||||
- userforms/javascript/UserForm.js
|
||||
|
||||
extra_requirements_css:
|
||||
- userforms/css/FieldEditor.css
|
||||
|
180
code/extensions/UserFormFieldEditorExtension.php
Normal file
180
code/extensions/UserFormFieldEditorExtension.php
Normal file
@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package userforms
|
||||
*/
|
||||
class UserFormFieldEditorExtension extends DataExtension {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $has_many = array(
|
||||
'Fields' => 'EditableFormField'
|
||||
);
|
||||
|
||||
/**
|
||||
* Adds the field editor to the page.
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
public function updateCMSFields(FieldList $fields) {
|
||||
$fieldEditor = $this->getFieldEditorGrid();
|
||||
|
||||
$fields->findOrMakeTab('Root.Form', _t('UserDefinedForm.FORM', 'Form'));
|
||||
$fields->addFieldToTab('Root.Form', $fieldEditor);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field editor, for adding and removing EditableFormFields.
|
||||
*
|
||||
* @return GridField
|
||||
*/
|
||||
public function getFieldEditorGrid() {
|
||||
$fieldEditor = GridField::create('Fields', _t('UserDefinedForm.FIELDS', 'Fields'), $this->owner->Fields());
|
||||
|
||||
$config = GridFieldConfig::create()
|
||||
->addComponents(
|
||||
(new GridFieldEditableColumns())
|
||||
->setDisplayFields(array(
|
||||
'ClassName' => function($record, $column, $grid) {
|
||||
return DropdownField::create($column, '', $this->getEditableFieldClasses());
|
||||
},
|
||||
'Title' => function($record, $column, $grid) {
|
||||
return TextField::create($column, ' ')
|
||||
->setAttribute('placeholder', _t('UserDefinedForm.TITLE', 'Title'));
|
||||
}
|
||||
)),
|
||||
new GridFieldButtonRow(),
|
||||
new GridFieldAddNewInlineButton(),
|
||||
new GridFieldEditButton(),
|
||||
new GridFieldDeleteAction(),
|
||||
new GridFieldToolbarHeader(),
|
||||
new GridFieldOrderableRows('Sort'),
|
||||
new GridState_Component(),
|
||||
new GridFieldDetailForm()
|
||||
);
|
||||
|
||||
$fieldEditor->setConfig($config);
|
||||
|
||||
return $fieldEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getEditableFieldClasses() {
|
||||
$classes = ClassInfo::getValidSubClasses('EditableFormField');
|
||||
|
||||
// Remove classes we don't want to display in the dropdown.
|
||||
$classes = array_diff($classes, array(
|
||||
'EditableFormField',
|
||||
'EditableMultipleOptionField'
|
||||
));
|
||||
|
||||
$editableFieldClasses = array();
|
||||
|
||||
foreach ($classes as $key => $className) {
|
||||
$singleton = singleton($className);
|
||||
|
||||
if(!$singleton->canCreate()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$editableFieldClasses[$className] = $singleton->i18n_singular_name();
|
||||
}
|
||||
|
||||
return $editableFieldClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SiteTree::doPublish
|
||||
* @param Page $original
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onAfterPublish($original) {
|
||||
// Remove fields on the live table which could have been orphaned.
|
||||
$live = Versioned::get_by_stage("EditableFormField", "Live", array(
|
||||
'ParentID' => $original->ID
|
||||
));
|
||||
|
||||
if($live) {
|
||||
foreach($live as $field) {
|
||||
$field->doDeleteFromStage('Live');
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->owner->Fields() as $field) {
|
||||
$field->doPublish('Stage', 'Live');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SiteTree::doUnpublish
|
||||
* @param Page $page
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onAfterUnpublish($page) {
|
||||
foreach($page->Fields() as $field) {
|
||||
$field->doDeleteFromStage('Live');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SiteTree::duplicate
|
||||
* @param DataObject $newPage
|
||||
*
|
||||
* @return DataObject
|
||||
*/
|
||||
public function onAfterDuplicate($newPage) {
|
||||
foreach($this->owner->Fields() as $field) {
|
||||
$newField = $field->duplicate();
|
||||
$newField->ParentID = $newPage->ID;
|
||||
$newField->ParentClass = $newPage->ClassName;
|
||||
$newField->write();
|
||||
|
||||
foreach ($field->CustomRules() as $customRule) {
|
||||
$newRule = $customRule->duplicate();
|
||||
$newRule->ParentID = $newField->ID;
|
||||
$newRule->write();
|
||||
}
|
||||
}
|
||||
|
||||
return $newPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SiteTree::getIsModifiedOnStage
|
||||
* @param boolean $isModified
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function getIsModifiedOnStage($isModified) {
|
||||
if(!$isModified) {
|
||||
foreach($this->owner->Fields() as $field) {
|
||||
if($field->getIsModifiedOnStage()) {
|
||||
$isModified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $isModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SiteTree::doRevertToLive
|
||||
* @param Page $page
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onAfterRevertToLive($page) {
|
||||
foreach($page->Fields() as $field) {
|
||||
$field->publish('Live', 'Stage', false);
|
||||
$field->writeWithoutVersion();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,338 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* A form field allowing a user to customize and create form fields.
|
||||
* for saving into a {@link UserDefinedForm}
|
||||
*
|
||||
* @package userforms
|
||||
*/
|
||||
|
||||
class FieldEditor extends FormField {
|
||||
|
||||
private static $url_handlers = array(
|
||||
'$Action!/$ID' => '$Action'
|
||||
);
|
||||
|
||||
private static $allowed_actions = array(
|
||||
'addfield',
|
||||
'addoptionfield',
|
||||
'handleField'
|
||||
);
|
||||
|
||||
/**
|
||||
* @param array $properties
|
||||
*
|
||||
* @return HTML
|
||||
*/
|
||||
public function FieldHolder($properties = array()) {
|
||||
$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.
|
||||
*
|
||||
* @param Member $member
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canEdit($member = null) {
|
||||
if($this->readonly) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->form->getRecord()->canEdit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if($this->readonly) return false;
|
||||
|
||||
return $this->form->getRecord()->canEdit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform this form field to a readonly version.
|
||||
*
|
||||
* @return ViewableData_Customised
|
||||
*/
|
||||
public function performReadonlyTransformation() {
|
||||
$clone = clone $this;
|
||||
$clone->readonly = true;
|
||||
$fields = $clone->Fields();
|
||||
|
||||
if($fields) {
|
||||
foreach($fields as $field) {
|
||||
$field->setReadonly();
|
||||
}
|
||||
}
|
||||
|
||||
return $clone->customise(array(
|
||||
'Fields' => $fields
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the fields.
|
||||
*
|
||||
* @return RelationList
|
||||
*/
|
||||
public function Fields() {
|
||||
if($this->form && $this->form->getRecord() && $this->name) {
|
||||
$relationName = $this->name;
|
||||
$fields = $this->form->getRecord()->getComponents($relationName);
|
||||
|
||||
if($fields) {
|
||||
foreach($fields as $field) {
|
||||
if(!$this->canEdit() && is_a($field, 'FormField')) {
|
||||
$fields->remove($field);
|
||||
$fields->push($field->performReadonlyTransformation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link ArrayList} of all the addable fields to populate the add
|
||||
* field menu.
|
||||
*
|
||||
* @return ArrayList
|
||||
*/
|
||||
public function CreatableFields() {
|
||||
$fields = ClassInfo::subclassesFor('EditableFormField');
|
||||
|
||||
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 && $field != "EditableMultipleOptionField") {
|
||||
$output->push(new ArrayData(array(
|
||||
'ClassName' => $field,
|
||||
'Title' => "$niceTitle"
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles saving the page. Needs to keep an eye on fields and options which
|
||||
* have been removed / added
|
||||
*
|
||||
* @param DataObject $record
|
||||
*/
|
||||
public function saveInto(DataObjectInterface $record) {
|
||||
$name = $this->name;
|
||||
$fieldSet = $record->$name();
|
||||
|
||||
// store the field IDs and delete the missing fields
|
||||
// alternatively, we could delete all the fields and re add them
|
||||
$missingFields = array();
|
||||
|
||||
foreach($fieldSet as $existingField) {
|
||||
$missingFields[$existingField->ID] = $existingField;
|
||||
}
|
||||
|
||||
if(isset($_REQUEST[$name]) && is_array($_REQUEST[$name])) {
|
||||
foreach($_REQUEST[$name] as $newEditableID => $newEditableData) {
|
||||
if(!is_numeric($newEditableID)) continue;
|
||||
|
||||
// get it from the db
|
||||
$editable = DataObject::get_by_id('EditableFormField', $newEditableID);
|
||||
|
||||
// if it exists in the db update it
|
||||
if($editable) {
|
||||
|
||||
// remove it from the removed fields list
|
||||
if(isset($missingFields[$editable->ID]) && isset($newEditableData) && is_array($newEditableData)) {
|
||||
unset($missingFields[$editable->ID]);
|
||||
}
|
||||
|
||||
// set form id
|
||||
if($editable->ParentID == 0) {
|
||||
$editable->ParentID = $record->ID;
|
||||
}
|
||||
|
||||
// save data
|
||||
$editable->populateFromPostData($newEditableData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the fields not saved
|
||||
if($this->canEdit()) {
|
||||
foreach($missingFields as $removedField) {
|
||||
if(is_numeric($removedField->ID)) {
|
||||
// check we can edit this
|
||||
$removedField->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to the field editor. Called via a ajax get.
|
||||
*
|
||||
* @return bool|html
|
||||
*/
|
||||
public function addfield() {
|
||||
if(!SecurityToken::inst()->checkRequest($this->request)) {
|
||||
return $this->httpError(400);
|
||||
}
|
||||
|
||||
// get the last field in this form editor
|
||||
$parentID = $this->form->getRecord()->ID;
|
||||
|
||||
if($parentID) {
|
||||
$parentID = (int)$parentID;
|
||||
|
||||
$sqlQuery = new SQLQuery();
|
||||
$sqlQuery = $sqlQuery
|
||||
->setSelect("MAX(\"Sort\")")
|
||||
->setFrom("\"EditableFormField\"")
|
||||
->setWhere("\"ParentID\" = $parentID");
|
||||
|
||||
$sort = $sqlQuery->execute()->value() + 1;
|
||||
|
||||
$className = (isset($_REQUEST['Type'])) ? $_REQUEST['Type'] : '';
|
||||
|
||||
if(!$className) {
|
||||
// A possible reason for the classname being blank is because we have execeded
|
||||
// the number of input requests
|
||||
// http://www.php.net/manual/en/info.configuration.php#ini.max-input-vars
|
||||
$maxRequests = ini_get('max_input_vars');
|
||||
$numRequests = count($_REQUEST, COUNT_RECURSIVE);
|
||||
if ($numRequests > $maxRequests) {
|
||||
$error = sprintf('You have exceded the maximum number %s of input requests',
|
||||
"[$maxRequests]");
|
||||
user_error($error, E_USER_WARNING);
|
||||
}
|
||||
user_error('Please select a field type to created', E_USER_WARNING);
|
||||
}
|
||||
|
||||
if(is_subclass_of($className, "EditableFormField")) {
|
||||
$field = new $className();
|
||||
$field->ParentID = $this->form->getRecord()->ID;
|
||||
$field->Name = $field->class . $field->ID;
|
||||
$field->Sort = $sort;
|
||||
$field->write();
|
||||
|
||||
return $field->EditSegment();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the html for a field option such as a
|
||||
* dropdown field or a radio check box field
|
||||
*
|
||||
* @return bool|html
|
||||
*/
|
||||
public function addoptionfield() {
|
||||
if(!SecurityToken::inst()->checkRequest($this->request)) {
|
||||
return $this->httpError(400);
|
||||
}
|
||||
|
||||
// passed via the ajax
|
||||
$parent = (isset($_REQUEST['Parent'])) ? $_REQUEST['Parent'] : false;
|
||||
|
||||
// work out the sort by getting the sort of the last field in the form +1
|
||||
if($parent) {
|
||||
$sql_parent = (int)$parent;
|
||||
|
||||
$parentObj = EditableFormField::get()->byID($parent);
|
||||
$optionClass = ($parentObj && $parentObj->exists()) ? $parentObj->getRelationClass('Options') : 'EditableOption';
|
||||
|
||||
$sqlQuery = new SQLQuery();
|
||||
$sqlQuery = $sqlQuery
|
||||
->setSelect("MAX(\"Sort\")")
|
||||
->setFrom("\"EditableOption\"")
|
||||
->setWhere("\"ParentID\" = $sql_parent");
|
||||
|
||||
$sort = $sqlQuery->execute()->value() + 1;
|
||||
|
||||
if($parent) {
|
||||
$object = Injector::inst()->create($optionClass);
|
||||
$object->write();
|
||||
$object->ParentID = $parent;
|
||||
$object->Sort = $sort;
|
||||
$object->Name = 'option' . $object->ID;
|
||||
$object->write();
|
||||
|
||||
return $object->EditSegment();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
158
code/forms/UserForm.php
Normal file
158
code/forms/UserForm.php
Normal file
@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package userforms
|
||||
*/
|
||||
class UserForm extends Form {
|
||||
|
||||
/**
|
||||
* @param Controller $controller
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(Controller $controller, $name = 'Form') {
|
||||
|
||||
$this->controller = $controller;
|
||||
$this->setRedirectToFormOnValidationError(true);
|
||||
|
||||
parent::__construct(
|
||||
$controller,
|
||||
$name,
|
||||
$this->getFormFields(),
|
||||
$this->getFormActions(),
|
||||
$this->getRequiredFields()
|
||||
);
|
||||
|
||||
if($controller->DisableCsrfSecurityToken) {
|
||||
$this->disableSecurityToken();
|
||||
}
|
||||
|
||||
$data = Session::get("FormInfo.{$this->FormName()}.data");
|
||||
|
||||
if(is_array($data)) {
|
||||
$this->loadDataFrom($data);
|
||||
}
|
||||
|
||||
$this->extend('updateForm');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the form fields for the form on this page. Can modify this FieldSet
|
||||
* by using {@link updateFormFields()} on an {@link Extension} subclass which
|
||||
* is applied to this controller.
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getFormFields() {
|
||||
$fields = new FieldList();
|
||||
|
||||
foreach($this->controller->Fields() as $editableField) {
|
||||
// get the raw form field from the editable version
|
||||
$field = $editableField->getFormField();
|
||||
|
||||
if(!$field) continue;
|
||||
|
||||
// set the error / formatting messages
|
||||
$field->setCustomValidationMessage($editableField->getErrorMessage());
|
||||
|
||||
// set the right title on this field
|
||||
if($right = $editableField->getSetting('RightTitle')) {
|
||||
// Since this field expects raw html, safely escape the user data prior
|
||||
$field->setRightTitle(Convert::raw2xml($right));
|
||||
}
|
||||
|
||||
// if this field is required add some
|
||||
if($editableField->Required) {
|
||||
$field->addExtraClass('requiredField');
|
||||
|
||||
if($identifier = UserDefinedForm::config()->required_identifier) {
|
||||
|
||||
$title = $field->Title() ." <span class='required-identifier'>". $identifier . "</span>";
|
||||
$field->setTitle($title);
|
||||
}
|
||||
}
|
||||
// if this field has an extra class
|
||||
if($extraClass = $editableField->getSetting('ExtraClass')) {
|
||||
$field->addExtraClass(Convert::raw2att($extraClass));
|
||||
}
|
||||
|
||||
// set the values passed by the url to the field
|
||||
$request = $this->controller->getRequest();
|
||||
if($value = $request->getVar($field->getName())) {
|
||||
$field->setValue($value);
|
||||
}
|
||||
|
||||
$fields->push($field);
|
||||
}
|
||||
|
||||
$this->extend('updateFormFields', $fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the form actions for the UserDefinedForm. You
|
||||
* can manipulate these by using {@link updateFormActions()} on
|
||||
* a decorator.
|
||||
*
|
||||
* @todo Make form actions editable via their own field editor.
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getFormActions() {
|
||||
$submitText = ($this->controller->SubmitButtonText) ? $this->controller->SubmitButtonText : _t('UserDefinedForm.SUBMITBUTTON', 'Submit');
|
||||
$clearText = ($this->controller->ClearButtonText) ? $this->controller->ClearButtonText : _t('UserDefinedForm.CLEARBUTTON', 'Clear');
|
||||
|
||||
$actions = new FieldList(
|
||||
new FormAction("process", $submitText)
|
||||
);
|
||||
|
||||
if($this->controller->ShowClearButton) {
|
||||
$actions->push(new ResetFormAction("clearForm", $clearText));
|
||||
}
|
||||
|
||||
$this->extend('updateFormActions', $actions);
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the required form fields for this form.
|
||||
*
|
||||
* @return RequiredFields
|
||||
*/
|
||||
public function getRequiredFields() {
|
||||
// Generate required field validator
|
||||
$requiredNames = $this
|
||||
->controller
|
||||
->Fields()
|
||||
->filter('Required', true)
|
||||
->column('Name');
|
||||
$required = new RequiredFields($requiredNames);
|
||||
|
||||
$this->extend('updateRequiredFields', $required);
|
||||
|
||||
return $required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override validation so conditional fields can be validated correctly.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function validate() {
|
||||
$data = $this->getData();
|
||||
|
||||
Session::set("FormInfo.{$this->FormName()}.data", $data);
|
||||
Session::clear("FormInfo.{$this->FormName()}.errors");
|
||||
|
||||
foreach ($this->controller->Fields() as $key => $field) {
|
||||
$field->validateField($data, $this);
|
||||
}
|
||||
|
||||
if(Session::get("FormInfo.{$this->FormName()}.errors")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
60
code/model/EditableCustomRule.php
Normal file
60
code/model/EditableCustomRule.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* A custom rule for showing / hiding an EditableFormField
|
||||
* based the value of another EditableFormField.
|
||||
*
|
||||
* @package userforms
|
||||
*/
|
||||
class EditableCustomRule extends DataObject {
|
||||
|
||||
private static $condition_options = array(
|
||||
"IsBlank" => "Is blank",
|
||||
"IsNotBlank" => "Is not blank",
|
||||
"HasValue" => "Equals",
|
||||
"ValueNot" => "Doesn't equal",
|
||||
"ValueLessThan" => "Less than",
|
||||
"ValueLessThanEqual" => "Less than or equal",
|
||||
"ValueGreaterThan" => "Greater than",
|
||||
"ValueGreaterThanEqual" => "Greater than or equal"
|
||||
);
|
||||
|
||||
private static $db = array(
|
||||
'Display' => 'Enum("Show,Hide")',
|
||||
'ConditionOption' => 'Enum("IsBlank,IsNotBlank,HasValue,ValueNot,ValueLessThan,ValueLessThanEqual,ValueGreaterThan,ValueGreaterThanEqual")',
|
||||
'FieldValue' => 'Varchar'
|
||||
);
|
||||
|
||||
private static $has_one = array(
|
||||
'Parent' => 'EditableFormField',
|
||||
'ConditionField' => 'EditableFormField'
|
||||
);
|
||||
|
||||
/**
|
||||
* Built in extensions required
|
||||
*
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $extensions = array(
|
||||
"Versioned('Stage', 'Live')"
|
||||
);
|
||||
|
||||
/**
|
||||
* Publish this custom rule to the live site
|
||||
*
|
||||
* Wrapper for the {@link Versioned} publish function
|
||||
*/
|
||||
public function doPublish($fromStage, $toStage, $createNewVersion = false) {
|
||||
$this->publish($fromStage, $toStage, $createNewVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this custom rule from a given stage
|
||||
*
|
||||
* Wrapper for the {@link Versioned} deleteFromStage function
|
||||
*/
|
||||
public function doDeleteFromStage($stage) {
|
||||
$this->deleteFromStage($stage);
|
||||
}
|
||||
}
|
@ -12,14 +12,24 @@ class EditableCheckbox extends EditableFormField {
|
||||
private static $singular_name = 'Checkbox Field';
|
||||
|
||||
private static $plural_name = 'Checkboxes';
|
||||
|
||||
public function getFieldConfiguration() {
|
||||
$options = parent::getFieldConfiguration();
|
||||
$options->push(new CheckboxField("Fields[$this->ID][CustomSettings][Default]", _t('EditableFormField.CHECKEDBYDEFAULT', 'Checked by Default?'), $this->getSetting('Default')));
|
||||
|
||||
return $options;
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->removeByName('Default');
|
||||
|
||||
$fields->addFieldToTab('Root.Main', CheckboxField::create(
|
||||
"Fields[$this->ID][CustomSettings][Default]",
|
||||
_t('EditableFormField.CHECKEDBYDEFAULT', 'Checked by Default?'),
|
||||
$this->getSetting('Default')
|
||||
));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
||||
public function getFormField() {
|
||||
|
||||
$field = CheckboxField::create( $this->Name, $this->Title, $this->getSetting('Default'));
|
||||
@ -31,6 +41,8 @@ class EditableCheckbox extends EditableFormField {
|
||||
$field->setAttribute('data-rule-required', 'true');
|
||||
$field->setAttribute('data-msg-required', $errorMessage);
|
||||
}
|
||||
|
||||
$field->setValue($this->getSetting('Default'));
|
||||
|
||||
return $field;
|
||||
}
|
@ -19,7 +19,16 @@ class EditableCheckboxGroupField extends EditableMultipleOptionField {
|
||||
|
||||
$optionMap = ($optionSet) ? $optionSet->map('EscapedTitle', 'Title') : array();
|
||||
|
||||
return new UserFormsCheckboxSetField($this->Name, $this->Title, $optionMap);
|
||||
$field = new UserFormsCheckboxSetField($this->Name, $this->Title, $optionMap);
|
||||
|
||||
// Set the default checked items
|
||||
$defaultCheckedItems = $optionSet->filter('Default', 1);
|
||||
|
||||
if ($defaultCheckedItems->count()) {
|
||||
$field->setDefaultItems($optionSet->filter('Default', 1)->map('EscapedTitle')->keys());
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
public function getValueFromData($data) {
|
@ -10,9 +10,20 @@ class EditableCountryDropdownField extends EditableFormField {
|
||||
private static $singular_name = 'Country Dropdown';
|
||||
|
||||
private static $plural_name = 'Country Dropdowns';
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->removeByName('Default');
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function getFormField() {
|
||||
return new CountryDropdownField($this->Name, $this->Title);
|
||||
return CountryDropdownField::create($this->Name, $this->Title);
|
||||
}
|
||||
|
||||
public function getValueFromData($data) {
|
@ -12,24 +12,25 @@ class EditableDateField extends EditableFormField {
|
||||
private static $singular_name = 'Date Field';
|
||||
|
||||
private static $plural_name = 'Date Fields';
|
||||
|
||||
public function getFieldConfiguration() {
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->removeByName('Default');
|
||||
|
||||
$default = ($this->getSetting('DefaultToToday')) ? $this->getSetting('DefaultToToday') : false;
|
||||
$label = _t('EditableFormField.DEFAULTTOTODAY', 'Default to Today?');
|
||||
|
||||
return new FieldList(
|
||||
new CheckboxField($this->getSettingName("DefaultToToday"), $label, $default)
|
||||
);
|
||||
}
|
||||
|
||||
public function populateFromPostData($data) {
|
||||
$fieldPrefix = 'Default-';
|
||||
|
||||
if(empty($data['Default']) && !empty($data[$fieldPrefix.'Year']) && !empty($data[$fieldPrefix.'Month']) && !empty($data[$fieldPrefix.'Day'])) {
|
||||
$data['Default'] = $data['Year'] . '-' . $data['Month'] . '-' . $data['Day'];
|
||||
}
|
||||
|
||||
parent::populateFromPostData($data);
|
||||
|
||||
$fields->addFieldToTab('Root.Main', CheckboxField::create(
|
||||
$this->getSettingName('DefaultToToday'),
|
||||
$label,
|
||||
$default
|
||||
));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
@ -12,12 +12,24 @@ class EditableDropdown extends EditableMultipleOptionField {
|
||||
private static $singular_name = 'Dropdown Field';
|
||||
|
||||
private static $plural_name = 'Dropdowns';
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->removeByName('Default');
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DropdownField
|
||||
*/
|
||||
public function getFormField() {
|
||||
public function getFormField() {
|
||||
$optionSet = $this->Options();
|
||||
$defaultOptions = $optionSet->filter('Default', 1);
|
||||
$options = array();
|
||||
|
||||
if($optionSet) {
|
||||
@ -35,6 +47,10 @@ class EditableDropdown extends EditableMultipleOptionField {
|
||||
$field->setAttribute('data-rule-required', 'true');
|
||||
$field->setAttribute('data-msg-required', $errorMessage);
|
||||
}
|
||||
|
||||
if($defaultOptions->count()) {
|
||||
$field->setValue($defaultOptions->First()->EscapedTitle);
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
@ -28,6 +28,8 @@ class EditableEmailField extends EditableFormField {
|
||||
$field->setAttribute('data-rule-required', 'true');
|
||||
$field->setAttribute('data-msg-required', $errorMessage);
|
||||
}
|
||||
|
||||
$field->setValue($this->Default);
|
||||
|
||||
return $field;
|
||||
}
|
@ -12,21 +12,21 @@ class EditableFileField extends EditableFormField {
|
||||
|
||||
private static $plural_names = 'File Fields';
|
||||
|
||||
public function getFieldConfiguration() {
|
||||
$field = parent::getFieldConfiguration();
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$folder = ($this->getSetting('Folder')) ? $this->getSetting('Folder') : null;
|
||||
|
||||
$tree = UserformsTreeDropdownField::create(
|
||||
$this->getSettingName("Folder"),
|
||||
$fields->addFieldToTab('Root.Main', UserformsTreeDropdownField::create(
|
||||
$this->getSettingName('Folder'),
|
||||
_t('EditableUploadField.SELECTUPLOADFOLDER', 'Select upload folder'),
|
||||
"Folder"
|
||||
);
|
||||
'Folder'
|
||||
)->setValue($folder));
|
||||
|
||||
$tree->setValue($folder);
|
||||
|
||||
$field->push($tree);
|
||||
|
||||
return $field;
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function getFormField() {
|
@ -7,8 +7,14 @@
|
||||
*/
|
||||
|
||||
class EditableFormField extends DataObject {
|
||||
|
||||
private static $default_sort = "Sort";
|
||||
|
||||
/**
|
||||
* Default sort order
|
||||
*
|
||||
* @config
|
||||
* @var string
|
||||
*/
|
||||
private static $default_sort = '"Sort"';
|
||||
|
||||
/**
|
||||
* A list of CSS classes that can be added
|
||||
@ -16,7 +22,19 @@ class EditableFormField extends DataObject {
|
||||
* @var array
|
||||
*/
|
||||
public static $allowed_css = array();
|
||||
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $summary_fields = array(
|
||||
'Title'
|
||||
);
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $db = array(
|
||||
"Name" => "Varchar",
|
||||
"Title" => "Varchar(255)",
|
||||
@ -24,24 +42,40 @@ class EditableFormField extends DataObject {
|
||||
"Sort" => "Int",
|
||||
"Required" => "Boolean",
|
||||
"CustomErrorMessage" => "Varchar(255)",
|
||||
"CustomRules" => "Text",
|
||||
"CustomSettings" => "Text",
|
||||
"CustomParameter" => "Varchar(200)"
|
||||
"CustomSettings" => "Text"
|
||||
);
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $has_one = array(
|
||||
"Parent" => "UserDefinedForm",
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Built in extensions required
|
||||
*
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $extensions = array(
|
||||
"Versioned('Stage', 'Live')"
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $has_many = array(
|
||||
"CustomRules" => "EditableCustomRule.Parent"
|
||||
);
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $readonly;
|
||||
|
||||
|
||||
/**
|
||||
* Set the visibility of an individual form field
|
||||
*
|
||||
@ -59,14 +93,181 @@ class EditableFormField extends DataObject {
|
||||
private function isReadonly() {
|
||||
return $this->readonly;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Template to render the form field into
|
||||
*
|
||||
* @return String
|
||||
* @return FieldList
|
||||
*/
|
||||
public function EditSegment() {
|
||||
return $this->renderWith('EditableFormField');
|
||||
public function getCMSFields() {
|
||||
$fields = $this->scaffoldFormFields(array(
|
||||
'tabbed' => true
|
||||
));
|
||||
|
||||
$fields->removeByName('Sort');
|
||||
$fields->removeByName('Version');
|
||||
$fields->removeByName('ParentID');
|
||||
$fields->removeByName('CustomSettings');
|
||||
$fields->removeByName('Name');
|
||||
|
||||
$fields->insertBefore(ReadonlyField::create(
|
||||
'Type',
|
||||
_t('EditableFormField.TYPE', 'Type'),
|
||||
$this->config()->get('singular_name')),
|
||||
'Title'
|
||||
);
|
||||
|
||||
$fields->insertBefore(LiteralField::create(
|
||||
'MergeField',
|
||||
_t('EditableFormField.MERGEFIELDNAME',
|
||||
'<div class="field readonly">' .
|
||||
'<label class="left">Merge field</label>' .
|
||||
'<div class="middleColumn">' .
|
||||
'<span class="readonly">$' . $this->Name . '</span>' .
|
||||
'</div>' .
|
||||
'</div>')),
|
||||
'Title'
|
||||
);
|
||||
|
||||
/*
|
||||
* Validation
|
||||
*/
|
||||
$requiredCheckbox = $fields->fieldByName('Root')->fieldByName('Main')->fieldByName('Required');
|
||||
$customErrorMessage = $fields->fieldByName('Root')->fieldByName('Main')->fieldByName('CustomErrorMessage');
|
||||
|
||||
$fields->removeFieldFromTab('Root.Main', 'Required');
|
||||
$fields->removeFieldFromTab('Root.Main', 'CustomErrorMessage');
|
||||
|
||||
$fields->addFieldToTab('Root.Validation', $requiredCheckbox);
|
||||
$fields->addFieldToTab('Root.Validation', $customErrorMessage);
|
||||
|
||||
/*
|
||||
* Custom rules
|
||||
*/
|
||||
|
||||
$customRulesConfig = GridFieldConfig::create()
|
||||
->addComponents(
|
||||
(new GridFieldEditableColumns())
|
||||
->setDisplayFields(array(
|
||||
'Display' => '',
|
||||
'ConditionFieldID' => function($record, $column, $grid) {
|
||||
return DropdownField::create(
|
||||
$column,
|
||||
'',
|
||||
EditableFormField::get()
|
||||
->filter(array(
|
||||
'ParentID' => $this->ParentID
|
||||
))
|
||||
->exclude(array(
|
||||
'ID' => $this->ID
|
||||
))
|
||||
->map('ID', 'Title')
|
||||
);
|
||||
},
|
||||
'ConditionOption' => function($record, $column, $grid) {
|
||||
$options = Config::inst()->get('EditableCustomRule', 'condition_options');
|
||||
return DropdownField::create($column, '', $options);
|
||||
},
|
||||
'FieldValue' => function($record, $column, $grid) {
|
||||
return TextField::create($column);
|
||||
},
|
||||
'ParentID' => function($record, $column, $grid) {
|
||||
return HiddenField::create($column, '', $this->ID);
|
||||
}
|
||||
)),
|
||||
new GridFieldButtonRow(),
|
||||
new GridFieldToolbarHeader(),
|
||||
new GridFieldAddNewInlineButton(),
|
||||
new GridFieldDeleteAction(),
|
||||
new GridState_Component()
|
||||
);
|
||||
|
||||
|
||||
$customRulesGrid = GridField::create(
|
||||
'CustomRules',
|
||||
_t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
|
||||
$this->CustomRules(),
|
||||
$customRulesConfig
|
||||
);
|
||||
|
||||
$fields->addFieldToTab('Root.CustomRules', $customRulesGrid);
|
||||
|
||||
/*
|
||||
* Custom settings
|
||||
*/
|
||||
$extraClass = ($this->getSetting('ExtraClass')) ? $this->getSetting('ExtraClass') : '';
|
||||
|
||||
if (is_array(self::$allowed_css) && !empty(self::$allowed_css)) {
|
||||
foreach(self::$allowed_css as $k => $v) {
|
||||
if (!is_array($v)) $cssList[$k]=$v;
|
||||
elseif ($k == $this->ClassName()) $cssList = array_merge($cssList, $v);
|
||||
}
|
||||
|
||||
$fields->addFieldToTab('Root.Main',
|
||||
new DropdownField(
|
||||
$this->getSettingName('ExtraClass'),
|
||||
_t('EditableFormField.EXTRACLASSA', 'Extra Styling/Layout'),
|
||||
$cssList,
|
||||
$extraClass
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$fields->addFieldToTab('Root.Main',
|
||||
new TextField(
|
||||
$this->getSettingName('ExtraClass'),
|
||||
_t('EditableFormField.EXTRACLASSB', 'Extra CSS class - separate multiples with a space'),
|
||||
$extraClass
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$fields->addFieldToTab('Root.Main',
|
||||
new TextField(
|
||||
$this->getSettingName('RightTitle'),
|
||||
_t('EditableFormField.RIGHTTITLE', 'Right Title'),
|
||||
$this->getSetting('RightTitle')
|
||||
)
|
||||
);
|
||||
|
||||
$this->extend('updateCMSFields', $fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function onBeforeWrite() {
|
||||
parent::onBeforeWrite();
|
||||
|
||||
// Save custom settings.
|
||||
$fields = $this->toMap();
|
||||
$settings = $this->getSettings();
|
||||
|
||||
foreach($fields as $field => $value) {
|
||||
if(preg_match("/\[CustomSettings\]\[((\w)+)\]$/", $field, $matches)) {
|
||||
$settings[$matches[1]] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$this->setSettings($settings);
|
||||
|
||||
if(!isset($this->Sort)) {
|
||||
$parentID = ($this->ParentID) ? $this->ParentID : 0;
|
||||
|
||||
$this->Sort = EditableFormField::get()->filter('ParentID', $parentID)->max('Sort') + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function onAfterWrite() {
|
||||
parent::onAfterWrite();
|
||||
|
||||
// Set a field name.
|
||||
if(!$this->Name) {
|
||||
$this->Name = $this->RecordClassName . $this->ID;
|
||||
$this->write();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,7 +286,11 @@ class EditableFormField extends DataObject {
|
||||
* @return bool
|
||||
*/
|
||||
public function canDelete($member = null) {
|
||||
return ($this->Parent()->canEdit($member = null) && !$this->isReadonly());
|
||||
if($this->Parent()) {
|
||||
return $this->Parent()->canEdit($member) && !$this->isReadonly();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,7 +300,11 @@ class EditableFormField extends DataObject {
|
||||
* @return bool
|
||||
*/
|
||||
public function canEdit($member = null) {
|
||||
return ($this->Parent()->canEdit($member = null) && !$this->isReadonly());
|
||||
if($this->Parent()) {
|
||||
return $this->Parent()->canEdit($member) && !$this->isReadonly();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,6 +314,11 @@ class EditableFormField extends DataObject {
|
||||
*/
|
||||
public function doPublish($fromStage, $toStage, $createNewVersion = false) {
|
||||
$this->publish($fromStage, $toStage, $createNewVersion);
|
||||
|
||||
// Don't forget to publish the related custom rules...
|
||||
foreach ($this->CustomRules() as $rule) {
|
||||
$rule->doPublish($fromStage, $toStage, $createNewVersion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,6 +328,11 @@ class EditableFormField extends DataObject {
|
||||
*/
|
||||
public function doDeleteFromStage($stage) {
|
||||
$this->deleteFromStage($stage);
|
||||
|
||||
// Don't forget to delete the related custom rules...
|
||||
foreach ($this->CustomRules() as $rule) {
|
||||
$rule->deleteFromStage($stage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,7 +355,7 @@ class EditableFormField extends DataObject {
|
||||
if($this->isNew()) return false;
|
||||
|
||||
$stageVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Stage', $this->ID);
|
||||
$liveVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Live', $this->ID);
|
||||
$liveVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Live', $this->ID);
|
||||
|
||||
return ($stageVersion && $stageVersion != $liveVersion);
|
||||
}
|
||||
@ -243,51 +462,6 @@ class EditableFormField extends DataObject {
|
||||
public function showExtraOptions() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the custom validation fields for this field for the CMS
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function Dependencies() {
|
||||
return ($this->CustomRules) ? unserialize($this->CustomRules) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the custom validation fields for the field
|
||||
*
|
||||
* @return DataObjectSet
|
||||
*/
|
||||
public function CustomRules() {
|
||||
$output = new ArrayList();
|
||||
$fields = $this->Parent()->Fields();
|
||||
|
||||
// check for existing ones
|
||||
if($rules = $this->Dependencies()) {
|
||||
foreach($rules as $rule => $data) {
|
||||
// recreate all the field object to prevent caching
|
||||
$outputFields = new ArrayList();
|
||||
|
||||
foreach($fields as $field) {
|
||||
$new = clone $field;
|
||||
|
||||
$new->isSelected = ($new->Name == $data['ConditionField']) ? true : false;
|
||||
$outputFields->push($new);
|
||||
}
|
||||
|
||||
$output->push(new ArrayData(array(
|
||||
'FieldName' => $this->getFieldName(),
|
||||
'Display' => $data['Display'],
|
||||
'Fields' => $outputFields,
|
||||
'ConditionField' => $data['ConditionField'],
|
||||
'ConditionOption' => $data['ConditionOption'],
|
||||
'Value' => $data['Value']
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title field of the field in the backend of the page
|
||||
@ -336,118 +510,6 @@ class EditableFormField extends DataObject {
|
||||
return $name . '[' . $field .']';
|
||||
}
|
||||
|
||||
/**
|
||||
* How to save the data submitted in this field into the database object
|
||||
* which this field represents.
|
||||
*
|
||||
* Any class's which call this should also call
|
||||
* {@link parent::populateFromPostData()} to ensure that this method is
|
||||
* called
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public function populateFromPostData($data) {
|
||||
$this->Title = (isset($data['Title'])) ? $data['Title']: "";
|
||||
$this->Default = (isset($data['Default'])) ? $data['Default'] : "";
|
||||
$this->Sort = (isset($data['Sort'])) ? $data['Sort'] : null;
|
||||
$this->Required = !empty($data['Required']) ? 1 : 0;
|
||||
$this->Name = $this->class.$this->ID;
|
||||
$this->CustomRules = "";
|
||||
$this->CustomErrorMessage = (isset($data['CustomErrorMessage'])) ? $data['CustomErrorMessage'] : "";
|
||||
$this->CustomSettings = "";
|
||||
|
||||
// custom settings
|
||||
if(isset($data['CustomSettings'])) {
|
||||
$this->setSettings($data['CustomSettings']);
|
||||
}
|
||||
|
||||
// custom validation
|
||||
if(isset($data['CustomRules'])) {
|
||||
$rules = array();
|
||||
|
||||
foreach($data['CustomRules'] as $key => $value) {
|
||||
|
||||
if(is_array($value)) {
|
||||
$fieldValue = (isset($value['Value'])) ? $value['Value'] : '';
|
||||
|
||||
if(isset($value['ConditionOption']) && $value['ConditionOption'] == "Blank" || $value['ConditionOption'] == "NotBlank") {
|
||||
$fieldValue = "";
|
||||
}
|
||||
|
||||
$rules[] = array(
|
||||
'Display' => (isset($value['Display'])) ? $value['Display'] : "",
|
||||
'ConditionField' => (isset($value['ConditionField'])) ? $value['ConditionField'] : "",
|
||||
'ConditionOption' => (isset($value['ConditionOption'])) ? $value['ConditionOption'] : "",
|
||||
'Value' => $fieldValue
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->CustomRules = serialize($rules);
|
||||
}
|
||||
|
||||
$this->extend('onPopulateFromPostData', $data);
|
||||
$this->write();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement custom field Configuration on this field. Includes such things as
|
||||
* settings and options of a given editable form field
|
||||
*
|
||||
* @return FieldSet
|
||||
*/
|
||||
public function getFieldConfiguration() {
|
||||
$extraClass = ($this->getSetting('ExtraClass')) ? $this->getSetting('ExtraClass') : '';
|
||||
|
||||
$mergeFieldName = new LiteralField('MergeFieldName', _t('EditableFormField.MERGEFIELDNAME',
|
||||
'<div class="field">' .
|
||||
'<label class="left" for="Fields-6-CustomSettings-RightTitle">Merge field</label>' .
|
||||
'<div class="middleColumn">' .
|
||||
'<p>$' . $this->Name . '</p>' .
|
||||
'<em>Use this to display the field\'s value in email content.</em>' .
|
||||
'</div>' .
|
||||
'</div>'
|
||||
));
|
||||
|
||||
if (is_array(self::$allowed_css) && !empty(self::$allowed_css)) {
|
||||
foreach(self::$allowed_css as $k => $v) {
|
||||
if (!is_array($v)) $cssList[$k]=$v;
|
||||
elseif ($k == $this->ClassName()) $cssList = array_merge($cssList, $v);
|
||||
}
|
||||
|
||||
$ec = new DropdownField(
|
||||
$this->getSettingName('ExtraClass'),
|
||||
_t('EditableFormField.EXTRACLASSA', 'Extra Styling/Layout'),
|
||||
$cssList, $extraClass
|
||||
);
|
||||
|
||||
}
|
||||
else {
|
||||
$ec = new TextField(
|
||||
$this->getSettingName('ExtraClass'),
|
||||
_t('EditableFormField.EXTRACLASSB', 'Extra css Class - separate multiples with a space'),
|
||||
$extraClass
|
||||
);
|
||||
}
|
||||
|
||||
$right = new TextField(
|
||||
$this->getSettingName('RightTitle'),
|
||||
_t('EditableFormField.RIGHTTITLE', 'Right Title'),
|
||||
$this->getSetting('RightTitle')
|
||||
);
|
||||
|
||||
$fields = FieldList::create(
|
||||
$mergeFieldName,
|
||||
$ec,
|
||||
$right
|
||||
);
|
||||
$this->extend('updateFieldConfiguration', $fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append custom validation fields to the default 'Validation'
|
||||
* section in the editable options view
|
||||
@ -533,4 +595,32 @@ class EditableFormField extends DataObject {
|
||||
|
||||
return DBField::create_field('Varchar', $errorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the field taking into account its custom rules.
|
||||
*
|
||||
* @param Array $data
|
||||
* @param UserForm $form
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function validateField($data, $form) {
|
||||
if($this->Required && $this->CustomRules()->Count() == 0) {
|
||||
$formField = $this->getFormField();
|
||||
|
||||
if(isset($data[$this->Name])) {
|
||||
$formField->setValue($data[$this->Name]);
|
||||
}
|
||||
|
||||
if(
|
||||
!isset($data[$this->Name]) ||
|
||||
!$data[$this->Name] ||
|
||||
!$formField->validate($form->getValidator())
|
||||
) {
|
||||
$form->addErrorMessage($this->Name, $this->getErrorMessage(), 'bad');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -10,8 +10,16 @@ class EditableFormHeading extends EditableFormField {
|
||||
private static $singular_name = 'Heading';
|
||||
|
||||
private static $plural_name = 'Headings';
|
||||
|
||||
public function getFieldConfiguration() {
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->removeByName('Default');
|
||||
$fields->removeByName('Validation');
|
||||
|
||||
$levels = array(
|
||||
'1' => '1',
|
||||
'2' => '2',
|
||||
@ -23,26 +31,22 @@ class EditableFormHeading extends EditableFormField {
|
||||
|
||||
$level = ($this->getSetting('Level')) ? $this->getSetting('Level') : 3;
|
||||
$label = _t('EditableFormHeading.LEVEL', 'Select Heading Level');
|
||||
|
||||
$options = parent::getFieldConfiguration();
|
||||
|
||||
$options->push(
|
||||
new DropdownField($this->getSettingName("Level"), $label, $levels, $level)
|
||||
);
|
||||
|
||||
if($this->readonly) {
|
||||
$extraFields = $options->makeReadonly();
|
||||
}
|
||||
|
||||
$options->push(
|
||||
new CheckboxField(
|
||||
$fields->addFieldsToTab('Root.Main', array(
|
||||
DropdownField::create(
|
||||
$this->getSettingName('Level'),
|
||||
$label,
|
||||
$levels,
|
||||
$level
|
||||
),
|
||||
CheckboxField::create(
|
||||
$this->getSettingName('HideFromReports'),
|
||||
_t('EditableLiteralField.HIDEFROMREPORT', 'Hide from reports?'),
|
||||
$this->getSetting('HideFromReports')
|
||||
)
|
||||
);
|
||||
|
||||
return $options;
|
||||
));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function getFormField() {
|
@ -70,24 +70,31 @@ class EditableLiteralField extends EditableFormField {
|
||||
$content = $this->sanitiseContent($content);
|
||||
$this->setSetting('Content', $content);
|
||||
}
|
||||
|
||||
public function getFieldConfiguration() {
|
||||
$textAreaField = new HTMLEditorField(
|
||||
$this->getSettingName('Content'),
|
||||
"HTML",
|
||||
$this->getContent()
|
||||
);
|
||||
$textAreaField->setRows(4);
|
||||
$textAreaField->setColumns(20);
|
||||
|
||||
return new FieldList(
|
||||
$textAreaField,
|
||||
new CheckboxField(
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->removeByName('Default');
|
||||
$fields->removeByName('Validation');
|
||||
|
||||
$fields->addFieldsToTab('Root.Main', array(
|
||||
HTMLEditorField::create(
|
||||
$this->getSettingName('Content'),
|
||||
'HTML',
|
||||
$this->getContent())
|
||||
->setRows(4)
|
||||
->setColumns(20),
|
||||
CheckboxField::create(
|
||||
$this->getSettingName('HideFromReports'),
|
||||
_t('EditableLiteralField.HIDEFROMREPORT', 'Hide from reports?'),
|
||||
$this->getSetting('HideFromReports')
|
||||
)
|
||||
);
|
||||
));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function getFormField() {
|
@ -10,17 +10,30 @@ class EditableMemberListField extends EditableFormField {
|
||||
private static $singular_name = 'Member List Field';
|
||||
|
||||
private static $plural_name = 'Member List Fields';
|
||||
|
||||
public function getFieldConfiguration() {
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->removeByName('Default');
|
||||
$fields->removeByName('Validation');
|
||||
|
||||
$groupID = ($this->getSetting('GroupID')) ? $this->getSetting('GroupID') : 0;
|
||||
$groups = DataObject::get("Group");
|
||||
$groups = DataObject::get('Group');
|
||||
|
||||
if($groups) $groups = $groups->map('ID', 'Title');
|
||||
|
||||
$fields = new FieldList(
|
||||
new DropdownField("Fields[$this->ID][CustomSettings][GroupID]", _t('EditableFormField.GROUP', 'Group'), $groups, $groupID)
|
||||
);
|
||||
if($groups) {
|
||||
$groups = $groups->map('ID', 'Title');
|
||||
}
|
||||
|
||||
$fields->addFieldToTab('Root.Main', DropdownField::create(
|
||||
"Fields[$this->ID][CustomSettings][GroupID]",
|
||||
_t('EditableFormField.GROUP', 'Group'),
|
||||
$groups,
|
||||
$groupID
|
||||
));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
@ -18,6 +18,46 @@ class EditableMultipleOptionField extends EditableFormField {
|
||||
private static $has_many = array(
|
||||
"Options" => "EditableOption"
|
||||
);
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$optionsGrid = GridField::create(
|
||||
'Options',
|
||||
_t('EditableFormField.CUSTOMOPTIONS', 'Options'),
|
||||
$this->Options()
|
||||
);
|
||||
|
||||
$optionsConfig = GridFieldConfig::create()
|
||||
->addComponents(
|
||||
(new GridFieldEditableColumns())
|
||||
->setDisplayFields(array(
|
||||
'Title' => function($record, $column, $grid) {
|
||||
return TextField::create($column);
|
||||
},
|
||||
'Default' => function($record, $column, $grid) {
|
||||
return CheckboxField::create($column);
|
||||
},
|
||||
'ParentID' => function($record, $column, $grid) {
|
||||
return HiddenField::create($column, '', $this->ID);
|
||||
}
|
||||
)),
|
||||
new GridFieldButtonRow(),
|
||||
new GridFieldToolbarHeader(),
|
||||
new GridFieldAddNewInlineButton(),
|
||||
new GridFieldDeleteAction(),
|
||||
new GridState_Component()
|
||||
);
|
||||
|
||||
$optionsGrid->setConfig($optionsConfig);
|
||||
|
||||
$fields->addFieldToTab('Root.Options', $optionsGrid);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishing Versioning support.
|
||||
@ -100,29 +140,6 @@ class EditableMultipleOptionField extends EditableFormField {
|
||||
return $clonedNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* On before saving this object we need to go through and keep an eye on
|
||||
* all our option fields that are related to this field in the form
|
||||
*
|
||||
* @param ArrayData
|
||||
*/
|
||||
public function populateFromPostData($data) {
|
||||
parent::populateFromPostData($data);
|
||||
|
||||
// get the current options
|
||||
$fieldSet = $this->Options();
|
||||
|
||||
// go over all the current options and check if ID and Title still exists
|
||||
foreach($fieldSet as $option) {
|
||||
if(isset($data[$option->ID]) && isset($data[$option->ID]['Title']) && $data[$option->ID]['Title'] != "field-node-deleted") {
|
||||
$option->populateFromPostData($data[$option->ID]);
|
||||
}
|
||||
else {
|
||||
$option->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not this field has addable options such as a
|
||||
* {@link EditableDropdownField} or {@link EditableRadioField}
|
@ -23,6 +23,7 @@ class EditableNumericField extends EditableFormField {
|
||||
public function getFormField() {
|
||||
$field = new NumericField($this->Name, $this->Title);
|
||||
$field->addExtraClass('number');
|
||||
$field->setValue($this->Default);
|
||||
|
||||
if ($this->Required) {
|
||||
// Required and numeric validation can conflict so add the
|
@ -26,23 +26,23 @@ class EditableOption extends DataObject {
|
||||
"Versioned('Stage', 'Live')"
|
||||
);
|
||||
|
||||
/**
|
||||
* @param Member $member
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canEdit($member = null) {
|
||||
return ($this->Parent()->canEdit($member));
|
||||
}
|
||||
/**
|
||||
* @param Member $member
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canEdit($member = null) {
|
||||
return ($this->Parent()->canEdit($member));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Member $member
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canDelete($member = null) {
|
||||
return ($this->Parent()->canDelete($member));
|
||||
}
|
||||
/**
|
||||
* @param Member $member
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canDelete($member = null) {
|
||||
return ($this->Parent()->canDelete($member));
|
||||
}
|
||||
|
||||
/**
|
||||
* Template for the editing view of this option field
|
||||
@ -68,20 +68,6 @@ class EditableOption extends DataObject {
|
||||
public function FieldName() {
|
||||
return "Fields[{$this->ParentID}][{$this->ID}]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate this option from the form field
|
||||
*
|
||||
* @param Array Data
|
||||
*/
|
||||
public function populateFromPostData($data) {
|
||||
$this->Title = (isset($data['Title'])) ? $data['Title'] : "";
|
||||
$this->Default = (isset($data['Default'])) ? $data['Default'] : "";
|
||||
$this->Sort = (isset($data['Sort'])) ? $data['Sort'] : 0;
|
||||
|
||||
$this->extend('onPopulateFromPostData', $data);
|
||||
$this->write();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make this option readonly
|
||||
@ -91,7 +77,7 @@ class EditableOption extends DataObject {
|
||||
return $this->EditSegment();
|
||||
}
|
||||
|
||||
public function getEscapedTitle() {
|
||||
return Convert::raw2att($this->Title);
|
||||
}
|
||||
public function getEscapedTitle() {
|
||||
return Convert::raw2att($this->Title);
|
||||
}
|
||||
}
|
@ -12,17 +12,35 @@ class EditableRadioField extends EditableMultipleOptionField {
|
||||
private static $singular_name = 'Radio field';
|
||||
|
||||
private static $plural_name = 'Radio fields';
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->removeByName('Default');
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function getFormField() {
|
||||
$optionSet = $this->Options();
|
||||
$defaultOptions = $optionSet->filter('Default', 1);
|
||||
$options = array();
|
||||
|
||||
|
||||
if($optionSet) {
|
||||
foreach( $optionSet as $option ) {
|
||||
foreach($optionSet as $option) {
|
||||
$options[$option->EscapedTitle] = $option->Title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new OptionsetField($this->Name, $this->Title, $options);
|
||||
|
||||
$field = OptionsetField::create($this->Name, $this->Title, $options);
|
||||
|
||||
if($defaultOptions->count()) {
|
||||
$field->setValue($defaultOptions->First()->EscapedTitle);
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
}
|
@ -12,27 +12,32 @@ class EditableTextField extends EditableFormField {
|
||||
private static $singular_name = 'Text Field';
|
||||
|
||||
private static $plural_name = 'Text Fields';
|
||||
|
||||
public function getFieldConfiguration() {
|
||||
$fields = parent::getFieldConfiguration();
|
||||
|
||||
|
||||
/**
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields() {
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$min = ($this->getSetting('MinLength')) ? $this->getSetting('MinLength') : '';
|
||||
$max = ($this->getSetting('MaxLength')) ? $this->getSetting('MaxLength') : '';
|
||||
|
||||
|
||||
$rows = ($this->getSetting('Rows')) ? $this->getSetting('Rows') : '1';
|
||||
|
||||
$extraFields = new FieldList(
|
||||
new FieldGroup(_t('EditableTextField.TEXTLENGTH', 'Text length'),
|
||||
new NumericField($this->getSettingName('MinLength'), "", $min),
|
||||
new NumericField($this->getSettingName('MaxLength'), " - ", $max)
|
||||
|
||||
$fields->addFieldsToTab('Root.Main', array(
|
||||
FieldGroup::create(
|
||||
_t('EditableTextField.TEXTLENGTH', 'Text length'),
|
||||
NumericField::create($this->getSettingName('MinLength'), '', $min),
|
||||
NumericField::create($this->getSettingName('MaxLength'), ' - ', $max)
|
||||
),
|
||||
new NumericField($this->getSettingName('Rows'), _t('EditableTextField.NUMBERROWS',
|
||||
'Number of rows'), $rows)
|
||||
);
|
||||
|
||||
$fields->merge($extraFields);
|
||||
|
||||
return $fields;
|
||||
NumericField::create(
|
||||
'Rows',
|
||||
_t('EditableTextField.NUMBERROWS', 'Number of rows'),
|
||||
$rows
|
||||
)
|
||||
));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,6 +62,8 @@ class EditableTextField extends EditableFormField {
|
||||
$field->setAttribute('data-rule-required', 'true');
|
||||
$field->setAttribute('data-msg-required', $errorMessage);
|
||||
}
|
||||
|
||||
$field->setValue($this->Default);
|
||||
|
||||
return $field;
|
||||
}
|
@ -16,20 +16,19 @@ class UserDefinedForm extends Page {
|
||||
*/
|
||||
private static $required_identifier = null;
|
||||
|
||||
/**
|
||||
* Prevent translatable module from attepmting to translate FieldEditor
|
||||
*
|
||||
* @var array
|
||||
* @config
|
||||
*/
|
||||
private static $translate_excluded_fields = array(
|
||||
'Fields'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $email_template_directory = 'userforms/templates/email/';
|
||||
|
||||
/**
|
||||
* Built in extensions required by this page
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $extensions = array(
|
||||
'UserFormFieldEditorExtension'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array Fields on the user defined form page.
|
||||
@ -60,7 +59,6 @@ class UserDefinedForm extends Page {
|
||||
* @var array
|
||||
*/
|
||||
private static $has_many = array(
|
||||
"Fields" => "EditableFormField",
|
||||
"Submissions" => "SubmittedForm",
|
||||
"EmailRecipients" => "UserDefinedForm_EmailRecipient"
|
||||
);
|
||||
@ -98,14 +96,10 @@ class UserDefinedForm extends Page {
|
||||
$this->beforeUpdateCMSFields(function($fields) use ($self) {
|
||||
|
||||
// define tabs
|
||||
$fields->findOrMakeTab('Root.FormContent', _t('UserDefinedForm.FORM', 'Form'));
|
||||
$fields->findOrMakeTab('Root.FormOptions', _t('UserDefinedForm.CONFIGURATION', 'Configuration'));
|
||||
$fields->findOrMakeTab('Root.Recipients', _t('UserDefinedForm.RECIPIENTS', 'Recipients'));
|
||||
$fields->findOrMakeTab('Root.Submissions', _t('UserDefinedForm.SUBMISSIONS', 'Submissions'));
|
||||
|
||||
// field editor
|
||||
$fields->addFieldToTab('Root.FormContent', new FieldEditor('Fields', 'Fields', '', $self ));
|
||||
|
||||
// text to show on complete
|
||||
$onCompleteFieldSet = new CompositeField(
|
||||
$label = new LabelField('OnCompleteMessageLabel',_t('UserDefinedForm.ONCOMPLETELABEL', 'Show on completion')),
|
||||
@ -209,125 +203,6 @@ SQL;
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When publishing copy the editable form fields to the live database
|
||||
* Not going to version emails and submissions as they are likely to
|
||||
* persist over multiple versions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function doPublish() {
|
||||
$parentID = (!empty($this->ID)) ? $this->ID : 0;
|
||||
// remove fields on the live table which could have been orphaned.
|
||||
$live = Versioned::get_by_stage("EditableFormField", "Live", "\"EditableFormField\".\"ParentID\" = $parentID");
|
||||
|
||||
if($live) {
|
||||
foreach($live as $field) {
|
||||
$field->doDeleteFromStage('Live');
|
||||
}
|
||||
}
|
||||
|
||||
// publish the draft pages
|
||||
if($this->Fields()) {
|
||||
foreach($this->Fields() as $field) {
|
||||
$field->doPublish('Stage', 'Live');
|
||||
}
|
||||
}
|
||||
|
||||
parent::doPublish();
|
||||
}
|
||||
|
||||
/**
|
||||
* When un-publishing the page it has to remove all the fields from the
|
||||
* live database table.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function doUnpublish() {
|
||||
if($this->Fields()) {
|
||||
foreach($this->Fields() as $field) {
|
||||
$field->doDeleteFromStage('Live');
|
||||
}
|
||||
}
|
||||
|
||||
parent::doUnpublish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll back a form to a previous version.
|
||||
*
|
||||
* @param string|int Version to roll back to
|
||||
*/
|
||||
public function doRollbackTo($version) {
|
||||
parent::doRollbackTo($version);
|
||||
|
||||
/*
|
||||
Not implemented yet
|
||||
|
||||
// get the older version
|
||||
$reverted = Versioned::get_version($this->ClassName, $this->ID, $version);
|
||||
|
||||
if($reverted) {
|
||||
|
||||
// using the lastedited date of the reverted object we can work out which
|
||||
// form fields to revert back to
|
||||
if($this->Fields()) {
|
||||
foreach($this->Fields() as $field) {
|
||||
// query to see when the version of the page was pumped
|
||||
$editedDate = DB::query("
|
||||
SELECT LastEdited
|
||||
FROM \"SiteTree_versions\"
|
||||
WHERE \"RecordID\" = '$this->ID' AND \"Version\" = $version
|
||||
")->value();
|
||||
|
||||
|
||||
// find a the latest version which has been edited
|
||||
$versionToGet = DB::query("
|
||||
SELECT *
|
||||
FROM \"EditableFormField_versions\"
|
||||
WHERE \"RecordID\" = '$field->ID' AND \"LastEdited\" <= '$editedDate'
|
||||
ORDER BY Version DESC
|
||||
LIMIT 1
|
||||
")->record();
|
||||
|
||||
if($versionToGet) {
|
||||
Debug::show('publishing field'. $field->Name);
|
||||
Debug::show($versionToGet);
|
||||
$field->publish($versionToGet, "Stage", true);
|
||||
$field->writeWithoutVersion();
|
||||
}
|
||||
else {
|
||||
Debug::show('deleting field'. $field->Name);
|
||||
$this->Fields()->remove($field);
|
||||
|
||||
$field->delete();
|
||||
$field->destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @todo Emails
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert the draft site to the current live site
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function doRevertToLive() {
|
||||
if($this->Fields()) {
|
||||
foreach($this->Fields() as $field) {
|
||||
$field->publish("Live", "Stage", false);
|
||||
$field->writeWithoutVersion();
|
||||
}
|
||||
}
|
||||
|
||||
parent::doRevertToLive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow overriding the EmailRecipients on a {@link DataExtension}
|
||||
@ -350,67 +225,6 @@ SQL;
|
||||
return $recipients;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store new and old ids of duplicated fields.
|
||||
* This method also serves as a hook for descendant classes.
|
||||
*/
|
||||
protected function afterDuplicateField($page, $fromField, $toField) {
|
||||
$this->fieldsFromTo[$fromField->ClassName . $fromField->ID] = $toField->ClassName . $toField->ID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Duplicate this UserDefinedForm page, and its form fields.
|
||||
* Submissions, on the other hand, won't be duplicated.
|
||||
*
|
||||
* @return Page
|
||||
*/
|
||||
public function duplicate($doWrite = true) {
|
||||
$page = parent::duplicate($doWrite);
|
||||
|
||||
// the form fields
|
||||
if($this->Fields()) {
|
||||
foreach($this->Fields() as $field) {
|
||||
$newField = $field->duplicate();
|
||||
$newField->ParentID = $page->ID;
|
||||
$newField->write();
|
||||
$this->afterDuplicateField($page, $field, $newField);
|
||||
}
|
||||
}
|
||||
|
||||
// the emails
|
||||
if($this->EmailRecipients()) {
|
||||
foreach($this->EmailRecipients() as $email) {
|
||||
$newEmail = $email->duplicate();
|
||||
$newEmail->FormID = $page->ID;
|
||||
$newEmail->write();
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite CustomRules
|
||||
if($page->Fields()) {
|
||||
foreach($page->Fields() as $field) {
|
||||
// Rewrite name to make the CustomRules-rewrite below work.
|
||||
$field->Name = $field->ClassName . $field->ID;
|
||||
$rules = unserialize($field->CustomRules);
|
||||
|
||||
if (count($rules) && isset($rules[0]['ConditionField'])) {
|
||||
$from = $rules[0]['ConditionField'];
|
||||
|
||||
if (array_key_exists($from, $this->fieldsFromTo)) {
|
||||
$rules[0]['ConditionField'] = $this->fieldsFromTo[$from];
|
||||
$field->CustomRules = serialize($rules);
|
||||
}
|
||||
}
|
||||
|
||||
$field->Write();
|
||||
}
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom options for the form. You can extend the built in options by
|
||||
* using {@link updateFormOptions()}
|
||||
@ -436,36 +250,6 @@ SQL;
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if this form has been modified on the stage site and not published.
|
||||
* this is used on the workflow module and for a couple highlighting things
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function getIsModifiedOnStage() {
|
||||
// new unsaved pages could be never be published
|
||||
if($this->isNew()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$stageVersion = Versioned::get_versionnumber_by_stage('UserDefinedForm', 'Stage', $this->ID);
|
||||
$liveVersion = Versioned::get_versionnumber_by_stage('UserDefinedForm', 'Live', $this->ID);
|
||||
|
||||
$isModified = ($stageVersion && $stageVersion != $liveVersion);
|
||||
|
||||
if(!$isModified) {
|
||||
if($this->Fields()) {
|
||||
foreach($this->Fields() as $field) {
|
||||
if($field->getIsModifiedOnStage()) {
|
||||
$isModified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $isModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML id of the error container displayed above the form.
|
||||
@ -552,141 +336,23 @@ class UserDefinedForm_Controller extends Page_Controller {
|
||||
* Get the form for the page. Form can be modified by calling {@link updateForm()}
|
||||
* on a UserDefinedForm extension.
|
||||
*
|
||||
* @return Form|false
|
||||
* @return Forms
|
||||
*/
|
||||
public function Form() {
|
||||
$fields = $this->getFormFields();
|
||||
if(!$fields || !$fields->exists()) return false;
|
||||
|
||||
$actions = $this->getFormActions();
|
||||
|
||||
// get the required fields including the validation
|
||||
$required = $this->getRequiredFields();
|
||||
$form = UserForm::create($this);
|
||||
|
||||
// generate the conditional logic
|
||||
$this->generateConditionalJavascript();
|
||||
|
||||
$form = new Form($this, "Form", $fields, $actions, $required);
|
||||
$form->setRedirectToFormOnValidationError(true);
|
||||
|
||||
$data = Session::get("FormInfo.{$form->FormName()}.data");
|
||||
|
||||
if(is_array($data)) $form->loadDataFrom($data);
|
||||
|
||||
$this->extend('updateForm', $form);
|
||||
|
||||
if($this->DisableCsrfSecurityToken) {
|
||||
$form->disableSecurityToken();
|
||||
}
|
||||
|
||||
$this->generateValidationJavascript($form);
|
||||
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the form fields for the form on this page. Can modify this FieldSet
|
||||
* by using {@link updateFormFields()} on an {@link Extension} subclass which
|
||||
* is applied to this controller.
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getFormFields() {
|
||||
$fields = new FieldList();
|
||||
|
||||
$editableFields = $this->Fields();
|
||||
if($editableFields) foreach($editableFields as $editableField) {
|
||||
// get the raw form field from the editable version
|
||||
$field = $editableField->getFormField();
|
||||
if(!$field) break;
|
||||
|
||||
// set the error / formatting messages
|
||||
$field->setCustomValidationMessage($editableField->getErrorMessage());
|
||||
|
||||
// set the right title on this field
|
||||
if($right = $editableField->getSetting('RightTitle')) {
|
||||
// Since this field expects raw html, safely escape the user data prior
|
||||
$field->setRightTitle(Convert::raw2xml($right));
|
||||
}
|
||||
|
||||
// if this field is required add some
|
||||
if($editableField->Required) {
|
||||
$field->addExtraClass('requiredField');
|
||||
|
||||
if($identifier = UserDefinedForm::config()->required_identifier) {
|
||||
|
||||
$title = $field->Title() ." <span class='required-identifier'>". $identifier . "</span>";
|
||||
$field->setTitle($title);
|
||||
}
|
||||
}
|
||||
// if this field has an extra class
|
||||
if($extraClass = $editableField->getSetting('ExtraClass')) {
|
||||
$field->addExtraClass(Convert::raw2att($extraClass));
|
||||
}
|
||||
|
||||
// set the values passed by the url to the field
|
||||
$request = $this->getRequest();
|
||||
if($value = $request->getVar($field->getName())) {
|
||||
$field->setValue($value);
|
||||
}
|
||||
|
||||
$fields->push($field);
|
||||
}
|
||||
$this->extend('updateFormFields', $fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the form actions for the UserDefinedForm. You
|
||||
* can manipulate these by using {@link updateFormActions()} on
|
||||
* a decorator.
|
||||
*
|
||||
* @todo Make form actions editable via their own field editor.
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getFormActions() {
|
||||
$submitText = ($this->SubmitButtonText) ? $this->SubmitButtonText : _t('UserDefinedForm.SUBMITBUTTON', 'Submit');
|
||||
$clearText = ($this->ClearButtonText) ? $this->ClearButtonText : _t('UserDefinedForm.CLEARBUTTON', 'Clear');
|
||||
|
||||
$actions = new FieldList(
|
||||
new FormAction("process", $submitText)
|
||||
);
|
||||
|
||||
if($this->ShowClearButton) {
|
||||
$actions->push(new ResetFormAction("clearForm", $clearText));
|
||||
}
|
||||
|
||||
$this->extend('updateFormActions', $actions);
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the required form fields for this form.
|
||||
*
|
||||
* @return RequiredFields
|
||||
*/
|
||||
public function getRequiredFields() {
|
||||
// Generate required field validator
|
||||
$requiredNames = $this
|
||||
->Fields()
|
||||
->filter('Required', true)
|
||||
->column('Name');
|
||||
$required = new RequiredFields($requiredNames);
|
||||
|
||||
$this->extend('updateRequiredFields', $required);
|
||||
|
||||
return $required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build jQuery validation script and require as a custom script
|
||||
*
|
||||
* @param Form $form
|
||||
* @param UserForm $form
|
||||
*/
|
||||
public function generateValidationJavascript($form) {
|
||||
public function generateValidationJavascript(UserForm $form) {
|
||||
// set the custom script for this form
|
||||
Requirements::customScript(
|
||||
$this
|
||||
@ -711,139 +377,125 @@ class UserDefinedForm_Controller extends Page_Controller {
|
||||
if($this->Fields()) {
|
||||
foreach($this->Fields() as $field) {
|
||||
$fieldId = $field->Name;
|
||||
|
||||
|
||||
if($field->ClassName == 'EditableFormHeading') {
|
||||
$fieldId = 'Form_Form_'.$field->Name;
|
||||
$fieldId = 'UserForm_Form_' . $field->Name;
|
||||
}
|
||||
|
||||
|
||||
// Is this Field Show by Default
|
||||
if(!$field->getShowOnLoad()) {
|
||||
$default .= "$(\"#" . $fieldId . "\").hide();\n";
|
||||
}
|
||||
|
||||
// Check for field dependencies / default
|
||||
if($field->Dependencies()) {
|
||||
foreach($field->Dependencies() as $dependency) {
|
||||
if(is_array($dependency) && isset($dependency['ConditionField']) && $dependency['ConditionField'] != "") {
|
||||
// get the field which is effected
|
||||
$formName = Convert::raw2sql($dependency['ConditionField']);
|
||||
$formFieldWatch = DataObject::get_one("EditableFormField", "\"Name\" = '$formName'");
|
||||
|
||||
if(!$formFieldWatch) break;
|
||||
|
||||
// watch out for multiselect options - radios and check boxes
|
||||
if(is_a($formFieldWatch, 'EditableDropdown')) {
|
||||
$fieldToWatch = "$(\"select[name='".$dependency['ConditionField']."']\")";
|
||||
$fieldToWatchOnLoad = $fieldToWatch;
|
||||
}
|
||||
// watch out for checkboxs as the inputs don't have values but are 'checked
|
||||
else if(is_a($formFieldWatch, 'EditableCheckboxGroupField')) {
|
||||
$fieldToWatch = "$(\"input[name='".$dependency['ConditionField']."[".$dependency['Value']."]']\")";
|
||||
$fieldToWatchOnLoad = $fieldToWatch;
|
||||
}
|
||||
else if(is_a($formFieldWatch, 'EditableRadioField')) {
|
||||
$fieldToWatch = "$(\"input[name='".$dependency['ConditionField']."']\")";
|
||||
// We only want to trigger on load once for the radio group - hence we focus on the first option only.
|
||||
$fieldToWatchOnLoad = "$(\"input[name='".$dependency['ConditionField']."']:first\")";
|
||||
}
|
||||
else {
|
||||
$fieldToWatch = "$(\"input[name='".$dependency['ConditionField']."']\")";
|
||||
$fieldToWatchOnLoad = $fieldToWatch;
|
||||
}
|
||||
|
||||
// show or hide?
|
||||
$view = (isset($dependency['Display']) && $dependency['Display'] == "Hide") ? "hide" : "show";
|
||||
$opposite = ($view == "show") ? "hide" : "show";
|
||||
|
||||
// what action do we need to keep track of. Something nicer here maybe?
|
||||
// @todo encapulsation
|
||||
$action = "change";
|
||||
|
||||
if($formFieldWatch->ClassName == "EditableTextField") {
|
||||
$action = "keyup";
|
||||
}
|
||||
|
||||
// is this field a special option field
|
||||
$checkboxField = false;
|
||||
$radioField = false;
|
||||
foreach($field->CustomRules() as $rule) {
|
||||
|
||||
if(in_array($formFieldWatch->ClassName, array('EditableCheckboxGroupField', 'EditableCheckbox'))) {
|
||||
$action = "click";
|
||||
$checkboxField = true;
|
||||
}
|
||||
else if ($formFieldWatch->ClassName == "EditableRadioField") {
|
||||
$radioField = true;
|
||||
}
|
||||
// Get the field which is effected
|
||||
$formFieldWatch = EditableFormField::get()->byId($rule->ConditionFieldID);
|
||||
|
||||
// Escape the values.
|
||||
$dependency['Value'] = str_replace('"', '\"', $dependency['Value']);
|
||||
|
||||
// and what should we evaluate
|
||||
switch($dependency['ConditionOption']) {
|
||||
case 'IsNotBlank':
|
||||
$expression = ($checkboxField || $radioField) ? '$(this).prop("checked")' :'$(this).val() != ""';
|
||||
|
||||
break;
|
||||
case 'IsBlank':
|
||||
$expression = ($checkboxField || $radioField) ? '!($(this).prop("checked"))' : '$(this).val() == ""';
|
||||
|
||||
break;
|
||||
case 'HasValue':
|
||||
if ($checkboxField) {
|
||||
$expression = '$(this).prop("checked")';
|
||||
} else if ($radioField) {
|
||||
// We cannot simply get the value of the radio group, we need to find the checked option first.
|
||||
$expression = '$(this).parents(".field, .control-group").find("input:checked").val()=="'. $dependency['Value'] .'"';
|
||||
} else {
|
||||
$expression = '$(this).val() == "'. $dependency['Value'] .'"';
|
||||
}
|
||||
|
||||
break;
|
||||
case 'ValueLessThan':
|
||||
$expression = '$(this).val() < parseFloat("'. $dependency['Value'] .'")';
|
||||
|
||||
break;
|
||||
case 'ValueLessThanEqual':
|
||||
$expression = '$(this).val() <= parseFloat("'. $dependency['Value'] .'")';
|
||||
|
||||
break;
|
||||
case 'ValueGreaterThan':
|
||||
$expression = '$(this).val() > parseFloat("'. $dependency['Value'] .'")';
|
||||
|
||||
break;
|
||||
case 'ValueGreaterThanEqual':
|
||||
$expression = '$(this).val() >= parseFloat("'. $dependency['Value'] .'")';
|
||||
|
||||
break;
|
||||
default: // ==HasNotValue
|
||||
if ($checkboxField) {
|
||||
$expression = '!$(this).prop("checked")';
|
||||
} else if ($radioField) {
|
||||
// We cannot simply get the value of the radio group, we need to find the checked option first.
|
||||
$expression = '$(this).parents(".field, .control-group").find("input:checked").val()!="'. $dependency['Value'] .'"';
|
||||
} else {
|
||||
$expression = '$(this).val() != "'. $dependency['Value'] .'"';
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(!isset($watch[$fieldToWatch])) {
|
||||
$watch[$fieldToWatch] = array();
|
||||
}
|
||||
|
||||
$watch[$fieldToWatch][] = array(
|
||||
'expression' => $expression,
|
||||
'field_id' => $fieldId,
|
||||
'view' => $view,
|
||||
'opposite' => $opposite,
|
||||
'action' => $action
|
||||
);
|
||||
|
||||
$watchLoad[$fieldToWatchOnLoad] = true;
|
||||
|
||||
}
|
||||
if($formFieldWatch->RecordClassName == 'EditableDropdown') {
|
||||
// watch out for multiselect options - radios and check boxes
|
||||
$fieldToWatch = "$(\"select[name='" . $formFieldWatch->Name . "']\")";
|
||||
$fieldToWatchOnLoad = $fieldToWatch;
|
||||
} else if($formFieldWatch->RecordClassName == 'EditableCheckboxGroupField') {
|
||||
// watch out for checkboxs as the inputs don't have values but are 'checked
|
||||
$fieldToWatch = "$(\"input[name='" . $formFieldWatch->Name . "[" . $rule->FieldValue . "]']\")";
|
||||
$fieldToWatchOnLoad = $fieldToWatch;
|
||||
} else if($formFieldWatch->RecordClassName == 'EditableRadioField') {
|
||||
$fieldToWatch = "$(\"input[name='" . $formFieldWatch->Name . "']\")";
|
||||
// We only want to trigger on load once for the radio group - hence we focus on the first option only.
|
||||
$fieldToWatchOnLoad = "$(\"input[name='" . $formFieldWatch->Name . "']:first\")";
|
||||
} else {
|
||||
$fieldToWatch = "$(\"input[name='" . $formFieldWatch->Name . "']\")";
|
||||
$fieldToWatchOnLoad = $fieldToWatch;
|
||||
}
|
||||
|
||||
// show or hide?
|
||||
$view = ($rule->Display == 'Hide') ? 'hide' : 'show';
|
||||
$opposite = ($view == "show") ? "hide" : "show";
|
||||
|
||||
// what action do we need to keep track of. Something nicer here maybe?
|
||||
// @todo encapulsation
|
||||
$action = "change";
|
||||
|
||||
if($formFieldWatch->ClassName == "EditableTextField") {
|
||||
$action = "keyup";
|
||||
}
|
||||
|
||||
// is this field a special option field
|
||||
$checkboxField = false;
|
||||
$radioField = false;
|
||||
|
||||
if(in_array($formFieldWatch->ClassName, array('EditableCheckboxGroupField', 'EditableCheckbox'))) {
|
||||
$action = "click";
|
||||
$checkboxField = true;
|
||||
} else if ($formFieldWatch->ClassName == "EditableRadioField") {
|
||||
$radioField = true;
|
||||
}
|
||||
|
||||
// and what should we evaluate
|
||||
switch($rule->ConditionOption) {
|
||||
case 'IsNotBlank':
|
||||
$expression = ($checkboxField || $radioField) ? '$(this).prop("checked")' :'$(this).val() != ""';
|
||||
|
||||
break;
|
||||
case 'IsBlank':
|
||||
$expression = ($checkboxField || $radioField) ? '!($(this).prop("checked"))' : '$(this).val() == ""';
|
||||
|
||||
break;
|
||||
case 'HasValue':
|
||||
if ($checkboxField) {
|
||||
$expression = '$(this).prop("checked")';
|
||||
} else if ($radioField) {
|
||||
// We cannot simply get the value of the radio group, we need to find the checked option first.
|
||||
$expression = '$(this).parents(".field, .control-group").find("input:checked").val()=="'. $rule->FieldValue .'"';
|
||||
} else {
|
||||
$expression = '$(this).val() == "'. $rule->FieldValue .'"';
|
||||
}
|
||||
|
||||
break;
|
||||
case 'ValueLessThan':
|
||||
$expression = '$(this).val() < parseFloat("'. $rule->FieldValue .'")';
|
||||
|
||||
break;
|
||||
case 'ValueLessThanEqual':
|
||||
$expression = '$(this).val() <= parseFloat("'. $rule->FieldValue .'")';
|
||||
|
||||
break;
|
||||
case 'ValueGreaterThan':
|
||||
$expression = '$(this).val() > parseFloat("'. $rule->FieldValue .'")';
|
||||
|
||||
break;
|
||||
case 'ValueGreaterThanEqual':
|
||||
$expression = '$(this).val() >= parseFloat("'. $rule->FieldValue .'")';
|
||||
|
||||
break;
|
||||
default: // ==HasNotValue
|
||||
if ($checkboxField) {
|
||||
$expression = '!$(this).prop("checked")';
|
||||
} else if ($radioField) {
|
||||
// We cannot simply get the value of the radio group, we need to find the checked option first.
|
||||
$expression = '$(this).parents(".field, .control-group").find("input:checked").val()!="'. $rule->FieldValue .'"';
|
||||
} else {
|
||||
$expression = '$(this).val() != "'. $rule->FieldValue .'"';
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(!isset($watch[$fieldToWatch])) {
|
||||
$watch[$fieldToWatch] = array();
|
||||
}
|
||||
|
||||
$watch[$fieldToWatch][] = array(
|
||||
'expression' => $expression,
|
||||
'field_id' => $fieldId,
|
||||
'view' => $view,
|
||||
'opposite' => $opposite,
|
||||
'action' => $action
|
||||
);
|
||||
|
||||
$watchLoad[$fieldToWatchOnLoad] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -902,27 +554,7 @@ JS
|
||||
, 'UserFormsConditional');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a PHP array to a JSON string. We cannot use {@link Convert::array2json}
|
||||
* as it escapes our values with "" which appears to break the validate plugin
|
||||
*
|
||||
* @param Array array to convert
|
||||
* @return JSON
|
||||
*/
|
||||
public function array2json($array) {
|
||||
foreach($array as $key => $value) {
|
||||
if(is_array( $value )) {
|
||||
$result[] = "$key:" . $this->array2json($value);
|
||||
} else {
|
||||
$value = ( is_bool($value) || is_numeric($value) ) ? $value : "\"$value\"";
|
||||
$result[] = "$key:$value";
|
||||
}
|
||||
}
|
||||
|
||||
return (isset($result)) ? "{\n".implode( ', ', $result ) ."\n}\n": '{}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the form that is submitted through the site
|
||||
*
|
||||
@ -934,7 +566,7 @@ JS
|
||||
public function process($data, $form) {
|
||||
Session::set("FormInfo.{$form->FormName()}.data",$data);
|
||||
Session::clear("FormInfo.{$form->FormName()}.errors");
|
||||
|
||||
|
||||
foreach($this->Fields() as $field) {
|
||||
$messages[$field->Name] = $field->getErrorMessage()->HTML();
|
||||
$formField = $field->getFormField();
|
||||
@ -953,13 +585,13 @@ JS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(Session::get("FormInfo.{$form->FormName()}.errors")){
|
||||
Controller::curr()->redirectBack();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$submittedForm = Object::create('SubmittedForm');
|
||||
$submittedForm->SubmittedByID = ($id = Member::currentUserID()) ? $id : 0;
|
||||
$submittedForm->ParentID = $this->ID;
|
||||
@ -968,22 +600,22 @@ JS
|
||||
if(!$this->DisableSaveSubmissions) {
|
||||
$submittedForm->write();
|
||||
}
|
||||
|
||||
|
||||
$values = array();
|
||||
$attachments = array();
|
||||
|
||||
$submittedFields = new ArrayList();
|
||||
|
||||
|
||||
foreach($this->Fields() as $field) {
|
||||
if(!$field->showInReports()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$submittedField = $field->getSubmittedFormField();
|
||||
$submittedField->ParentID = $submittedForm->ID;
|
||||
$submittedField->Name = $field->Name;
|
||||
$submittedField->Title = $field->getField('Title');
|
||||
|
||||
|
||||
// save the value from the data
|
||||
if($field->hasMethod('getValueFromData')) {
|
||||
$submittedField->Value = $field->getValueFromData($data);
|
||||
@ -1021,23 +653,23 @@ JS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$submittedField->extend('onPopulationFromField', $field);
|
||||
|
||||
if(!$this->DisableSaveSubmissions) {
|
||||
$submittedField->write();
|
||||
}
|
||||
|
||||
|
||||
$submittedFields->push($submittedField);
|
||||
}
|
||||
|
||||
|
||||
$emailData = array(
|
||||
"Sender" => Member::currentUser(),
|
||||
"Fields" => $submittedFields
|
||||
);
|
||||
|
||||
|
||||
$this->extend('updateEmailData', $emailData, $attachments);
|
||||
|
||||
|
||||
// email users on submit.
|
||||
if($recipients = $this->FilteredEmailRecipients($data, $form)) {
|
||||
$email = new UserDefinedForm_SubmittedFormEmail($submittedFields);
|
||||
@ -1117,7 +749,7 @@ JS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$submittedForm->extend('updateAfterProcess');
|
||||
|
||||
Session::clear("FormInfo.{$form->FormName()}.errors");
|
||||
@ -1125,7 +757,6 @@ JS
|
||||
|
||||
$referrer = (isset($data['Referrer'])) ? '?referrer=' . urlencode($data['Referrer']) : "";
|
||||
|
||||
|
||||
// set a session variable from the security ID to stop people accessing
|
||||
// the finished method directly.
|
||||
if(!$this->DisableAuthenicatedFinishAction) {
|
||||
@ -1142,7 +773,7 @@ JS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!$this->DisableSaveSubmissions) {
|
||||
Session::set('userformssubmission'. $this->ID, $submittedForm->ID);
|
||||
}
|
168
code/tasks/UserFormsUpgradeTask.php
Normal file
168
code/tasks/UserFormsUpgradeTask.php
Normal file
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Assists with upgrade of userforms to 3.0
|
||||
*
|
||||
* @author dmooyman
|
||||
*/
|
||||
class UserFormsUpgradeTask extends BuildTask {
|
||||
|
||||
protected $title = "UserForms 3.0 Migration Tool";
|
||||
|
||||
protected $description = "Upgrade tool for sites upgrading to userforms 3.0";
|
||||
|
||||
public function run($request) {
|
||||
$this->log("Upgrading userforms module");
|
||||
$this->upgradeRules();
|
||||
$this->log("Done");
|
||||
}
|
||||
|
||||
protected function log($message) {
|
||||
if(Director::is_cli()) {
|
||||
echo "{$message}\n";
|
||||
} else {
|
||||
echo "{$message}<br />";
|
||||
}
|
||||
}
|
||||
|
||||
protected function upgradeRules() {
|
||||
$this->log("Upgrading formfield rules");
|
||||
|
||||
// Upgrade rules from EditableFormField.CustomRules into dataobjects
|
||||
$fields = DB::fieldList('EditableFormField');
|
||||
if(!isset($fields['CustomRules'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// List of rules that have been created in all stages
|
||||
$fields = Versioned::get_including_deleted('EditableFormField');
|
||||
foreach($fields as $field) {
|
||||
$this->upgradeFieldRules($field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate a versioned field in all stages
|
||||
*
|
||||
* @param EditableFormField $field
|
||||
*/
|
||||
protected function upgradeFieldRules(EditableFormField $field) {
|
||||
$this->log("Upgrading formfield ID = ".$field->ID);
|
||||
|
||||
// Check versions this field exists on
|
||||
$filter = sprintf('"EditableFormField"."ID" = \'%d\'', $field->ID);
|
||||
$stageField = Versioned::get_one_by_stage('EditableFormField', 'Stage', $filter);
|
||||
$liveField = Versioned::get_one_by_stage('EditableFormField', 'Live', $filter);
|
||||
|
||||
if($stageField) {
|
||||
$this->upgradeFieldRulesInStage($stageField, 'Stage');
|
||||
}
|
||||
|
||||
if($liveField) {
|
||||
$this->upgradeFieldRulesInStage($liveField, 'Live');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate a versioned field in a single stage
|
||||
*
|
||||
* @param EditableFormField $field
|
||||
* @param stage $stage
|
||||
*/
|
||||
protected function upgradeFieldRulesInStage(EditableFormField $field, $stage) {
|
||||
Versioned::reading_stage($stage);
|
||||
|
||||
// Skip rules with empty data
|
||||
$rulesData = $this->getRuleData($field->ID);
|
||||
if(empty($rulesData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip migrated records
|
||||
if($field->CustomRules()->count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check value of this condition
|
||||
foreach($rulesData as $ruleDataItem) {
|
||||
if(empty($ruleDataItem['ConditionOption']) || empty($ruleDataItem['Display'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get data for this rule
|
||||
$conditionOption = $ruleDataItem['ConditionOption'];
|
||||
$display = $ruleDataItem['Display'];
|
||||
$conditionFieldName = empty($ruleDataItem['ConditionField']) ? null : $ruleDataItem['ConditionField'];
|
||||
$value = isset($ruleDataItem['Value'])
|
||||
? $ruleDataItem['Value']
|
||||
: null;
|
||||
|
||||
// Create rule
|
||||
$rule = $this->findOrCreateRule($field, $stage, $conditionOption, $display, $conditionFieldName, $value);
|
||||
$this->log("Upgrading rule ID = " . $rule->ID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or find an existing field with the matched specification
|
||||
*
|
||||
* @param EditableFormField $field
|
||||
* @param string $stage
|
||||
* @param string $conditionOption
|
||||
* @param string $display
|
||||
* @param string $conditionFieldName
|
||||
* @param string $value
|
||||
* @return EditableCustomRule
|
||||
*/
|
||||
protected function findOrCreateRule(EditableFormField $field, $stage, $conditionOption, $display, $conditionFieldName, $value) {
|
||||
// Get id of field
|
||||
$conditionField = $conditionFieldName
|
||||
? EditableFormField::get()->filter('Name', $conditionFieldName)->first()
|
||||
: null;
|
||||
|
||||
// If live, search stage record for matching one
|
||||
if($stage === 'Live') {
|
||||
$list = Versioned::get_by_stage('EditableCustomRule', 'Stage')
|
||||
->filter(array(
|
||||
'ParentID' => $field->ID,
|
||||
'ConditionFieldID' => $conditionField ? $conditionField->ID : 0,
|
||||
'Display' => $display,
|
||||
'ConditionOption' => $conditionOption
|
||||
));
|
||||
if($value) {
|
||||
$list = $list->filter('FieldValue', $value);
|
||||
} else {
|
||||
$list = $list->where('"FieldValue" IS NULL OR "FieldValue" = \'\'');
|
||||
}
|
||||
$rule = $list->first();
|
||||
if($rule) {
|
||||
$rule->write();
|
||||
$rule->publish("Stage", "Live");
|
||||
return $rule;
|
||||
}
|
||||
}
|
||||
|
||||
// If none found, or in stage, create new record
|
||||
$rule = new EditableCustomRule();
|
||||
$rule->ParentID = $field->ID;
|
||||
$rule->ConditionFieldID = $conditionField ? $conditionField->ID : 0;
|
||||
$rule->Display = $display;
|
||||
$rule->ConditionOption = $conditionOption;
|
||||
$rule->FieldValue = $value;
|
||||
$rule->write();
|
||||
return $rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get deserialised rule data for a field
|
||||
*
|
||||
* @param type $id
|
||||
*/
|
||||
protected function getRuleData($id) {
|
||||
$rules = DB::query(sprintf(
|
||||
'SELECT "CustomRules" FROM "EditableFormField" WHERE "ID" = %d',
|
||||
$id
|
||||
))->value();
|
||||
return $rules ? unserialize($rules) : array();
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 76 KiB |
Binary file not shown.
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 45 KiB |
Binary file not shown.
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 82 KiB |
@ -53,8 +53,8 @@ puts the form at the end of all the content.
|
||||
## Adding fields
|
||||
|
||||
To add a field to the form, click on the "Form" tab under the "Content" tab in the
|
||||
Editing Pane. Select the type of field you want to add from the drop-down menu and
|
||||
press the "Add" button. You can label any field by typing in the appropriate label field in the backend.
|
||||
Editing Pane. Click the "Add" button then select the type of field you want from the dropdown.
|
||||
Save or publish the form to start editing your new field's properties.
|
||||
|
||||
![Adding fields](_images/add-fields.png)
|
||||
|
||||
|
@ -1,134 +0,0 @@
|
||||
<!-- JS Relys on EditableFormField as a class - and the 3 ids in this order - do not change -->
|
||||
<li class="$ClassName EditableFormField" id="$Name.ATT EditableItem_$Pos $Name">
|
||||
<div class="fieldInfo">
|
||||
<% if canEdit %>
|
||||
<img class="fieldHandler" src="$ModulePath(framework)/images/drag.gif" alt="<% _t('EditableFormField.DRAG', 'Drag to rearrange order of fields') %>" />
|
||||
<% else %>
|
||||
<img class="fieldHandler" src="$ModulePath(framework)/images/drag_readonly.gif" alt="<% _t('EditableFormField.LOCKED', 'These fields cannot be modified') %>" />
|
||||
<% end_if %>
|
||||
|
||||
<img class="icon" src="$Icon" alt="$ClassName" title="$singular_name" />
|
||||
|
||||
$TitleField
|
||||
</div>
|
||||
|
||||
<div class="fieldActions">
|
||||
<% if showExtraOptions %>
|
||||
<a class="moreOptions" href="#" title="<% _t('EditableFormField.SHOWOPTIONS', 'Show Options') %>"><% _t('EditableFormField.SHOWOPTIONS','Show Options') %></a>
|
||||
<% end_if %>
|
||||
|
||||
<% if canDelete %>
|
||||
<a class="delete" href="#" title="<% _t('EditableFormField.DELETE', 'Delete') %>"><% _t('EditableFormField.DELETE', 'Delete') %></a>
|
||||
<% end_if %>
|
||||
</div>
|
||||
|
||||
<% if showExtraOptions %>
|
||||
<div class="extraOptions hidden" id="$Name.ATT-extraOptions">
|
||||
<% if HasAddableOptions %>
|
||||
<fieldset class="fieldOptionsGroup">
|
||||
<legend><% _t('EditableFormField.OPTIONS', 'Options') %></legend>
|
||||
<ul class="editableOptions" id="$FieldName.ATT-list">
|
||||
|
||||
<% if canEdit %>
|
||||
<% loop Options %>
|
||||
$EditSegment
|
||||
<% end_loop %>
|
||||
<% if HasAddableOptions %>
|
||||
<li class="{$ClassName}Option">
|
||||
<a href="#" rel="$ID" class="addableOption" title="<% _t('EditableFormField.ADD', 'Add option to field') %>">
|
||||
<% _t('EditableFormField.ADDLabel', 'Add option') %>
|
||||
</a>
|
||||
</li>
|
||||
<% end_if %>
|
||||
<% else %>
|
||||
<% loop Options %>
|
||||
$ReadonlyOption
|
||||
<% end_loop %>
|
||||
<% end_if %>
|
||||
</ul>
|
||||
</fieldset>
|
||||
<% end_if %>
|
||||
|
||||
<% if FieldConfiguration %>
|
||||
<fieldset class="fieldOptionsGroup">
|
||||
<legend><% _t('EditableFormField.FIELDCONFIGURATION', 'Field Configuration') %></legend>
|
||||
<% loop FieldConfiguration %>
|
||||
$FieldHolder
|
||||
<% end_loop %>
|
||||
</fieldset>
|
||||
<% end_if %>
|
||||
|
||||
<% if FieldValidationOptions %>
|
||||
<fieldset class="fieldOptionsGroup">
|
||||
<legend><% _t('EditableFormField.VALIDATION', 'Validation') %></legend>
|
||||
<% loop FieldValidationOptions %>
|
||||
$FieldHolder
|
||||
<% end_loop %>
|
||||
</fieldset>
|
||||
<% end_if %>
|
||||
|
||||
<fieldset class="customRules fieldOptionsGroup">
|
||||
<legend><% _t('EditableFormField.CUSTOMRULES', 'Custom Rules') %></legend>
|
||||
<ul id="{$FieldName}-customRules">
|
||||
<li>
|
||||
<a href="#" class="addCondition" title="<% _t('EditableFormField.ADD', 'Add') %>"><% _t('EditableFormField.ADDRULE', 'Add Rule') %></a>
|
||||
</li>
|
||||
<li class="addCustomRule">
|
||||
<select name="{$FieldName}[CustomSettings][ShowOnLoad]">
|
||||
<option value="Show" <% if ShowOnLoad %>selected="selected"<% end_if %>><% _t('EditableFormField.SHOW', 'Show') %></option>
|
||||
<option value="Hide" <% if ShowOnLoad %><% else %>selected="selected"<% end_if %>><% _t('EditableFormField.HIDE', 'Hide') %></option>
|
||||
</select>
|
||||
|
||||
<label class="left"><% _t('EditableFormField.FIELDONDEFAULT', 'Field On Default') %></label>
|
||||
</li>
|
||||
<li class="hidden">
|
||||
<select class="displayOption customRuleField" name="{$FieldName}[CustomRules][Display]">
|
||||
<option value="Show"><% _t('EditableFormField.SHOWTHISFIELD', 'Show This Field') %></option>
|
||||
<option value="Hide"><% _t('EditableFormField.HIDETHISFIELD', 'Hide This Field') %></option>
|
||||
</select>
|
||||
|
||||
<label><% _t('EditableFormField.WHEN', 'When') %></label>
|
||||
<select class="fieldOption customRuleField" name="{$FieldName}[CustomRules][ConditionField]">
|
||||
<option></option>
|
||||
<% loop Parent %>
|
||||
<% if Fields %>
|
||||
<% loop Fields %>
|
||||
<option value="$Name"><% if Title %>$Title<% else %>$Name<% end_if %></option>
|
||||
<% end_loop %>
|
||||
<% end_if %>
|
||||
<% end_loop %>
|
||||
</select>
|
||||
|
||||
<label><% _t('EditableFormField.IS', 'Is') %></label>
|
||||
<select class="conditionOption customRuleField" name="{$FieldName}[CustomRules][ConditionOption]">
|
||||
<option value=""></option>
|
||||
<option value="IsBlank"><% _t('EditableFormField.BLANK', 'Blank') %></option>
|
||||
<option value="IsNotBlank"><% _t('EditableFormField.NOTBLANK', 'Not Blank') %></option>
|
||||
<option value="HasValue"><% _t('EditableFormField.VALUE', 'Value') %></option>
|
||||
<option value="ValueNot"><% _t('EditableFormField.NOTVALUE', 'Not Value') %></option>
|
||||
<option value="ValueLessThan"><% _t('EditableFormField.LESSTHAN', 'Value Less Than') %></option>
|
||||
<option value="ValueLessThanEqual"><% _t('EditableFormField.LESSTHANEQUAL', 'Value Less Than Or Equal') %></option>
|
||||
<option value="ValueGreaterThan"><% _t('EditableFormField.GREATERTHAN', 'Value Greater Than') %></option>
|
||||
<option value="ValueGreaterThanEqual"><% _t('EditableFormField.GREATERTHANEQUAL', 'Value Greater Than Or Equal') %></option>
|
||||
</select>
|
||||
|
||||
<input type="text" class="ruleValue hidden customRuleField" name="{$FieldName}[CustomRules][Value]" />
|
||||
|
||||
<a href="#" class="deleteCondition" title="<% _t('EditableFormField.DELETE', 'Delete') %>"><img src="cms/images/delete.gif" alt="<% _t('EditableFormField.DELETE', 'Delete') %>" /></a>
|
||||
</li>
|
||||
<% if CustomRules %>
|
||||
<% loop CustomRules %>
|
||||
<li>
|
||||
<% include CustomRule %>
|
||||
</li>
|
||||
<% end_loop %>
|
||||
<% end_if %>
|
||||
</ul>
|
||||
</fieldset>
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
<!-- Hidden option Fields -->
|
||||
<input type="hidden" class="typeHidden" name="{$FieldName}[Type]" value="$ClassName" />
|
||||
<input type="hidden" class="sortHidden" name="{$FieldName}[Sort]" value="$Sort" />
|
||||
</li>
|
@ -1,28 +0,0 @@
|
||||
<select class="displayOption customRuleField" name="{$FieldName}[CustomRules][$Pos][Display]">
|
||||
<option value="Show" <% if Display = Show %>selected="selected"<% end_if %>><% _t('CustomRule.SHOWTHISFIELD', 'Show This Field') %></option>
|
||||
<option value="Hide" <% if Display = Hide %>selected="selected"<% end_if %>><% _t('CustomRule.HIDETHISFIELD', 'Hide This Field') %></option>
|
||||
</select>
|
||||
|
||||
<label><% _t('CustomRule.WHEN', 'When') %></label>
|
||||
<select class="fieldOption customRuleField" name="{$FieldName}[CustomRules][$Pos][ConditionField]">
|
||||
<option value="" selected="selected"></option>
|
||||
<% loop Fields %>
|
||||
<option value="$Name" <% if isSelected %>selected="selected"<% end_if %>>$Title</option>
|
||||
<% end_loop %>
|
||||
</select>
|
||||
|
||||
<label><% _t('CustomRule.IS', 'Is') %></label>
|
||||
<select class="conditionOption customRuleField" name="{$FieldName}[CustomRules][$Pos][ConditionOption]">
|
||||
<option value="IsBlank" <% if ConditionOption = IsBlank %>selected="selected"<% end_if %>><% _t('CustomRule.BLANK', 'Blank') %></option>
|
||||
<option value="IsNotBlank" <% if ConditionOption = IsNotBlank %>selected="selected"<% end_if %>><% _t('CustomRule.NOTBLANK', 'Not Blank') %></option>
|
||||
<option value="HasValue" <% if ConditionOption = HasValue %>selected="selected"<% end_if %>><% _t('CustomRule.VALUE', 'Value') %></option>
|
||||
<option value="ValueNot" <% if ConditionOption = ValueNot %>selected="selected"<% end_if %>><% _t('CustomRule.NOTVALUE', 'Not Value') %></option>
|
||||
<option value="ValueLessThan" <% if ConditionOption = ValueLessThan %>selected="selected"<% end_if %>><% _t('CustomRule.LESSTHAN', 'Value Less Than') %></option>
|
||||
<option value="ValueLessThanEqual" <% if ConditionOption = ValueLessThanEqual %>selected="selected"<% end_if %>><% _t('CustomRule.LESSTHANEQUAL', 'Value Less Than Or Equal') %></option>
|
||||
<option value="ValueGreaterThan" <% if ConditionOption = ValueGreaterThan %>selected="selected"<% end_if %>><% _t('CustomRule.GREATERTHAN', 'Value Greater Than') %></option>
|
||||
<option value="ValueGreaterThanEqual" <% if ConditionOption = ValueGreaterThanEqual %>selected="selected"<% end_if %>><% _t('CustomRule.GREATERTHANEQUAL', 'Value Greater Than Or Equal') %></option>
|
||||
</select>
|
||||
|
||||
<input type="text" class="ruleValue <% if ConditionOption %><% if ConditionOption = IsBlank %>hidden<% else_if ConditionOption = IsNotBlank %>hidden<% end_if %><% else %>hidden<% end_if %> customRuleField" name="{$FieldName}[CustomRules][$Pos][Value]" value="$Value" />
|
||||
|
||||
<a href="#" class="deleteCondition" title="<% _t('CustomRule.DELETE', 'Delete') %>"><img src="cms/images/delete.gif" alt="<% _t('CustomRule.DELETE', 'Delete') %>" /></a>
|
@ -82,58 +82,6 @@ class EditableFormFieldTest extends FunctionalTest {
|
||||
$text->setSetting('ShowOnLoad', '');
|
||||
$this->assertTrue($text->getShowOnLoad());
|
||||
}
|
||||
|
||||
|
||||
function testPopulateFromPostData() {
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$set = new ArrayList();
|
||||
|
||||
$field = new EditableFormField();
|
||||
|
||||
$data = array(
|
||||
'Title' => 'Field Title',
|
||||
'Default' => 'Default Value',
|
||||
'Sort' => '2',
|
||||
'Required' => 0,
|
||||
'CustomErrorMessage' => 'Custom'
|
||||
);
|
||||
|
||||
$field->populateFromPostData($data);
|
||||
$set->push($field);
|
||||
$this->assertDOSEquals(array($data), $set);
|
||||
|
||||
// test the custom settings
|
||||
$data['CustomSettings'] = array(
|
||||
'Foo' => 'Bar'
|
||||
);
|
||||
|
||||
$checkbox = new EditableCheckbox();
|
||||
$checkbox->write();
|
||||
|
||||
$checkbox->populateFromPostData(array('Title' => 'Checkbox'));
|
||||
|
||||
$field->populateFromPostData($data);
|
||||
|
||||
$this->assertEquals($field->getSettings(), array('Foo' => 'Bar'));
|
||||
|
||||
$rule = array(
|
||||
'Display' => 'Hide',
|
||||
'ConditionField' => $checkbox->Name,
|
||||
'ConditionOption' => 'HasValue',
|
||||
'Value' => 6
|
||||
);
|
||||
|
||||
// test the custom rules
|
||||
$data['CustomRules'] = array(
|
||||
'Rule1' => $rule
|
||||
);
|
||||
|
||||
$field->populateFromPostData($data);
|
||||
|
||||
$rules = unserialize($field->CustomRules);
|
||||
|
||||
$this->assertEquals($rules[0], $rule);
|
||||
}
|
||||
|
||||
function testCustomRules() {
|
||||
$this->logInWithPermission('ADMIN');
|
||||
@ -142,58 +90,18 @@ class EditableFormFieldTest extends FunctionalTest {
|
||||
$checkbox = $form->Fields()->find('ClassName', 'EditableCheckbox');
|
||||
$field = $form->Fields()->find('ClassName', 'EditableTextField');
|
||||
|
||||
$rule = array(
|
||||
'Display' => 'Hide',
|
||||
'ConditionField' => $checkbox->Name,
|
||||
'ConditionOption' => 'HasValue',
|
||||
'Value' => 6
|
||||
);
|
||||
$rules = $checkbox->CustomRules();
|
||||
|
||||
$data['CustomRules'] = array(
|
||||
'Rule1' => $rule
|
||||
);
|
||||
|
||||
$field->populateFromPostData($data);
|
||||
|
||||
$rules = $field->CustomRules();
|
||||
|
||||
// form has 2 fields - a checkbox and a text field
|
||||
// it has 1 rule - when ticked the checkbox hides the text field
|
||||
$this->assertEquals($rules->Count(), 1);
|
||||
|
||||
// rules are ArrayDatas not dataobjects
|
||||
// $this->assertDOSEquals(array($rule), $rules);
|
||||
|
||||
$checkboxRule = $rules->First();
|
||||
$checkboxRule->ConditionFieldID = $field->ID;
|
||||
|
||||
$this->assertEquals($checkboxRule->Display, 'Hide');
|
||||
$this->assertEquals($checkboxRule->ConditionField, $checkbox->Name);
|
||||
$this->assertEquals($checkboxRule->ConditionOption, 'HasValue');
|
||||
$this->assertEquals($checkboxRule->Value, '6');
|
||||
|
||||
foreach($checkboxRule->Fields as $condition) {
|
||||
if($checkbox->Name == $condition->Name) {
|
||||
$this->assertTrue($condition->isSelected);
|
||||
}
|
||||
else {
|
||||
$this->assertFalse($condition->isSelected);
|
||||
}
|
||||
}
|
||||
|
||||
$data['CustomRules'] = array(
|
||||
'Rule2' => array(
|
||||
'Display' => 'Hide',
|
||||
'ConditionField' => $checkbox->Name,
|
||||
'ConditionOption' => 'Blank'
|
||||
)
|
||||
);
|
||||
|
||||
$field->populateFromPostData($data);
|
||||
|
||||
$rules = $field->CustomRules();
|
||||
|
||||
// test that saving additional rules deletes the old one
|
||||
$this->assertEquals($rules->Count(), 1);
|
||||
|
||||
$this->assertEquals($checkboxRule->FieldValue, '6');
|
||||
}
|
||||
|
||||
function testEditableDropdownField() {
|
||||
@ -262,50 +170,6 @@ class EditableFormFieldTest extends FunctionalTest {
|
||||
$this->assertEquals($orginal->Sort, $option->Sort);
|
||||
}
|
||||
}
|
||||
|
||||
function testMultipleOptionPopulateFromPostData() {
|
||||
$dropdown = $this->objFromFixture('EditableDropdown','basic-dropdown');
|
||||
|
||||
$data = array();
|
||||
|
||||
foreach($dropdown->Options() as $option) {
|
||||
$orginal[$option->ID] = array(
|
||||
'Title' => $option->Title,
|
||||
'Sort' => $option->Sort
|
||||
);
|
||||
|
||||
$data[$option->ID] = array(
|
||||
'Title' => 'New - '. $option->Title,
|
||||
'Sort' => $option->Sort + 1
|
||||
);
|
||||
}
|
||||
|
||||
$dropdown->populateFromPostData($data);
|
||||
|
||||
$count = $dropdown->Options()->Count();
|
||||
|
||||
foreach($dropdown->Options() as $option) {
|
||||
$this->assertEquals($option->Title, 'New - '. $orginal[$option->ID]['Title']);
|
||||
$this->assertEquals($option->Sort, $orginal[$option->ID]['Sort'] + 1);
|
||||
}
|
||||
|
||||
// remove the first one. can't assume by ID
|
||||
foreach($data as $key => $value) {
|
||||
unset($data[$key]);
|
||||
break;
|
||||
}
|
||||
|
||||
$dropdown->populateFromPostData($data);
|
||||
|
||||
$this->assertEquals($dropdown->Options()->Count(), $count-1);
|
||||
}
|
||||
|
||||
function testEditableTextFieldConfiguration() {
|
||||
// $text = $this->objFromFixture('EditableTextField', 'basic-text');
|
||||
|
||||
// $configuration = $text->getFieldConfiguration();
|
||||
|
||||
}
|
||||
|
||||
function testExtendedEditableFormField() {
|
||||
/** @var ExtendedEditableFormField $field */
|
||||
@ -316,11 +180,6 @@ class EditableFormFieldTest extends FunctionalTest {
|
||||
$this->assertTrue(array_key_exists('TestExtraField', $dbFields));
|
||||
$this->assertTrue(array_key_exists('TestValidationField', $dbFields));
|
||||
|
||||
// Check Field Configuration
|
||||
$fieldConfiguration = $field->getFieldConfiguration();
|
||||
$extraField = $fieldConfiguration->dataFieldByName($field->getSettingName('TestExtraField'));
|
||||
$this->assertNotNull($extraField);
|
||||
|
||||
// Check Validation Fields
|
||||
$fieldValidation = $field->getFieldValidationOptions();
|
||||
$validationField = $fieldValidation->dataFieldByName($field->getSettingName('TestValidationField'));
|
||||
|
@ -1,8 +1,14 @@
|
||||
EditableCustomRule:
|
||||
rule-1:
|
||||
Display: Hide
|
||||
ConditionOption: HasValue
|
||||
FieldValue: 6
|
||||
|
||||
EditableOption:
|
||||
option-1:
|
||||
Name: Option1
|
||||
Title: Option 1
|
||||
|
||||
|
||||
option-2:
|
||||
Name: Option2
|
||||
Title: Option 2
|
||||
@ -30,79 +36,82 @@ EditableOption:
|
||||
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
|
||||
|
||||
|
||||
checkbox-with-rule:
|
||||
Name: checkbox-with-rule
|
||||
Title: Checkbox with rule
|
||||
CustomRules: =>EditableCustomRule.rule-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
|
||||
|
||||
|
||||
|
||||
EditableFileField:
|
||||
file-field:
|
||||
Name: file-uploader
|
||||
@ -120,20 +129,18 @@ UserDefinedForm:
|
||||
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
|
||||
Fields: =>EditableCheckbox.checkbox-with-rule, =>EditableTextField.basic-text-2
|
||||
empty-form:
|
||||
Title: Empty Form
|
||||
|
||||
|
||||
|
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tests covering the form editor / builder and
|
||||
* some of the user interface
|
||||
*
|
||||
* @package userforms
|
||||
*/
|
||||
|
||||
class FieldEditorTest extends FunctionalTest {
|
||||
|
||||
static $fixture_file = 'userforms/tests/UserDefinedFormTest.yml';
|
||||
|
||||
protected $editor;
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
|
||||
|
||||
$controller = new FieldEditorTest_Controller($form);
|
||||
|
||||
$fields = $controller->Form()->Fields();
|
||||
|
||||
$this->editor = $fields->fieldByName('Fields');
|
||||
}
|
||||
|
||||
function testSaveInto() {
|
||||
$this->logInWithPermission('ADMIN');
|
||||
|
||||
// @todo
|
||||
}
|
||||
|
||||
function testAddField() {
|
||||
$this->logInWithPermission('ADMIN');
|
||||
|
||||
// Debug::show($this->editor->addfield());
|
||||
}
|
||||
}
|
||||
|
||||
class FieldEditorTest_Controller extends Controller {
|
||||
|
||||
public function Form() {
|
||||
return new Form($this, 'Form', new FieldList(new FieldEditor('Fields')), new FieldList());
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
||||
|
||||
// load the form
|
||||
$this->get($form->URLSegment);
|
||||
$response = $this->submitForm('Form_Form', null, array('basic-text-name' => 'Basic Value'));
|
||||
$response = $this->submitForm('UserForm_Form', null, array('basic-text-name' => 'Basic Value'));
|
||||
|
||||
// should have a submitted form field now
|
||||
$submitted = DataObject::get('SubmittedFormField', "\"Name\" = 'basic-text-name'");
|
||||
@ -106,7 +106,7 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
||||
|
||||
$controller = new UserDefinedFormControllerTest_Controller($form);
|
||||
|
||||
$fields = $controller->getFormFields();
|
||||
$fields = $controller->Form()->getFormFields();
|
||||
|
||||
$this->assertEquals($fields->Count(), 1);
|
||||
|
||||
@ -116,7 +116,7 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
||||
|
||||
UserDefinedForm::config()->required_identifier = "*";
|
||||
|
||||
$fields = $controller->getFormFields();
|
||||
$fields = $controller->Form()->getFormFields();
|
||||
|
||||
$this->assertEquals($fields->First()->getCustomValidationMessage()->getValue(), 'Custom Error Message');
|
||||
$this->assertEquals($fields->First()->Title(), 'Required Text Field <span class=\'required-identifier\'>*</span>');
|
||||
@ -127,15 +127,15 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
||||
$field->write();
|
||||
|
||||
$controller = new UserDefinedFormControllerTest_Controller($form);
|
||||
$fields = $controller->getFormFields();
|
||||
$fields = $controller->Form()->getFormFields();
|
||||
|
||||
$this->assertEquals($fields->First()->RightTitle(), "Right Title");
|
||||
|
||||
// test empty form
|
||||
$emptyForm = $this->objFromFixture('UserDefinedForm', 'empty-form');
|
||||
$controller = new UserDefinedFormControllerTest_Controller($emptyForm);
|
||||
|
||||
$this->assertFalse($controller->Form());
|
||||
|
||||
$this->assertFalse($controller->Form()->getFormFields()->exists());
|
||||
}
|
||||
|
||||
function testGetFormActions() {
|
||||
@ -143,7 +143,7 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
||||
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
|
||||
|
||||
$controller = new UserDefinedFormControllerTest_Controller($form);
|
||||
$actions = $controller->getFormActions();
|
||||
$actions = $controller->Form()->getFormActions();
|
||||
|
||||
// by default will have 1 submit button which links to process
|
||||
$expected = new FieldList(new FormAction('process', 'Submit'));
|
||||
@ -153,23 +153,14 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
||||
// the custom popup should have a reset button and a custom text
|
||||
$custom = $this->objFromFixture('UserDefinedForm', 'form-with-reset-and-custom-action');
|
||||
$controller = new UserDefinedFormControllerTest_Controller($custom);
|
||||
|
||||
$actions = $controller->getFormActions();
|
||||
$actions = $controller->Form()->getFormActions();
|
||||
|
||||
$expected = new FieldList(new FormAction('process', 'Custom Button'));
|
||||
$expected->push(new ResetFormAction("clearForm", "Clear"));
|
||||
|
||||
|
||||
$this->assertEquals($actions, $expected);
|
||||
}
|
||||
|
||||
function testArrayToJson() {
|
||||
$array = array('1' => 'one', '2' => 'two');
|
||||
$string = "{\n1:\"one\", 2:\"two\"\n}\n";
|
||||
$form = new UserDefinedFormControllerTest_Controller();
|
||||
$this->assertEquals($form->array2json($array), $string);
|
||||
}
|
||||
|
||||
|
||||
function testRenderingIntoFormTemplate() {
|
||||
$form = $this->setupFormFrontend();
|
||||
|
||||
@ -210,7 +201,7 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
||||
}
|
||||
|
||||
function checkTemplateIsCorrect($parser) {
|
||||
$this->assertArrayHasKey(0, $parser->getBySelector('form#Form_Form'));
|
||||
$this->assertArrayHasKey(0, $parser->getBySelector('form#UserForm_Form'));
|
||||
|
||||
// check for the input
|
||||
$this->assertArrayHasKey(0, $parser->getBySelector('input.text'));
|
||||
|
Loading…
x
Reference in New Issue
Block a user