mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 17:05:42 +02:00
API new form editor
This commit is contained in:
parent
8f92d75975
commit
51864a6308
@ -1,6 +1,9 @@
|
|||||||
# See https://github.com/silverstripe-labs/silverstripe-travis-support for setup details
|
# See https://github.com/silverstripe-labs/silverstripe-travis-support for setup details
|
||||||
|
|
||||||
language: php
|
language: php
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 5.4
|
- 5.4
|
||||||
|
|
||||||
|
@ -3,3 +3,5 @@
|
|||||||
if(!defined('USERFORMS_DIR')) {
|
if(!defined('USERFORMS_DIR')) {
|
||||||
define('USERFORMS_DIR', basename(__DIR__));
|
define('USERFORMS_DIR', basename(__DIR__));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Deprecation::notification_version('3.0', 'userforms');
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
name: userforms
|
|
||||||
---
|
|
||||||
LeftAndMain:
|
|
||||||
extra_requirements_javascript:
|
|
||||||
- userforms/javascript/UserForm.js
|
|
||||||
|
|
||||||
extra_requirements_css:
|
|
||||||
- userforms/css/FieldEditor.css
|
|
186
code/extensions/UserFormFieldEditorExtension.php
Normal file
186
code/extensions/UserFormFieldEditorExtension.php
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
<?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->insertAfter(new Tab('FormFields', _t('UserFormFieldEditorExtension.FORMFIELDS', 'Form Fields')), 'Main');
|
||||||
|
$fields->addFieldToTab('Root.FormFields', $fieldEditor);
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the field editor, for adding and removing EditableFormFields.
|
||||||
|
*
|
||||||
|
* @return GridField
|
||||||
|
*/
|
||||||
|
public function getFieldEditorGrid() {
|
||||||
|
$fields = $this->owner->Fields();
|
||||||
|
|
||||||
|
$editableColumns = new GridFieldEditableColumns();
|
||||||
|
$editableColumns->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'));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
$fieldEditor = GridField::create(
|
||||||
|
'Fields',
|
||||||
|
_t('UserDefinedForm.FIELDS', 'Fields'),
|
||||||
|
$fields,
|
||||||
|
GridFieldConfig::create()
|
||||||
|
->addComponents(
|
||||||
|
$editableColumns,
|
||||||
|
new GridFieldButtonRow(),
|
||||||
|
new GridFieldAddNewInlineButton(),
|
||||||
|
new GridFieldEditButton(),
|
||||||
|
new GridFieldDeleteAction(),
|
||||||
|
new GridFieldToolbarHeader(),
|
||||||
|
new GridFieldOrderableRows('Sort'),
|
||||||
|
new GridState_Component(),
|
||||||
|
new GridFieldDetailForm()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
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")
|
||||||
|
->filter('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(false);
|
||||||
|
$newField->ParentID = $newPage->ID;
|
||||||
|
$newField->ParentClass = $newPage->ClassName;
|
||||||
|
$newField->Version = 0;
|
||||||
|
$newField->write();
|
||||||
|
|
||||||
|
foreach ($field->DisplayRules() as $customRule) {
|
||||||
|
$newRule = $customRule->duplicate(false);
|
||||||
|
$newRule->ParentID = $newField->ID;
|
||||||
|
$newRule->Version = 0;
|
||||||
|
$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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,17 +4,14 @@
|
|||||||
* {@link TreeDropdownField} subclass for handling loading folders through the
|
* {@link TreeDropdownField} subclass for handling loading folders through the
|
||||||
* nested {@link FormField} instances of the {@link FieldEditor}
|
* nested {@link FormField} instances of the {@link FieldEditor}
|
||||||
*
|
*
|
||||||
|
* @deprecated since version 4.0
|
||||||
* @package userforms
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class UserformsTreeDropdownField extends TreeDropdownField {
|
class UserformsTreeDropdownField extends TreeDropdownField {
|
||||||
|
|
||||||
public function Link($action = null) {
|
public function __construct($name, $title = null, $sourceObject = 'Group', $keyField = 'ID', $labelField = 'TreeTitle', $showSearch = true) {
|
||||||
$form = Controller::curr()->EditForm;
|
parent::__construct($name, $title, $sourceObject, $keyField, $labelField, $showSearch);
|
||||||
|
|
||||||
return Controller::join_links(
|
Deprecation::notice('4.0', __CLASS__ . " is deprecated");
|
||||||
$form->FormAction(), 'field/Fields/handleField/' . $this->name,
|
|
||||||
$action .
|
|
||||||
'?SecurityID='. $form->getSecurityToken()->getValue()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
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->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->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);
|
||||||
|
}
|
||||||
|
}
|
@ -16,20 +16,27 @@ class UserDefinedForm extends Page {
|
|||||||
*/
|
*/
|
||||||
private static $required_identifier = null;
|
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
|
* @var string
|
||||||
*/
|
*/
|
||||||
private static $email_template_directory = 'userforms/templates/email/';
|
private static $email_template_directory = 'userforms/templates/email/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should this module automatically upgrade on dev/build?
|
||||||
|
*
|
||||||
|
* @config
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private static $upgrade_on_build = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Built in extensions required by this page
|
||||||
|
* @config
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $extensions = array(
|
||||||
|
'UserFormFieldEditorExtension'
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array Fields on the user defined form page.
|
* @var array Fields on the user defined form page.
|
||||||
@ -60,7 +67,6 @@ class UserDefinedForm extends Page {
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private static $has_many = array(
|
private static $has_many = array(
|
||||||
"Fields" => "EditableFormField",
|
|
||||||
"Submissions" => "SubmittedForm",
|
"Submissions" => "SubmittedForm",
|
||||||
"EmailRecipients" => "UserDefinedForm_EmailRecipient"
|
"EmailRecipients" => "UserDefinedForm_EmailRecipient"
|
||||||
);
|
);
|
||||||
@ -98,14 +104,10 @@ class UserDefinedForm extends Page {
|
|||||||
$this->beforeUpdateCMSFields(function($fields) use ($self) {
|
$this->beforeUpdateCMSFields(function($fields) use ($self) {
|
||||||
|
|
||||||
// define tabs
|
// define tabs
|
||||||
$fields->findOrMakeTab('Root.FormContent', _t('UserDefinedForm.FORM', 'Form'));
|
|
||||||
$fields->findOrMakeTab('Root.FormOptions', _t('UserDefinedForm.CONFIGURATION', 'Configuration'));
|
$fields->findOrMakeTab('Root.FormOptions', _t('UserDefinedForm.CONFIGURATION', 'Configuration'));
|
||||||
$fields->findOrMakeTab('Root.Recipients', _t('UserDefinedForm.RECIPIENTS', 'Recipients'));
|
$fields->findOrMakeTab('Root.Recipients', _t('UserDefinedForm.RECIPIENTS', 'Recipients'));
|
||||||
$fields->findOrMakeTab('Root.Submissions', _t('UserDefinedForm.SUBMISSIONS', 'Submissions'));
|
$fields->findOrMakeTab('Root.Submissions', _t('UserDefinedForm.SUBMISSIONS', 'Submissions'));
|
||||||
|
|
||||||
// field editor
|
|
||||||
$fields->addFieldToTab('Root.FormContent', new FieldEditor('Fields', 'Fields', '', $self ));
|
|
||||||
|
|
||||||
// text to show on complete
|
// text to show on complete
|
||||||
$onCompleteFieldSet = new CompositeField(
|
$onCompleteFieldSet = new CompositeField(
|
||||||
$label = new LabelField('OnCompleteMessageLabel',_t('UserDefinedForm.ONCOMPLETELABEL', 'Show on completion')),
|
$label = new LabelField('OnCompleteMessageLabel',_t('UserDefinedForm.ONCOMPLETELABEL', 'Show on completion')),
|
||||||
@ -134,7 +136,7 @@ class UserDefinedForm extends Page {
|
|||||||
$emailRecipients
|
$emailRecipients
|
||||||
->getConfig()
|
->getConfig()
|
||||||
->getComponentByType('GridFieldDetailForm')
|
->getComponentByType('GridFieldDetailForm')
|
||||||
->setItemRequestClass('UserDefinedForm_EmailRecipient_ItemRequest');
|
->setItemRequestClass('UserFormRecipientItemRequest');
|
||||||
|
|
||||||
$fields->addFieldsToTab('Root.FormOptions', $onCompleteFieldSet);
|
$fields->addFieldsToTab('Root.FormOptions', $onCompleteFieldSet);
|
||||||
$fields->addFieldToTab('Root.Recipients', $emailRecipients);
|
$fields->addFieldToTab('Root.Recipients', $emailRecipients);
|
||||||
@ -209,125 +211,6 @@ SQL;
|
|||||||
|
|
||||||
return $fields;
|
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}
|
* Allow overriding the EmailRecipients on a {@link DataExtension}
|
||||||
@ -350,67 +233,6 @@ SQL;
|
|||||||
return $recipients;
|
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
|
* Custom options for the form. You can extend the built in options by
|
||||||
* using {@link updateFormOptions()}
|
* using {@link updateFormOptions()}
|
||||||
@ -436,36 +258,6 @@ SQL;
|
|||||||
|
|
||||||
return $options;
|
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.
|
* Get the HTML id of the error container displayed above the form.
|
||||||
@ -475,6 +267,22 @@ SQL;
|
|||||||
public function getErrorContainerID() {
|
public function getErrorContainerID() {
|
||||||
return $this->config()->error_container_id;
|
return $this->config()->error_container_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function requireDefaultRecords() {
|
||||||
|
parent::requireDefaultRecords();
|
||||||
|
|
||||||
|
if(!$this->config()->upgrade_on_build) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform migrations
|
||||||
|
Injector::inst()
|
||||||
|
->create('UserFormsUpgradeService')
|
||||||
|
->setQuiet(true)
|
||||||
|
->run();
|
||||||
|
|
||||||
|
DB::alteration_message('Migrated userforms', 'changed');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -552,141 +360,23 @@ class UserDefinedForm_Controller extends Page_Controller {
|
|||||||
* Get the form for the page. Form can be modified by calling {@link updateForm()}
|
* Get the form for the page. Form can be modified by calling {@link updateForm()}
|
||||||
* on a UserDefinedForm extension.
|
* on a UserDefinedForm extension.
|
||||||
*
|
*
|
||||||
* @return Form|false
|
* @return Forms
|
||||||
*/
|
*/
|
||||||
public function Form() {
|
public function Form() {
|
||||||
$fields = $this->getFormFields();
|
$form = UserForm::create($this);
|
||||||
if(!$fields || !$fields->exists()) return false;
|
|
||||||
|
|
||||||
$actions = $this->getFormActions();
|
|
||||||
|
|
||||||
// get the required fields including the validation
|
|
||||||
$required = $this->getRequiredFields();
|
|
||||||
|
|
||||||
// generate the conditional logic
|
|
||||||
$this->generateConditionalJavascript();
|
$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);
|
$this->generateValidationJavascript($form);
|
||||||
|
|
||||||
return $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
|
* 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
|
// set the custom script for this form
|
||||||
Requirements::customScript(
|
Requirements::customScript(
|
||||||
$this
|
$this
|
||||||
@ -711,139 +401,125 @@ class UserDefinedForm_Controller extends Page_Controller {
|
|||||||
if($this->Fields()) {
|
if($this->Fields()) {
|
||||||
foreach($this->Fields() as $field) {
|
foreach($this->Fields() as $field) {
|
||||||
$fieldId = $field->Name;
|
$fieldId = $field->Name;
|
||||||
|
|
||||||
if($field->ClassName == 'EditableFormHeading') {
|
if($field instanceof EditableFormHeading) {
|
||||||
$fieldId = 'Form_Form_'.$field->Name;
|
$fieldId = 'UserForm_Form_' . $field->Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this Field Show by Default
|
// Is this Field Show by Default
|
||||||
if(!$field->getShowOnLoad()) {
|
if(!$field->ShowOnLoad) {
|
||||||
$default .= "$(\"#" . $fieldId . "\").hide();\n";
|
$default .= "$(\"#" . $fieldId . "\").hide();\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for field dependencies / default
|
// Check for field dependencies / default
|
||||||
if($field->Dependencies()) {
|
foreach($field->DisplayRules() as $rule) {
|
||||||
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;
|
|
||||||
|
|
||||||
if(in_array($formFieldWatch->ClassName, array('EditableCheckboxGroupField', 'EditableCheckbox'))) {
|
// Get the field which is effected
|
||||||
$action = "click";
|
$formFieldWatch = EditableFormField::get()->byId($rule->ConditionFieldID);
|
||||||
$checkboxField = true;
|
|
||||||
}
|
|
||||||
else if ($formFieldWatch->ClassName == "EditableRadioField") {
|
|
||||||
$radioField = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Escape the values.
|
if($formFieldWatch->RecordClassName == 'EditableDropdown') {
|
||||||
$dependency['Value'] = str_replace('"', '\"', $dependency['Value']);
|
// watch out for multiselect options - radios and check boxes
|
||||||
|
$fieldToWatch = "$(\"select[name='" . $formFieldWatch->Name . "']\")";
|
||||||
// and what should we evaluate
|
$fieldToWatchOnLoad = $fieldToWatch;
|
||||||
switch($dependency['ConditionOption']) {
|
} else if($formFieldWatch->RecordClassName == 'EditableCheckboxGroupField') {
|
||||||
case 'IsNotBlank':
|
// watch out for checkboxs as the inputs don't have values but are 'checked
|
||||||
$expression = ($checkboxField || $radioField) ? '$(this).prop("checked")' :'$(this).val() != ""';
|
$fieldToWatch = "$(\"input[name='" . $formFieldWatch->Name . "[" . $rule->FieldValue . "]']\")";
|
||||||
|
$fieldToWatchOnLoad = $fieldToWatch;
|
||||||
break;
|
} else if($formFieldWatch->RecordClassName == 'EditableRadioField') {
|
||||||
case 'IsBlank':
|
$fieldToWatch = "$(\"input[name='" . $formFieldWatch->Name . "']\")";
|
||||||
$expression = ($checkboxField || $radioField) ? '!($(this).prop("checked"))' : '$(this).val() == ""';
|
// 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\")";
|
||||||
break;
|
} else {
|
||||||
case 'HasValue':
|
$fieldToWatch = "$(\"input[name='" . $formFieldWatch->Name . "']\")";
|
||||||
if ($checkboxField) {
|
$fieldToWatchOnLoad = $fieldToWatch;
|
||||||
$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;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 +578,7 @@ JS
|
|||||||
, 'UserFormsConditional');
|
, '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
|
* Process the form that is submitted through the site
|
||||||
*
|
*
|
||||||
@ -934,12 +590,12 @@ JS
|
|||||||
public function process($data, $form) {
|
public function process($data, $form) {
|
||||||
Session::set("FormInfo.{$form->FormName()}.data",$data);
|
Session::set("FormInfo.{$form->FormName()}.data",$data);
|
||||||
Session::clear("FormInfo.{$form->FormName()}.errors");
|
Session::clear("FormInfo.{$form->FormName()}.errors");
|
||||||
|
|
||||||
foreach($this->Fields() as $field) {
|
foreach($this->Fields() as $field) {
|
||||||
$messages[$field->Name] = $field->getErrorMessage()->HTML();
|
$messages[$field->Name] = $field->getErrorMessage()->HTML();
|
||||||
$formField = $field->getFormField();
|
$formField = $field->getFormField();
|
||||||
|
|
||||||
if($field->Required && $field->CustomRules()->Count() == 0) {
|
if($field->Required && $field->DisplayRules()->Count() == 0) {
|
||||||
if(isset($data[$field->Name])) {
|
if(isset($data[$field->Name])) {
|
||||||
$formField->setValue($data[$field->Name]);
|
$formField->setValue($data[$field->Name]);
|
||||||
}
|
}
|
||||||
@ -953,13 +609,13 @@ JS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Session::get("FormInfo.{$form->FormName()}.errors")){
|
if(Session::get("FormInfo.{$form->FormName()}.errors")){
|
||||||
Controller::curr()->redirectBack();
|
Controller::curr()->redirectBack();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$submittedForm = Object::create('SubmittedForm');
|
$submittedForm = Object::create('SubmittedForm');
|
||||||
$submittedForm->SubmittedByID = ($id = Member::currentUserID()) ? $id : 0;
|
$submittedForm->SubmittedByID = ($id = Member::currentUserID()) ? $id : 0;
|
||||||
$submittedForm->ParentID = $this->ID;
|
$submittedForm->ParentID = $this->ID;
|
||||||
@ -968,22 +624,22 @@ JS
|
|||||||
if(!$this->DisableSaveSubmissions) {
|
if(!$this->DisableSaveSubmissions) {
|
||||||
$submittedForm->write();
|
$submittedForm->write();
|
||||||
}
|
}
|
||||||
|
|
||||||
$values = array();
|
$values = array();
|
||||||
$attachments = array();
|
$attachments = array();
|
||||||
|
|
||||||
$submittedFields = new ArrayList();
|
$submittedFields = new ArrayList();
|
||||||
|
|
||||||
foreach($this->Fields() as $field) {
|
foreach($this->Fields() as $field) {
|
||||||
if(!$field->showInReports()) {
|
if(!$field->showInReports()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$submittedField = $field->getSubmittedFormField();
|
$submittedField = $field->getSubmittedFormField();
|
||||||
$submittedField->ParentID = $submittedForm->ID;
|
$submittedField->ParentID = $submittedForm->ID;
|
||||||
$submittedField->Name = $field->Name;
|
$submittedField->Name = $field->Name;
|
||||||
$submittedField->Title = $field->getField('Title');
|
$submittedField->Title = $field->getField('Title');
|
||||||
|
|
||||||
// save the value from the data
|
// save the value from the data
|
||||||
if($field->hasMethod('getValueFromData')) {
|
if($field->hasMethod('getValueFromData')) {
|
||||||
$submittedField->Value = $field->getValueFromData($data);
|
$submittedField->Value = $field->getValueFromData($data);
|
||||||
@ -1021,26 +677,26 @@ JS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$submittedField->extend('onPopulationFromField', $field);
|
$submittedField->extend('onPopulationFromField', $field);
|
||||||
|
|
||||||
if(!$this->DisableSaveSubmissions) {
|
if(!$this->DisableSaveSubmissions) {
|
||||||
$submittedField->write();
|
$submittedField->write();
|
||||||
}
|
}
|
||||||
|
|
||||||
$submittedFields->push($submittedField);
|
$submittedFields->push($submittedField);
|
||||||
}
|
}
|
||||||
|
|
||||||
$emailData = array(
|
$emailData = array(
|
||||||
"Sender" => Member::currentUser(),
|
"Sender" => Member::currentUser(),
|
||||||
"Fields" => $submittedFields
|
"Fields" => $submittedFields
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->extend('updateEmailData', $emailData, $attachments);
|
$this->extend('updateEmailData', $emailData, $attachments);
|
||||||
|
|
||||||
// email users on submit.
|
// email users on submit.
|
||||||
if($recipients = $this->FilteredEmailRecipients($data, $form)) {
|
if($recipients = $this->FilteredEmailRecipients($data, $form)) {
|
||||||
$email = new UserDefinedForm_SubmittedFormEmail($submittedFields);
|
$email = new UserFormRecipientEmail($submittedFields);
|
||||||
$mergeFields = $this->getMergeFieldsMap($emailData['Fields']);
|
$mergeFields = $this->getMergeFieldsMap($emailData['Fields']);
|
||||||
|
|
||||||
if($attachments) {
|
if($attachments) {
|
||||||
@ -1117,7 +773,7 @@ JS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$submittedForm->extend('updateAfterProcess');
|
$submittedForm->extend('updateAfterProcess');
|
||||||
|
|
||||||
Session::clear("FormInfo.{$form->FormName()}.errors");
|
Session::clear("FormInfo.{$form->FormName()}.errors");
|
||||||
@ -1125,7 +781,6 @@ JS
|
|||||||
|
|
||||||
$referrer = (isset($data['Referrer'])) ? '?referrer=' . urlencode($data['Referrer']) : "";
|
$referrer = (isset($data['Referrer'])) ? '?referrer=' . urlencode($data['Referrer']) : "";
|
||||||
|
|
||||||
|
|
||||||
// set a session variable from the security ID to stop people accessing
|
// set a session variable from the security ID to stop people accessing
|
||||||
// the finished method directly.
|
// the finished method directly.
|
||||||
if(!$this->DisableAuthenicatedFinishAction) {
|
if(!$this->DisableAuthenicatedFinishAction) {
|
||||||
@ -1142,7 +797,7 @@ JS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$this->DisableSaveSubmissions) {
|
if(!$this->DisableSaveSubmissions) {
|
||||||
Session::set('userformssubmission'. $this->ID, $submittedForm->ID);
|
Session::set('userformssubmission'. $this->ID, $submittedForm->ID);
|
||||||
}
|
}
|
||||||
@ -1210,499 +865,3 @@ JS
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A Form can have multiply members / emails to email the submission
|
|
||||||
* to and custom subjects
|
|
||||||
*
|
|
||||||
* @package userforms
|
|
||||||
*/
|
|
||||||
class UserDefinedForm_EmailRecipient extends DataObject {
|
|
||||||
|
|
||||||
private static $db = array(
|
|
||||||
'EmailAddress' => 'Varchar(200)',
|
|
||||||
'EmailSubject' => 'Varchar(200)',
|
|
||||||
'EmailFrom' => 'Varchar(200)',
|
|
||||||
'EmailReplyTo' => 'Varchar(200)',
|
|
||||||
'EmailBody' => 'Text',
|
|
||||||
'EmailBodyHtml' => 'HTMLText',
|
|
||||||
'EmailTemplate' => 'Varchar',
|
|
||||||
'SendPlain' => 'Boolean',
|
|
||||||
'HideFormData' => 'Boolean',
|
|
||||||
'CustomRulesCondition' => 'Enum("And,Or")'
|
|
||||||
);
|
|
||||||
|
|
||||||
private static $has_one = array(
|
|
||||||
'Form' => 'UserDefinedForm',
|
|
||||||
'SendEmailFromField' => 'EditableFormField',
|
|
||||||
'SendEmailToField' => 'EditableFormField',
|
|
||||||
'SendEmailSubjectField' => 'EditableFormField'
|
|
||||||
);
|
|
||||||
|
|
||||||
private static $has_many = array(
|
|
||||||
'CustomRules' => 'UserDefinedForm_EmailRecipientCondition'
|
|
||||||
);
|
|
||||||
|
|
||||||
private static $summary_fields = array(
|
|
||||||
'EmailAddress',
|
|
||||||
'EmailSubject',
|
|
||||||
'EmailFrom'
|
|
||||||
);
|
|
||||||
|
|
||||||
public function summaryFields() {
|
|
||||||
$fields = parent::summaryFields();
|
|
||||||
if(isset($fields['EmailAddress'])) {
|
|
||||||
$fields['EmailAddress'] = _t('UserDefinedForm.EMAILADDRESS', 'Email');
|
|
||||||
}
|
|
||||||
if(isset($fields['EmailSubject'])) {
|
|
||||||
$fields['EmailSubject'] = _t('UserDefinedForm.EMAILSUBJECT', 'Subject');
|
|
||||||
}
|
|
||||||
if(isset($fields['EmailFrom'])) {
|
|
||||||
$fields['EmailFrom'] = _t('UserDefinedForm.EMAILFROM', 'From');
|
|
||||||
}
|
|
||||||
return $fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get instance of UserDefinedForm when editing in getCMSFields
|
|
||||||
*
|
|
||||||
* @return UserDefinedFrom
|
|
||||||
*/
|
|
||||||
protected function getFormParent() {
|
|
||||||
$formID = $this->FormID
|
|
||||||
? $this->FormID
|
|
||||||
: Session::get('CMSMain.currentPage');
|
|
||||||
return UserDefinedForm::get()->byID($formID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle() {
|
|
||||||
if($this->EmailAddress) {
|
|
||||||
return $this->EmailAddress;
|
|
||||||
}
|
|
||||||
if($this->EmailSubject) {
|
|
||||||
return $this->EmailSubject;
|
|
||||||
}
|
|
||||||
return parent::getTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a gridfield config for editing filter rules
|
|
||||||
*
|
|
||||||
* @return GridFieldConfig
|
|
||||||
*/
|
|
||||||
protected function getRulesConfig() {
|
|
||||||
$formFields = $this->getFormParent()->Fields();
|
|
||||||
|
|
||||||
$config = GridFieldConfig::create()
|
|
||||||
->addComponents(
|
|
||||||
new GridFieldButtonRow('before'),
|
|
||||||
new GridFieldToolbarHeader(),
|
|
||||||
new GridFieldAddNewInlineButton(),
|
|
||||||
new GridState_Component(),
|
|
||||||
new GridFieldDeleteAction(),
|
|
||||||
$columns = new GridFieldEditableColumns()
|
|
||||||
);
|
|
||||||
|
|
||||||
$columns->setDisplayFields(array(
|
|
||||||
'ConditionFieldID' => function($record, $column, $grid) use ($formFields) {
|
|
||||||
return DropdownField::create($column, false, $formFields->map('ID', 'Title'));
|
|
||||||
},
|
|
||||||
'ConditionOption' => function($record, $column, $grid) {
|
|
||||||
$options = UserDefinedForm_EmailRecipientCondition::config()->condition_options;
|
|
||||||
return DropdownField::create($column, false, $options);
|
|
||||||
},
|
|
||||||
'ConditionValue' => function($record, $column, $grid) {
|
|
||||||
return TextField::create($column);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
return $config;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return FieldList
|
|
||||||
*/
|
|
||||||
public function getCMSFields() {
|
|
||||||
// Determine optional field values
|
|
||||||
$form = $this->getFormParent();
|
|
||||||
|
|
||||||
// predefined choices are also candidates
|
|
||||||
$multiOptionFields = EditableMultipleOptionField::get()->filter('ParentID', $form->ID);
|
|
||||||
|
|
||||||
// if they have email fields then we could send from it
|
|
||||||
$validEmailFromFields = EditableEmailField::get()->filter('ParentID', $form->ID);
|
|
||||||
|
|
||||||
// For the subject, only one-line entry boxes make sense
|
|
||||||
$validSubjectFields = EditableTextField::get()
|
|
||||||
->filter('ParentID', $form->ID)
|
|
||||||
->filterByCallback(function($item, $list) {
|
|
||||||
return (int)$item->getSetting('Rows') === 1;
|
|
||||||
});
|
|
||||||
$validSubjectFields->merge($multiOptionFields);
|
|
||||||
|
|
||||||
// To address can only be email fields or multi option fields
|
|
||||||
$validEmailToFields = new ArrayList($validEmailFromFields->toArray());
|
|
||||||
$validEmailToFields->merge($multiOptionFields);
|
|
||||||
|
|
||||||
// Build fieldlist
|
|
||||||
$fields = FieldList::create(Tabset::create('Root')->addExtraClass('EmailRecipientForm'));
|
|
||||||
|
|
||||||
// Configuration fields
|
|
||||||
$fields->addFieldsToTab('Root.EmailDetails', array(
|
|
||||||
// Subject
|
|
||||||
FieldGroup::create(
|
|
||||||
TextField::create('EmailSubject', _t('UserDefinedForm.TYPESUBJECT', 'Type subject'))
|
|
||||||
->setAttribute('style', 'min-width: 400px;'),
|
|
||||||
DropdownField::create(
|
|
||||||
'SendEmailSubjectFieldID',
|
|
||||||
_t('UserDefinedForm.SELECTAFIELDTOSETSUBJECT', '.. or select a field to use as the subject'),
|
|
||||||
$validSubjectFields->map('ID', 'Title')
|
|
||||||
)->setEmptyString('')
|
|
||||||
)
|
|
||||||
->setTitle(_t('UserDefinedForm.EMAILSUBJECT', 'Email subject')),
|
|
||||||
|
|
||||||
// To
|
|
||||||
FieldGroup::create(
|
|
||||||
TextField::create('EmailAddress', _t('UserDefinedForm.TYPETO', 'Type to address'))
|
|
||||||
->setAttribute('style', 'min-width: 400px;'),
|
|
||||||
DropdownField::create(
|
|
||||||
'SendEmailToFieldID',
|
|
||||||
_t('UserDefinedForm.ORSELECTAFIELDTOUSEASTO', '.. or select a field to use as the to address'),
|
|
||||||
$validEmailToFields->map('ID', 'Title')
|
|
||||||
)->setEmptyString(' ')
|
|
||||||
)
|
|
||||||
->setTitle(_t('UserDefinedForm.SENDEMAILTO','Send email to'))
|
|
||||||
->setDescription(_t(
|
|
||||||
'UserDefinedForm.SENDEMAILTO_DESCRIPTION',
|
|
||||||
'You may enter multiple email addresses as a comma separated list.'
|
|
||||||
)),
|
|
||||||
|
|
||||||
|
|
||||||
// From
|
|
||||||
TextField::create('EmailFrom', _t('UserDefinedForm.FROMADDRESS','Send email from'))
|
|
||||||
->setDescription(_t(
|
|
||||||
'UserDefinedForm.EmailFromContent',
|
|
||||||
"The from address allows you to set who the email comes from. On most servers this ".
|
|
||||||
"will need to be set to an email address on the same domain name as your site. ".
|
|
||||||
"For example on yoursite.com the from address may need to be something@yoursite.com. ".
|
|
||||||
"You can however, set any email address you wish as the reply to address."
|
|
||||||
)),
|
|
||||||
|
|
||||||
|
|
||||||
// Reply-To
|
|
||||||
FieldGroup::create(
|
|
||||||
TextField::create('EmailReplyTo', _t('UserDefinedForm.TYPEREPLY', 'Type reply address'))
|
|
||||||
->setAttribute('style', 'min-width: 400px;'),
|
|
||||||
DropdownField::create(
|
|
||||||
'SendEmailFromFieldID',
|
|
||||||
_t('UserDefinedForm.ORSELECTAFIELDTOUSEASFROM', '.. or select a field to use as reply to address'),
|
|
||||||
$validEmailFromFields->map('ID', 'Title')
|
|
||||||
)->setEmptyString(' ')
|
|
||||||
)
|
|
||||||
->setTitle(_t('UserDefinedForm.REPLYADDRESS', 'Email for reply to'))
|
|
||||||
->setDescription(_t(
|
|
||||||
'UserDefinedForm.REPLYADDRESS_DESCRIPTION',
|
|
||||||
'The email address which the recipient is able to \'reply\' to.'
|
|
||||||
))
|
|
||||||
));
|
|
||||||
|
|
||||||
// Only show the preview link if the recipient has been saved.
|
|
||||||
if (!empty($this->EmailTemplate)) {
|
|
||||||
$preview = sprintf(
|
|
||||||
'<p><a href="%s" target="_blank" class="ss-ui-button">%s</a></p><em>%s</em>',
|
|
||||||
"admin/pages/edit/EditForm/field/EmailRecipients/item/{$this->ID}/preview",
|
|
||||||
_t('UserDefinedForm.PREVIEW_EMAIL', 'Preview email'),
|
|
||||||
_t('UserDefinedForm.PREVIEW_EMAIL_DESCRIPTION', 'Note: Unsaved changes will not appear in the preview.')
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$preview = sprintf(
|
|
||||||
'<em>%s</em>',
|
|
||||||
_t(
|
|
||||||
'UserDefinedForm.PREVIEW_EMAIL_UNAVAILABLE',
|
|
||||||
'You can preview this email once you have saved the Recipient.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Email templates
|
|
||||||
$fields->addFieldsToTab('Root.EmailContent', array(
|
|
||||||
new CheckboxField('HideFormData', _t('UserDefinedForm.HIDEFORMDATA', 'Hide form data from email?')),
|
|
||||||
new CheckboxField('SendPlain', _t('UserDefinedForm.SENDPLAIN', 'Send email as plain text? (HTML will be stripped)')),
|
|
||||||
new DropdownField('EmailTemplate', _t('UserDefinedForm.EMAILTEMPLATE', 'Email template'), $this->getEmailTemplateDropdownValues()),
|
|
||||||
new HTMLEditorField('EmailBodyHtml', _t('UserDefinedForm.EMAILBODYHTML','Body')),
|
|
||||||
new TextareaField('EmailBody', _t('UserDefinedForm.EMAILBODY','Body')),
|
|
||||||
new LiteralField('EmailPreview', '<div id="EmailPreview">' . $preview . '</div>')
|
|
||||||
));
|
|
||||||
|
|
||||||
// Custom rules for sending this field
|
|
||||||
$grid = new GridField(
|
|
||||||
"CustomRules",
|
|
||||||
_t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
|
|
||||||
$this->CustomRules(),
|
|
||||||
$this->getRulesConfig()
|
|
||||||
);
|
|
||||||
$grid->setDescription(_t(
|
|
||||||
'UserDefinedForm.RulesDescription',
|
|
||||||
'Emails will only be sent to the recipient if the custom rules are met. If no rules are defined, this receipient will receive notifications for every submission.'
|
|
||||||
));
|
|
||||||
$fields->addFieldsToTab('Root.CustomRules', array(
|
|
||||||
new DropdownField(
|
|
||||||
'CustomRulesCondition',
|
|
||||||
_t('UserDefinedForm.SENDIF', 'Send condition'),
|
|
||||||
array(
|
|
||||||
'Or' => 'Any conditions are true',
|
|
||||||
'And' => 'All conditions are true'
|
|
||||||
)
|
|
||||||
),
|
|
||||||
$grid
|
|
||||||
));
|
|
||||||
|
|
||||||
$this->extend('updateCMSFields', $fields);
|
|
||||||
return $fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Member
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function canCreate($member = null) {
|
|
||||||
return $this->Form()->canCreate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Member
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function canView($member = null) {
|
|
||||||
return $this->Form()->canView();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Member
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function canEdit($member = null) {
|
|
||||||
return $this->Form()->canEdit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Member
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function canDelete($member = null) {
|
|
||||||
return $this->Form()->canDelete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine if this recipient may receive notifications for this submission
|
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @param Form $form
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function canSend($data, $form) {
|
|
||||||
// Skip if no rules configured
|
|
||||||
$customRules = $this->CustomRules();
|
|
||||||
if(!$customRules->count()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check all rules
|
|
||||||
$isAnd = $this->CustomRulesCondition === 'And';
|
|
||||||
foreach($customRules as $customRule) {
|
|
||||||
$matches = $customRule->matches($data, $form);
|
|
||||||
if($isAnd && !$matches) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(!$isAnd && $matches) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Once all rules are checked
|
|
||||||
return $isAnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure the email template saved against the recipient exists on the file system.
|
|
||||||
*
|
|
||||||
* @param string
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function emailTemplateExists($template = '') {
|
|
||||||
$t = ($template ? $template : $this->EmailTemplate);
|
|
||||||
|
|
||||||
return in_array($t, $this->getEmailTemplateDropdownValues());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the email body for the current email format
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getEmailBodyContent() {
|
|
||||||
return $this->SendPlain ? $this->EmailBody : $this->EmailBodyHtml;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a list of email templates suitable for populating the email template dropdown.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getEmailTemplateDropdownValues() {
|
|
||||||
$templates = array();
|
|
||||||
|
|
||||||
$finder = new SS_FileFinder();
|
|
||||||
$finder->setOption('name_regex', '/^.*\.ss$/');
|
|
||||||
|
|
||||||
$found = $finder->find(BASE_PATH . '/' . UserDefinedForm::config()->email_template_directory);
|
|
||||||
|
|
||||||
foreach ($found as $key => $value) {
|
|
||||||
$template = pathinfo($value);
|
|
||||||
|
|
||||||
$templates[$template['filename']] = $template['filename'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $templates;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller that handles requests to EmailRecipient's
|
|
||||||
*
|
|
||||||
* @package userforms
|
|
||||||
*/
|
|
||||||
class UserDefinedForm_EmailRecipient_ItemRequest extends GridFieldDetailForm_ItemRequest {
|
|
||||||
|
|
||||||
private static $allowed_actions = array(
|
|
||||||
'edit',
|
|
||||||
'view',
|
|
||||||
'ItemEditForm',
|
|
||||||
'preview'
|
|
||||||
);
|
|
||||||
|
|
||||||
public function edit($request) {
|
|
||||||
Requirements::javascript(USERFORMS_DIR . '/javascript/Recipient.js');
|
|
||||||
return parent::edit($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders a preview of the recipient email.
|
|
||||||
*/
|
|
||||||
public function preview() {
|
|
||||||
return $this->customise(new ArrayData(array(
|
|
||||||
'Body' => $this->record->getEmailBodyContent(),
|
|
||||||
'HideFormData' => $this->record->HideFormData,
|
|
||||||
'Fields' => $this->getPreviewFieldData()
|
|
||||||
)))->renderWith($this->record->EmailTemplate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get some placeholder field values to display in the preview
|
|
||||||
* @return ArrayList
|
|
||||||
*/
|
|
||||||
private function getPreviewFieldData() {
|
|
||||||
$data = new ArrayList();
|
|
||||||
|
|
||||||
$fields = $this->record->Form()->Fields()->filter(array(
|
|
||||||
'ClassName:not' => 'EditableLiteralField',
|
|
||||||
'ClassName:not' => 'EditableFormHeading'
|
|
||||||
));
|
|
||||||
|
|
||||||
foreach ($fields as $field) {
|
|
||||||
$data->push(new ArrayData(array(
|
|
||||||
'Name' => $field->Name,
|
|
||||||
'Title' => $field->Title,
|
|
||||||
'Value' => '$' . $field->Name,
|
|
||||||
'FormattedValue' => '$' . $field->Name
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Declares a condition that determines whether an email can be sent to a given recipient
|
|
||||||
*/
|
|
||||||
class UserDefinedForm_EmailRecipientCondition extends DataObject {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of options
|
|
||||||
*
|
|
||||||
* @config
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private static $condition_options = array(
|
|
||||||
"IsBlank" => "Is blank",
|
|
||||||
"IsNotBlank" => "Is not blank",
|
|
||||||
"Equals" => "Equals",
|
|
||||||
"NotEquals" => "Doesn't equal"
|
|
||||||
);
|
|
||||||
|
|
||||||
private static $db = array(
|
|
||||||
'ConditionOption' => 'Enum("IsBlank,IsNotBlank,Equals,NotEquals")',
|
|
||||||
'ConditionValue' => 'Varchar'
|
|
||||||
);
|
|
||||||
|
|
||||||
private static $has_one = array(
|
|
||||||
'Parent' => 'UserDefinedForm_EmailRecipient',
|
|
||||||
'ConditionField' => 'EditableFormField'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if this rule matches the given condition
|
|
||||||
*
|
|
||||||
* @param array $data
|
|
||||||
* @param Form $form
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function matches($data, $form) {
|
|
||||||
$fieldName = $this->ConditionField()->Name;
|
|
||||||
$fieldValue = isset($data[$fieldName]) ? $data[$fieldName] : null;
|
|
||||||
switch($this->ConditionOption) {
|
|
||||||
case 'IsBlank':
|
|
||||||
return empty($fieldValue);
|
|
||||||
case 'IsNotBlank':
|
|
||||||
return !empty($fieldValue);
|
|
||||||
default:
|
|
||||||
$matches = is_array($fieldValue)
|
|
||||||
? in_array($this->ConditionValue, $fieldValue)
|
|
||||||
: $this->ConditionValue === (string)$fieldValue;
|
|
||||||
return ($this->ConditionOption === 'Equals') === (bool)$matches;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Email that gets sent to the people listed in the Email Recipients when a
|
|
||||||
* submission is made.
|
|
||||||
*
|
|
||||||
* @package userforms
|
|
||||||
*/
|
|
||||||
|
|
||||||
class UserDefinedForm_SubmittedFormEmail extends Email {
|
|
||||||
|
|
||||||
protected $ss_template = "SubmittedFormEmail";
|
|
||||||
|
|
||||||
protected $data;
|
|
||||||
|
|
||||||
public function __construct($submittedFields = null) {
|
|
||||||
parent::__construct($submittedFields = null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the "Reply-To" header with an email address rather than append as
|
|
||||||
* {@link Email::replyTo} does.
|
|
||||||
*
|
|
||||||
* @param string $email The email address to set the "Reply-To" header to
|
|
||||||
*/
|
|
||||||
public function setReplyTo($email) {
|
|
||||||
$this->customHeaders['Reply-To'] = $email;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -12,17 +12,27 @@ class EditableCheckbox extends EditableFormField {
|
|||||||
private static $singular_name = 'Checkbox Field';
|
private static $singular_name = 'Checkbox Field';
|
||||||
|
|
||||||
private static $plural_name = 'Checkboxes';
|
private static $plural_name = 'Checkboxes';
|
||||||
|
|
||||||
public function getFieldConfiguration() {
|
private static $db = array(
|
||||||
$options = parent::getFieldConfiguration();
|
'CheckedDefault' => 'Boolean' // from CustomSettings
|
||||||
$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->replaceField('Default', CheckboxField::create(
|
||||||
|
"CheckedDefault",
|
||||||
|
_t('EditableFormField.CHECKEDBYDEFAULT', 'Checked by Default?')
|
||||||
|
));
|
||||||
|
|
||||||
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
|
$field = CheckboxField::create($this->Name, $this->Title, $this->CheckedDefault);
|
||||||
$field = CheckboxField::create( $this->Name, $this->Title, $this->getSetting('Default'));
|
|
||||||
|
|
||||||
if ($this->Required) {
|
if ($this->Required) {
|
||||||
// Required validation can conflict so add the Required validation messages
|
// Required validation can conflict so add the Required validation messages
|
||||||
@ -40,4 +50,14 @@ class EditableCheckbox extends EditableFormField {
|
|||||||
|
|
||||||
return ($value) ? _t('EditableFormField.YES', 'Yes') : _t('EditableFormField.NO', 'No');
|
return ($value) ? _t('EditableFormField.YES', 'Yes') : _t('EditableFormField.NO', 'No');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function migrateSettings($data) {
|
||||||
|
// Migrate 'Default' setting to 'CheckedDefault'
|
||||||
|
if(isset($data['Default'])) {
|
||||||
|
$this->CheckedDefault = (bool)$data['Default'];
|
||||||
|
unset($data['Default']);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::migrateSettings($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,11 +15,17 @@ class EditableCheckboxGroupField extends EditableMultipleOptionField {
|
|||||||
|
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
$optionSet = $this->Options();
|
$optionSet = $this->Options();
|
||||||
$options = array();
|
$optionMap = $optionSet->map('EscapedTitle', 'Title');
|
||||||
|
|
||||||
$optionMap = ($optionSet) ? $optionSet->map('EscapedTitle', 'Title') : array();
|
$field = new UserFormsCheckboxSetField($this->Name, $this->Title, $optionMap);
|
||||||
|
|
||||||
return new UserFormsCheckboxSetField($this->Name, $this->Title, $optionMap);
|
// Set the default checked items
|
||||||
|
$defaultCheckedItems = $optionSet->filter('Default', 1);
|
||||||
|
if ($defaultCheckedItems->count()) {
|
||||||
|
$field->setDefaultItems($defaultCheckedItems->map('EscapedTitle')->keys());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $field;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValueFromData($data) {
|
public function getValueFromData($data) {
|
||||||
|
@ -10,9 +10,20 @@ class EditableCountryDropdownField extends EditableFormField {
|
|||||||
private static $singular_name = 'Country Dropdown';
|
private static $singular_name = 'Country Dropdown';
|
||||||
|
|
||||||
private static $plural_name = 'Country Dropdowns';
|
private static $plural_name = 'Country Dropdowns';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
public function getCMSFields() {
|
||||||
|
$fields = parent::getCMSFields();
|
||||||
|
|
||||||
|
$fields->removeByName('Default');
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
return new CountryDropdownField($this->Name, $this->Title);
|
return CountryDropdownField::create($this->Name, $this->Title);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValueFromData($data) {
|
public function getValueFromData($data) {
|
||||||
|
@ -12,24 +12,27 @@ class EditableDateField extends EditableFormField {
|
|||||||
private static $singular_name = 'Date Field';
|
private static $singular_name = 'Date Field';
|
||||||
|
|
||||||
private static $plural_name = 'Date Fields';
|
private static $plural_name = 'Date Fields';
|
||||||
|
|
||||||
public function getFieldConfiguration() {
|
private static $db = array(
|
||||||
$default = ($this->getSetting('DefaultToToday')) ? $this->getSetting('DefaultToToday') : false;
|
'DefaultToToday' => 'Boolean' // From customsettings
|
||||||
$label = _t('EditableFormField.DEFAULTTOTODAY', 'Default to Today?');
|
);
|
||||||
|
|
||||||
return new FieldList(
|
/**
|
||||||
new CheckboxField($this->getSettingName("DefaultToToday"), $label, $default)
|
* @return FieldList
|
||||||
);
|
*/
|
||||||
}
|
public function getCMSFields() {
|
||||||
|
$this->beforeUpdateCMSFields(function(FieldList $fields) {
|
||||||
public function populateFromPostData($data) {
|
$fields->addFieldToTab(
|
||||||
$fieldPrefix = 'Default-';
|
'Root.Main',
|
||||||
|
CheckboxField::create(
|
||||||
if(empty($data['Default']) && !empty($data[$fieldPrefix.'Year']) && !empty($data[$fieldPrefix.'Month']) && !empty($data[$fieldPrefix.'Day'])) {
|
'DefaultToToday',
|
||||||
$data['Default'] = $data['Year'] . '-' . $data['Month'] . '-' . $data['Day'];
|
_t('EditableFormField.DEFAULTTOTODAY', 'Default to Today?')
|
||||||
}
|
),
|
||||||
|
'RightTitle'
|
||||||
parent::populateFromPostData($data);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return parent::getCMSFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,7 +40,9 @@ class EditableDateField extends EditableFormField {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
$defaultValue = ($this->getSetting('DefaultToToday')) ? date('Y-m-d') : $this->Default;
|
$defaultValue = $this->DefaultToToday
|
||||||
|
? SS_Datetime::now()->Format('Y-m-d')
|
||||||
|
: $this->Default;
|
||||||
$field = EditableDateField_FormField::create( $this->Name, $this->Title, $defaultValue);
|
$field = EditableDateField_FormField::create( $this->Name, $this->Title, $defaultValue);
|
||||||
$field->setConfig('showcalendar', true);
|
$field->setConfig('showcalendar', true);
|
||||||
|
|
||||||
|
@ -12,12 +12,24 @@ class EditableDropdown extends EditableMultipleOptionField {
|
|||||||
private static $singular_name = 'Dropdown Field';
|
private static $singular_name = 'Dropdown Field';
|
||||||
|
|
||||||
private static $plural_name = 'Dropdowns';
|
private static $plural_name = 'Dropdowns';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
public function getCMSFields() {
|
||||||
|
$fields = parent::getCMSFields();
|
||||||
|
|
||||||
|
$fields->removeByName('Default');
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return DropdownField
|
* @return DropdownField
|
||||||
*/
|
*/
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
$optionSet = $this->Options();
|
$optionSet = $this->Options();
|
||||||
|
$defaultOptions = $optionSet->filter('Default', 1);
|
||||||
$options = array();
|
$options = array();
|
||||||
|
|
||||||
if($optionSet) {
|
if($optionSet) {
|
||||||
@ -35,6 +47,10 @@ class EditableDropdown extends EditableMultipleOptionField {
|
|||||||
$field->setAttribute('data-rule-required', 'true');
|
$field->setAttribute('data-rule-required', 'true');
|
||||||
$field->setAttribute('data-msg-required', $errorMessage);
|
$field->setAttribute('data-msg-required', $errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($defaultOptions->count()) {
|
||||||
|
$field->setValue($defaultOptions->First()->EscapedTitle);
|
||||||
|
}
|
||||||
|
|
||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ class EditableEmailField extends EditableFormField {
|
|||||||
$field->setAttribute('data-rule-required', 'true');
|
$field->setAttribute('data-rule-required', 'true');
|
||||||
$field->setAttribute('data-msg-required', $errorMessage);
|
$field->setAttribute('data-msg-required', $errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$field->setValue($this->Default);
|
||||||
|
|
||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
|
@ -12,21 +12,26 @@ class EditableFileField extends EditableFormField {
|
|||||||
|
|
||||||
private static $plural_names = 'File Fields';
|
private static $plural_names = 'File Fields';
|
||||||
|
|
||||||
public function getFieldConfiguration() {
|
private static $has_one = array(
|
||||||
$field = parent::getFieldConfiguration();
|
'Folder' => 'Folder' // From CustomFields
|
||||||
$folder = ($this->getSetting('Folder')) ? $this->getSetting('Folder') : null;
|
);
|
||||||
|
|
||||||
$tree = UserformsTreeDropdownField::create(
|
/**
|
||||||
$this->getSettingName("Folder"),
|
* @return FieldList
|
||||||
_t('EditableUploadField.SELECTUPLOADFOLDER', 'Select upload folder'),
|
*/
|
||||||
"Folder"
|
public function getCMSFields() {
|
||||||
|
$fields = parent::getCMSFields();
|
||||||
|
|
||||||
|
$fields->addFieldToTab(
|
||||||
|
'Root.Main',
|
||||||
|
TreeDropdownField::create(
|
||||||
|
'FolderID',
|
||||||
|
_t('EditableUploadField.SELECTUPLOADFOLDER', 'Select upload folder'),
|
||||||
|
'Folder'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
$tree->setValue($folder);
|
return $fields;
|
||||||
|
|
||||||
$field->push($tree);
|
|
||||||
|
|
||||||
return $field;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
@ -37,14 +42,11 @@ class EditableFileField extends EditableFormField {
|
|||||||
array_filter(Config::inst()->get('File', 'allowed_extensions'))
|
array_filter(Config::inst()->get('File', 'allowed_extensions'))
|
||||||
);
|
);
|
||||||
|
|
||||||
if($this->getSetting('Folder')) {
|
$folder = $this->Folder();
|
||||||
$folder = Folder::get()->byId($this->getSetting('Folder'));
|
if($folder && $folder->exists()) {
|
||||||
|
$field->setFolderName(
|
||||||
if($folder) {
|
preg_replace("/^assets\//","", $folder->Filename)
|
||||||
$field->setFolderName(
|
);
|
||||||
preg_replace("/^assets\//","", $folder->Filename)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->Required) {
|
if ($this->Required) {
|
||||||
@ -72,4 +74,15 @@ class EditableFileField extends EditableFormField {
|
|||||||
public function getSubmittedFormField() {
|
public function getSubmittedFormField() {
|
||||||
return new SubmittedFileField();
|
return new SubmittedFileField();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function migrateSettings($data) {
|
||||||
|
// Migrate 'Folder' setting to 'FolderID'
|
||||||
|
if(isset($data['Folder'])) {
|
||||||
|
$this->FolderID = $data['Folder'];
|
||||||
|
unset($data['Folder']);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::migrateSettings($data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,17 @@
|
|||||||
* object like {@link EditableTextField}.
|
* object like {@link EditableTextField}.
|
||||||
*
|
*
|
||||||
* @package userforms
|
* @package userforms
|
||||||
|
* @method DataList DisplayRules() List of EditableCustomRule objects
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class EditableFormField extends DataObject {
|
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
|
* A list of CSS classes that can be added
|
||||||
@ -16,32 +22,67 @@ class EditableFormField extends DataObject {
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $allowed_css = array();
|
public static $allowed_css = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @config
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $summary_fields = array(
|
||||||
|
'Title'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @config
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
private static $db = array(
|
private static $db = array(
|
||||||
"Name" => "Varchar",
|
"Name" => "Varchar",
|
||||||
"Title" => "Varchar(255)",
|
"Title" => "Varchar(255)",
|
||||||
"Default" => "Varchar",
|
"Default" => "Varchar(255)",
|
||||||
"Sort" => "Int",
|
"Sort" => "Int",
|
||||||
"Required" => "Boolean",
|
"Required" => "Boolean",
|
||||||
"CustomErrorMessage" => "Varchar(255)",
|
"CustomErrorMessage" => "Varchar(255)",
|
||||||
"CustomRules" => "Text",
|
|
||||||
"CustomSettings" => "Text",
|
"CustomRules" => "Text", // @deprecated from 2.0
|
||||||
"CustomParameter" => "Varchar(200)"
|
"CustomSettings" => "Text", // @deprecated from 2.0
|
||||||
|
"Migrated" => "Boolean", // set to true when migrated
|
||||||
|
|
||||||
|
"ExtraClass" => "Text", // from CustomSettings
|
||||||
|
"RightTitle" => "Varchar(255)", // from CustomSettings
|
||||||
|
"ShowOnLoad" => "Boolean(1)", // from CustomSettings
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @config
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
private static $has_one = array(
|
private static $has_one = array(
|
||||||
"Parent" => "UserDefinedForm",
|
"Parent" => "UserDefinedForm",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Built in extensions required
|
||||||
|
*
|
||||||
|
* @config
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
private static $extensions = array(
|
private static $extensions = array(
|
||||||
"Versioned('Stage', 'Live')"
|
"Versioned('Stage', 'Live')"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @config
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $has_many = array(
|
||||||
|
"DisplayRules" => "EditableCustomRule.Parent" // from CustomRules
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
protected $readonly;
|
protected $readonly;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the visibility of an individual form field
|
* Set the visibility of an individual form field
|
||||||
*
|
*
|
||||||
@ -59,14 +100,163 @@ class EditableFormField extends DataObject {
|
|||||||
private function isReadonly() {
|
private function isReadonly() {
|
||||||
return $this->readonly;
|
return $this->readonly;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Template to render the form field into
|
* @return FieldList
|
||||||
*
|
|
||||||
* @return String
|
|
||||||
*/
|
*/
|
||||||
public function EditSegment() {
|
public function getCMSFields() {
|
||||||
return $this->renderWith('EditableFormField');
|
$fields = new FieldList(new TabSet('Root'));
|
||||||
|
|
||||||
|
// Main tab
|
||||||
|
$fields->addFieldsToTab(
|
||||||
|
'Root.Main',
|
||||||
|
array(
|
||||||
|
ReadonlyField::create(
|
||||||
|
'Type',
|
||||||
|
_t('EditableFormField.TYPE', 'Type'),
|
||||||
|
$this->i18n_singular_name()
|
||||||
|
),
|
||||||
|
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>'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
TextField::create('Title'),
|
||||||
|
TextField::create('Default', _t('EditableFormField.DEFAULT', 'Default value')),
|
||||||
|
TextField::create('RightTitle', _t('EditableFormField.RIGHTTITLE', 'Right title'))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Custom settings
|
||||||
|
if (!empty(self::$allowed_css)) {
|
||||||
|
$cssList = array();
|
||||||
|
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',
|
||||||
|
DropdownField::create(
|
||||||
|
'ExtraClass',
|
||||||
|
_t('EditableFormField.EXTRACLASS_TITLE', 'Extra Styling/Layout'),
|
||||||
|
$cssList
|
||||||
|
)->setDescription(_t(
|
||||||
|
'EditableFormField.EXTRACLASS_SELECT',
|
||||||
|
'Select from the list of allowed styles'
|
||||||
|
))
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$fields->addFieldToTab('Root.Main',
|
||||||
|
TextField::create(
|
||||||
|
'ExtraClass',
|
||||||
|
_t('EditableFormField.EXTRACLASS_Title', 'Extra CSS Classes')
|
||||||
|
)->setDescription(_t(
|
||||||
|
'EditableFormField.EXTRACLASS_MULTIPLE',
|
||||||
|
'Separate each CSS class with a single space'
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation
|
||||||
|
$fields->addFieldsToTab(
|
||||||
|
'Root.Validation',
|
||||||
|
$this->getFieldValidationOptions()
|
||||||
|
);
|
||||||
|
|
||||||
|
$editableColumns = new GridFieldEditableColumns();
|
||||||
|
$editableColumns->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);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
// Custom rules
|
||||||
|
$customRulesConfig = GridFieldConfig::create()
|
||||||
|
->addComponents(
|
||||||
|
$editableColumns,
|
||||||
|
new GridFieldButtonRow(),
|
||||||
|
new GridFieldToolbarHeader(),
|
||||||
|
new GridFieldAddNewInlineButton(),
|
||||||
|
new GridFieldDeleteAction(),
|
||||||
|
new GridState_Component()
|
||||||
|
);
|
||||||
|
|
||||||
|
$fields->addFieldsToTab('Root.DisplayRules', array(
|
||||||
|
CheckboxField::create('ShowOnLoad')
|
||||||
|
->setDescription(_t(
|
||||||
|
'EditableFormField.SHOWONLOAD',
|
||||||
|
'Initial visibility before processing these rules'
|
||||||
|
)),
|
||||||
|
GridField::create(
|
||||||
|
'DisplayRules',
|
||||||
|
_t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
|
||||||
|
$this->DisplayRules(),
|
||||||
|
$customRulesConfig
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->extend('updateCMSFields', $fields);
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function onBeforeWrite() {
|
||||||
|
parent::onBeforeWrite();
|
||||||
|
|
||||||
|
if(!$this->Sort && $this->ParentID) {
|
||||||
|
$parentID = $this->ParentID;
|
||||||
|
$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 +275,11 @@ class EditableFormField extends DataObject {
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function canDelete($member = null) {
|
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 +289,11 @@ class EditableFormField extends DataObject {
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function canEdit($member = null) {
|
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 +303,11 @@ class EditableFormField extends DataObject {
|
|||||||
*/
|
*/
|
||||||
public function doPublish($fromStage, $toStage, $createNewVersion = false) {
|
public function doPublish($fromStage, $toStage, $createNewVersion = false) {
|
||||||
$this->publish($fromStage, $toStage, $createNewVersion);
|
$this->publish($fromStage, $toStage, $createNewVersion);
|
||||||
|
|
||||||
|
// Don't forget to publish the related custom rules...
|
||||||
|
foreach ($this->DisplayRules() as $rule) {
|
||||||
|
$rule->doPublish($fromStage, $toStage, $createNewVersion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,6 +317,11 @@ class EditableFormField extends DataObject {
|
|||||||
*/
|
*/
|
||||||
public function doDeleteFromStage($stage) {
|
public function doDeleteFromStage($stage) {
|
||||||
$this->deleteFromStage($stage);
|
$this->deleteFromStage($stage);
|
||||||
|
|
||||||
|
// Don't forget to delete the related custom rules...
|
||||||
|
foreach ($this->DisplayRules() as $rule) {
|
||||||
|
$rule->deleteFromStage($stage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,49 +344,32 @@ class EditableFormField extends DataObject {
|
|||||||
if($this->isNew()) return false;
|
if($this->isNew()) return false;
|
||||||
|
|
||||||
$stageVersion = Versioned::get_versionnumber_by_stage('EditableFormField', 'Stage', $this->ID);
|
$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);
|
return ($stageVersion && $stageVersion != $liveVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show this form on load or not
|
* @deprecated since version 4.0
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function getShowOnLoad() {
|
|
||||||
return ($this->getSetting('ShowOnLoad') == "Show" || $this->getSetting('ShowOnLoad') == '') ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To prevent having tables for each fields minor settings we store it as
|
|
||||||
* a serialized array in the database.
|
|
||||||
*
|
|
||||||
* @return Array Return all the Settings
|
|
||||||
*/
|
*/
|
||||||
public function getSettings() {
|
public function getSettings() {
|
||||||
|
Deprecation::notice('4.0', 'getSettings is deprecated');
|
||||||
return (!empty($this->CustomSettings)) ? unserialize($this->CustomSettings) : array();
|
return (!empty($this->CustomSettings)) ? unserialize($this->CustomSettings) : array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the custom settings for this field as we store the minor details in
|
* @deprecated since version 4.0
|
||||||
* a serialized array in the database
|
|
||||||
*
|
|
||||||
* @param Array the custom settings
|
|
||||||
*/
|
*/
|
||||||
public function setSettings($settings = array()) {
|
public function setSettings($settings = array()) {
|
||||||
|
Deprecation::notice('4.0', 'setSettings is deprecated');
|
||||||
$this->CustomSettings = serialize($settings);
|
$this->CustomSettings = serialize($settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a given field setting. Appends the option to the settings or overrides
|
* @deprecated since version 4.0
|
||||||
* the existing value
|
|
||||||
*
|
|
||||||
* @param String key
|
|
||||||
* @param String value
|
|
||||||
*/
|
*/
|
||||||
public function setSetting($key, $value) {
|
public function setSetting($key, $value) {
|
||||||
|
Deprecation::notice('4.0', "setSetting({$key}) is deprecated");
|
||||||
$settings = $this->getSettings();
|
$settings = $this->getSettings();
|
||||||
$settings[$key] = $value;
|
$settings[$key] = $value;
|
||||||
|
|
||||||
@ -199,13 +390,11 @@ class EditableFormField extends DataObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return just one custom setting or empty string if it does
|
* @deprecated since version 4.0
|
||||||
* not exist
|
|
||||||
*
|
|
||||||
* @param String Value to use as key
|
|
||||||
* @return String
|
|
||||||
*/
|
*/
|
||||||
public function getSetting($setting) {
|
public function getSetting($setting) {
|
||||||
|
Deprecation::notice("4.0", "getSetting({$setting}) is deprecated");
|
||||||
|
|
||||||
$settings = $this->getSettings();
|
$settings = $this->getSettings();
|
||||||
if(isset($settings) && count($settings) > 0) {
|
if(isset($settings) && count($settings) > 0) {
|
||||||
if(isset($settings[$setting])) {
|
if(isset($settings[$setting])) {
|
||||||
@ -243,51 +432,6 @@ class EditableFormField extends DataObject {
|
|||||||
public function showExtraOptions() {
|
public function showExtraOptions() {
|
||||||
return true;
|
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
|
* Title field of the field in the backend of the page
|
||||||
@ -307,164 +451,44 @@ class EditableFormField extends DataObject {
|
|||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the Title for rendering in the front-end (with XML values escaped) */
|
/**
|
||||||
|
* Returns the Title for rendering in the front-end (with XML values escaped)
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
return Convert::raw2att($this->getField('Title'));
|
return Convert::raw2att($this->getField('Title'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the base name for this form field in the
|
* @deprecated since version 4.0
|
||||||
* form builder. Optionally returns the name with the given field
|
|
||||||
*
|
|
||||||
* @param String Field Name
|
|
||||||
*
|
|
||||||
* @return String
|
|
||||||
*/
|
*/
|
||||||
public function getFieldName($field = false) {
|
public function getFieldName($field = false) {
|
||||||
|
Deprecation::notice('4.0', "getFieldName({$field}) is deprecated");
|
||||||
return ($field) ? "Fields[".$this->ID."][".$field."]" : "Fields[".$this->ID."]";
|
return ($field) ? "Fields[".$this->ID."][".$field."]" : "Fields[".$this->ID."]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a name for the Setting field
|
* @deprecated since version 4.0
|
||||||
*
|
|
||||||
* @param String name of the setting
|
|
||||||
* @return String
|
|
||||||
*/
|
*/
|
||||||
public function getSettingName($field) {
|
public function getSettingName($field) {
|
||||||
|
Deprecation::notice('4.0', "getSettingName({$field}) is deprecated");
|
||||||
$name = $this->getFieldName('CustomSettings');
|
$name = $this->getFieldName('CustomSettings');
|
||||||
|
|
||||||
return $name . '[' . $field .']';
|
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'
|
* Append custom validation fields to the default 'Validation'
|
||||||
* section in the editable options view
|
* section in the editable options view
|
||||||
*
|
*
|
||||||
* @return FieldSet
|
* @return FieldList
|
||||||
*/
|
*/
|
||||||
public function getFieldValidationOptions() {
|
public function getFieldValidationOptions() {
|
||||||
$fields = new FieldList(
|
$fields = new FieldList(
|
||||||
new CheckboxField($this->getFieldName('Required'), _t('EditableFormField.REQUIRED', 'Is this field Required?'), $this->Required),
|
CheckboxField::create('Required', _t('EditableFormField.REQUIRED', 'Is this field Required?')),
|
||||||
new TextField($this->getFieldName('CustomErrorMessage'), _t('EditableFormField.CUSTOMERROR','Custom Error Message'), $this->CustomErrorMessage)
|
TextField::create('CustomErrorMessage', _t('EditableFormField.CUSTOMERROR','Custom Error Message'))
|
||||||
);
|
);
|
||||||
|
|
||||||
if(!$this->canEdit()) {
|
|
||||||
foreach($fields as $field) {
|
|
||||||
$field->performReadonlyTransformation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->extend('updateFieldValidationOptions', $fields);
|
$this->extend('updateFieldValidationOptions', $fields);
|
||||||
|
|
||||||
@ -533,4 +557,53 @@ class EditableFormField extends DataObject {
|
|||||||
|
|
||||||
return DBField::create_field('Varchar', $errorMessage);
|
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->DisplayRules()->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked by UserFormUpgradeService to migrate settings specific to this field from CustomSettings
|
||||||
|
* to the field proper
|
||||||
|
*
|
||||||
|
* @param array $data Unserialised data
|
||||||
|
*/
|
||||||
|
public function migrateSettings($data) {
|
||||||
|
// Map 'Show' / 'Hide' to boolean
|
||||||
|
if(isset($data['ShowOnLoad'])) {
|
||||||
|
$this->ShowOnLoad = $data['ShowOnLoad'] === '' || ($data['ShowOnLoad'] && $data['ShowOnLoad'] !== 'Hide');
|
||||||
|
unset($data['ShowOnLoad']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate all other settings
|
||||||
|
foreach($data as $key => $value) {
|
||||||
|
if($this->hasField($key)) {
|
||||||
|
$this->setField($key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,26 @@ class EditableFormHeading extends EditableFormField {
|
|||||||
private static $singular_name = 'Heading';
|
private static $singular_name = 'Heading';
|
||||||
|
|
||||||
private static $plural_name = 'Headings';
|
private static $plural_name = 'Headings';
|
||||||
|
|
||||||
public function getFieldConfiguration() {
|
private static $db = array(
|
||||||
|
'Level' => 'Int(3)', // From CustomSettings
|
||||||
|
'HideFromReports' => 'Boolean(0)' // from CustomSettings
|
||||||
|
);
|
||||||
|
|
||||||
|
private static $defaults = array(
|
||||||
|
'Level' => 3,
|
||||||
|
'HideFromReports' => false
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
public function getCMSFields() {
|
||||||
|
$fields = parent::getCMSFields();
|
||||||
|
|
||||||
|
$fields->removeByName('Default');
|
||||||
|
$fields->removeByName('Validation');
|
||||||
|
|
||||||
$levels = array(
|
$levels = array(
|
||||||
'1' => '1',
|
'1' => '1',
|
||||||
'2' => '2',
|
'2' => '2',
|
||||||
@ -21,39 +39,29 @@ class EditableFormHeading extends EditableFormField {
|
|||||||
'6' => '6'
|
'6' => '6'
|
||||||
);
|
);
|
||||||
|
|
||||||
$level = ($this->getSetting('Level')) ? $this->getSetting('Level') : 3;
|
$fields->addFieldsToTab('Root.Main', array(
|
||||||
$label = _t('EditableFormHeading.LEVEL', 'Select Heading Level');
|
DropdownField::create(
|
||||||
|
'Level',
|
||||||
$options = parent::getFieldConfiguration();
|
_t('EditableFormHeading.LEVEL', 'Select Heading Level'),
|
||||||
|
$levels
|
||||||
$options->push(
|
),
|
||||||
new DropdownField($this->getSettingName("Level"), $label, $levels, $level)
|
CheckboxField::create(
|
||||||
);
|
'HideFromReports',
|
||||||
|
_t('EditableLiteralField.HIDEFROMREPORT', 'Hide from reports?')
|
||||||
if($this->readonly) {
|
|
||||||
$extraFields = $options->makeReadonly();
|
|
||||||
}
|
|
||||||
|
|
||||||
$options->push(
|
|
||||||
new CheckboxField(
|
|
||||||
$this->getSettingName('HideFromReports'),
|
|
||||||
_t('EditableLiteralField.HIDEFROMREPORT', 'Hide from reports?'),
|
|
||||||
$this->getSetting('HideFromReports')
|
|
||||||
)
|
)
|
||||||
);
|
));
|
||||||
|
|
||||||
return $options;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
$labelField = new HeaderField($this->Name,$this->Title, $this->getSetting('Level'));
|
$labelField = new HeaderField($this->Name, $this->Title, $this->Level);
|
||||||
$labelField->addExtraClass('FormHeading');
|
$labelField->addExtraClass('FormHeading');
|
||||||
|
|
||||||
return $labelField;
|
return $labelField;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function showInReports() {
|
public function showInReports() {
|
||||||
return (!$this->getSetting('HideFromReports'));
|
return !$this->HideFromReports;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFieldValidationOptions() {
|
public function getFieldValidationOptions() {
|
||||||
|
@ -21,6 +21,15 @@ class EditableLiteralField extends EditableFormField {
|
|||||||
*/
|
*/
|
||||||
private static $editor_config = null;
|
private static $editor_config = null;
|
||||||
|
|
||||||
|
private static $db = array(
|
||||||
|
'Content' => 'HTMLText', // From CustomSettings
|
||||||
|
'HideFromReports' => 'Boolean(0)' // from CustomSettings
|
||||||
|
);
|
||||||
|
|
||||||
|
private static $defaults = array(
|
||||||
|
'HideFromReports' => false
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@see HtmlEditorConfig} instance to use for sanitisation
|
* Returns the {@see HtmlEditorConfig} instance to use for sanitisation
|
||||||
*
|
*
|
||||||
@ -56,7 +65,7 @@ class EditableLiteralField extends EditableFormField {
|
|||||||
*/
|
*/
|
||||||
public function getContent() {
|
public function getContent() {
|
||||||
// Apply html editor sanitisation rules
|
// Apply html editor sanitisation rules
|
||||||
$content = $this->getSetting('Content');
|
$content = $this->getField('Content');
|
||||||
return $this->sanitiseContent($content);
|
return $this->sanitiseContent($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,41 +77,53 @@ class EditableLiteralField extends EditableFormField {
|
|||||||
public function setContent($content) {
|
public function setContent($content) {
|
||||||
// Apply html editor sanitisation rules
|
// Apply html editor sanitisation rules
|
||||||
$content = $this->sanitiseContent($content);
|
$content = $this->sanitiseContent($content);
|
||||||
$this->setSetting('Content', $content);
|
$this->setField('Content', $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFieldConfiguration() {
|
/**
|
||||||
$textAreaField = new HTMLEditorField(
|
* @return FieldList
|
||||||
$this->getSettingName('Content'),
|
*/
|
||||||
"HTML",
|
public function getCMSFields() {
|
||||||
$this->getContent()
|
$fields = parent::getCMSFields();
|
||||||
);
|
|
||||||
$textAreaField->setRows(4);
|
$fields->removeByName('Default');
|
||||||
$textAreaField->setColumns(20);
|
$fields->removeByName('Validation');
|
||||||
|
|
||||||
return new FieldList(
|
$fields->addFieldsToTab('Root.Main', array(
|
||||||
$textAreaField,
|
HTMLEditorField::create('Content', _t('EditableLiteralField.CONTENT', 'HTML'))
|
||||||
new CheckboxField(
|
->setRows(4)
|
||||||
$this->getSettingName('HideFromReports'),
|
->setColumns(20),
|
||||||
_t('EditableLiteralField.HIDEFROMREPORT', 'Hide from reports?'),
|
CheckboxField::create(
|
||||||
$this->getSetting('HideFromReports')
|
'HideFromReports',
|
||||||
|
_t('EditableLiteralField.HIDEFROMREPORT', 'Hide from reports?')
|
||||||
)
|
)
|
||||||
);
|
));
|
||||||
|
|
||||||
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
$label = $this->Title ? "<label class='left'>$this->Title</label>":"";
|
$label = $this->Title
|
||||||
|
? "<label class='left'>".Convert::raw2xml($this->Title)."</label>"
|
||||||
|
: "";
|
||||||
$classes = $this->Title ? "" : " nolabel";
|
$classes = $this->Title ? "" : " nolabel";
|
||||||
|
|
||||||
return new LiteralField("LiteralField[$this->ID]",
|
return new LiteralField(
|
||||||
"<div id='$this->Name' class='field text$classes'>
|
"LiteralField[{$this->ID}]",
|
||||||
$label
|
sprintf(
|
||||||
<div class='middleColumn literalFieldArea'>". $this->getSetting('Content') ."</div>".
|
"<div id='%s' class='field text%s'>
|
||||||
"</div>"
|
%s
|
||||||
|
<div class='middleColumn literalFieldArea'>%s</div>".
|
||||||
|
"</div>",
|
||||||
|
Convert::raw2htmlname($this->Name),
|
||||||
|
Convert::raw2att($classes),
|
||||||
|
$label,
|
||||||
|
$this->Content
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function showInReports() {
|
public function showInReports() {
|
||||||
return (!$this->getSetting('HideFromReports'));
|
return ! $this->HideFromReports;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,37 +10,46 @@ class EditableMemberListField extends EditableFormField {
|
|||||||
private static $singular_name = 'Member List Field';
|
private static $singular_name = 'Member List Field';
|
||||||
|
|
||||||
private static $plural_name = 'Member List Fields';
|
private static $plural_name = 'Member List Fields';
|
||||||
|
|
||||||
public function getFieldConfiguration() {
|
private static $has_one = array(
|
||||||
$groupID = ($this->getSetting('GroupID')) ? $this->getSetting('GroupID') : 0;
|
'Group' => 'Group'
|
||||||
$groups = DataObject::get("Group");
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
public function getCMSFields() {
|
||||||
|
$fields = parent::getCMSFields();
|
||||||
|
|
||||||
|
$fields->removeByName('Default');
|
||||||
|
$fields->removeByName('Validation');
|
||||||
|
|
||||||
if($groups) $groups = $groups->map('ID', 'Title');
|
$fields->addFieldToTab(
|
||||||
|
'Root.Main',
|
||||||
$fields = new FieldList(
|
DropdownField::create(
|
||||||
new DropdownField("Fields[$this->ID][CustomSettings][GroupID]", _t('EditableFormField.GROUP', 'Group'), $groups, $groupID)
|
"GroupID",
|
||||||
|
_t('EditableFormField.GROUP', 'Group'),
|
||||||
|
Group::get()->map()
|
||||||
|
)->setEmptyString(' ')
|
||||||
);
|
);
|
||||||
|
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
if ($this->getSetting('GroupID')) {
|
if(empty($this->GroupID)) {
|
||||||
$members = Member::map_in_groups($this->getSetting('GroupID'));
|
return false;
|
||||||
|
|
||||||
return new DropdownField($this->Name, $this->Title, $members);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
$members = Member::map_in_groups($this->GroupID);
|
||||||
|
return new DropdownField($this->Name, $this->Title, $members);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValueFromData($data) {
|
public function getValueFromData($data) {
|
||||||
if(isset($data[$this->Name])) {
|
if(isset($data[$this->Name])) {
|
||||||
$value = Convert::raw2sql($data[$this->Name]);
|
$memberID = $data[$this->Name];
|
||||||
|
$member = Member::get()->byID($memberID);
|
||||||
$member = DataObject::get_one('Member', "Member.ID = {$value}");
|
return $member ? $member->getName() : "";
|
||||||
|
|
||||||
return ($member) ? $member->getName() : "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -18,6 +18,52 @@ class EditableMultipleOptionField extends EditableFormField {
|
|||||||
private static $has_many = array(
|
private static $has_many = array(
|
||||||
"Options" => "EditableOption"
|
"Options" => "EditableOption"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
public function getCMSFields() {
|
||||||
|
$fields = parent::getCMSFields();
|
||||||
|
|
||||||
|
$editableColumns = new GridFieldEditableColumns();
|
||||||
|
$editableColumns->setDisplayFields(array(
|
||||||
|
'Title' => array(
|
||||||
|
'title' => 'Title',
|
||||||
|
'callback' => function($record, $column, $grid) {
|
||||||
|
return TextField::create($column);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'Default' => array(
|
||||||
|
'title' => _t('EditableMultipleOptionField.DEFAULT', 'Selected by default?'),
|
||||||
|
'callback' => function($record, $column, $grid) {
|
||||||
|
return CheckboxField::create($column);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
$optionsConfig = GridFieldConfig::create()
|
||||||
|
->addComponents(
|
||||||
|
new GridFieldToolbarHeader(),
|
||||||
|
new GridFieldTitleHeader(),
|
||||||
|
$editableColumns,
|
||||||
|
new GridFieldButtonRow(),
|
||||||
|
new GridFieldAddNewInlineButton(),
|
||||||
|
new GridFieldDeleteAction(),
|
||||||
|
new GridState_Component()
|
||||||
|
);
|
||||||
|
|
||||||
|
$optionsGrid = GridField::create(
|
||||||
|
'Options',
|
||||||
|
_t('EditableFormField.CUSTOMOPTIONS', 'Options'),
|
||||||
|
$this->Options(),
|
||||||
|
$optionsConfig
|
||||||
|
);
|
||||||
|
|
||||||
|
$fields->insertAfter(new Tab('Options'), 'Main');
|
||||||
|
$fields->addFieldToTab('Root.Options', $optionsGrid);
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishing Versioning support.
|
* Publishing Versioning support.
|
||||||
@ -89,40 +135,16 @@ class EditableMultipleOptionField extends EditableFormField {
|
|||||||
public function duplicate($doWrite = true) {
|
public function duplicate($doWrite = true) {
|
||||||
$clonedNode = parent::duplicate();
|
$clonedNode = parent::duplicate();
|
||||||
|
|
||||||
if($this->Options()) {
|
foreach($this->Options() as $field) {
|
||||||
foreach($this->Options() as $field) {
|
$newField = $field->duplicate(false);
|
||||||
$newField = $field->duplicate();
|
$newField->ParentID = $clonedNode->ID;
|
||||||
$newField->ParentID = $clonedNode->ID;
|
$newField->Version = 0;
|
||||||
$newField->write();
|
$newField->write();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $clonedNode;
|
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
|
* Return whether or not this field has addable options such as a
|
||||||
* {@link EditableDropdownField} or {@link EditableRadioField}
|
* {@link EditableDropdownField} or {@link EditableRadioField}
|
||||||
|
@ -12,6 +12,11 @@ class EditableNumericField extends EditableFormField {
|
|||||||
private static $singular_name = 'Numeric Field';
|
private static $singular_name = 'Numeric Field';
|
||||||
|
|
||||||
private static $plural_name = 'Numeric Fields';
|
private static $plural_name = 'Numeric Fields';
|
||||||
|
|
||||||
|
private static $db = array(
|
||||||
|
'MinValue' => 'Int',
|
||||||
|
'MaxValue' => 'Int'
|
||||||
|
);
|
||||||
|
|
||||||
public function getSetsOwnError() {
|
public function getSetsOwnError() {
|
||||||
return true;
|
return true;
|
||||||
@ -23,6 +28,7 @@ class EditableNumericField extends EditableFormField {
|
|||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
$field = new NumericField($this->Name, $this->Title);
|
$field = new NumericField($this->Name, $this->Title);
|
||||||
$field->addExtraClass('number');
|
$field->addExtraClass('number');
|
||||||
|
$field->setValue($this->Default);
|
||||||
|
|
||||||
if ($this->Required) {
|
if ($this->Required) {
|
||||||
// Required and numeric validation can conflict so add the
|
// Required and numeric validation can conflict so add the
|
||||||
@ -37,31 +43,25 @@ class EditableNumericField extends EditableFormField {
|
|||||||
|
|
||||||
public function getFieldValidationOptions() {
|
public function getFieldValidationOptions() {
|
||||||
$fields = parent::getFieldValidationOptions();
|
$fields = parent::getFieldValidationOptions();
|
||||||
|
$fields->push(FieldGroup::create(
|
||||||
$min = ($this->getSetting('MinValue')) ? $this->getSetting('MinValue') : '';
|
_t("EditableNumericField.RANGE", "Allowed numeric range"),
|
||||||
$max = ($this->getSetting('MaxValue')) ? $this->getSetting('MaxValue') : '';
|
array(
|
||||||
|
new NumericField('MinValue', false),
|
||||||
$extraFields = new FieldList(
|
new LiteralField('RangeValue', _t("EditableNumericField.RANGE_TO", "to")),
|
||||||
new NumericField($this->getSettingName('MinValue'), _t('EditableFormField.MINVALUE', 'Min Value'), $min),
|
new NumericField('MaxValue', false)
|
||||||
new NumericField($this->getSettingName('MaxValue'), _t('EditableFormField.MAXVALUE', 'Max Value'), $max)
|
)
|
||||||
);
|
));
|
||||||
|
|
||||||
$fields->merge($extraFields);
|
|
||||||
|
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getValidation() {
|
public function getValidation() {
|
||||||
$options = array();
|
$options = array();
|
||||||
|
if($this->MinValue) {
|
||||||
if($this->getSetting('MinValue')) {
|
$options['min'] = (int)$this->MinValue;
|
||||||
$options['min'] = 0 + (int) $this->getSetting('MinValue');
|
|
||||||
}
|
}
|
||||||
|
if($this->MaxValue) {
|
||||||
if($this->getSetting('MaxValue')) {
|
$options['max'] = (int)$this->MaxValue;
|
||||||
$options['max'] = 0 + (int)$this->getSetting('MaxValue');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,23 +26,28 @@ class EditableOption extends DataObject {
|
|||||||
"Versioned('Stage', 'Live')"
|
"Versioned('Stage', 'Live')"
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
private static $summary_fields = array(
|
||||||
* @param Member $member
|
'Title',
|
||||||
*
|
'Default'
|
||||||
* @return boolean
|
);
|
||||||
*/
|
|
||||||
public function canEdit($member = null) {
|
|
||||||
return ($this->Parent()->canEdit($member));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Member $member
|
* @param Member $member
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function canDelete($member = null) {
|
public function canEdit($member = null) {
|
||||||
return ($this->Parent()->canDelete($member));
|
return ($this->Parent()->canEdit($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
|
* Template for the editing view of this option field
|
||||||
@ -68,20 +73,6 @@ class EditableOption extends DataObject {
|
|||||||
public function FieldName() {
|
public function FieldName() {
|
||||||
return "Fields[{$this->ParentID}][{$this->ID}]";
|
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
|
* Make this option readonly
|
||||||
@ -91,7 +82,7 @@ class EditableOption extends DataObject {
|
|||||||
return $this->EditSegment();
|
return $this->EditSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEscapedTitle() {
|
public function getEscapedTitle() {
|
||||||
return Convert::raw2att($this->Title);
|
return Convert::raw2att($this->Title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,17 +12,35 @@ class EditableRadioField extends EditableMultipleOptionField {
|
|||||||
private static $singular_name = 'Radio field';
|
private static $singular_name = 'Radio field';
|
||||||
|
|
||||||
private static $plural_name = 'Radio fields';
|
private static $plural_name = 'Radio fields';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
public function getCMSFields() {
|
||||||
|
$fields = parent::getCMSFields();
|
||||||
|
|
||||||
|
$fields->removeByName('Default');
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
$optionSet = $this->Options();
|
$optionSet = $this->Options();
|
||||||
|
$defaultOptions = $optionSet->filter('Default', 1);
|
||||||
$options = array();
|
$options = array();
|
||||||
|
|
||||||
if($optionSet) {
|
if($optionSet) {
|
||||||
foreach( $optionSet as $option ) {
|
foreach($optionSet as $option) {
|
||||||
$options[$option->EscapedTitle] = $option->Title;
|
$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,42 +12,63 @@ class EditableTextField extends EditableFormField {
|
|||||||
private static $singular_name = 'Text Field';
|
private static $singular_name = 'Text Field';
|
||||||
|
|
||||||
private static $plural_name = 'Text Fields';
|
private static $plural_name = 'Text Fields';
|
||||||
|
|
||||||
public function getFieldConfiguration() {
|
private static $db = array(
|
||||||
$fields = parent::getFieldConfiguration();
|
'MinLength' => 'Int',
|
||||||
|
'MaxLength' => 'Int',
|
||||||
$min = ($this->getSetting('MinLength')) ? $this->getSetting('MinLength') : '';
|
'Rows' => 'Int(1)'
|
||||||
$max = ($this->getSetting('MaxLength')) ? $this->getSetting('MaxLength') : '';
|
);
|
||||||
|
|
||||||
$rows = ($this->getSetting('Rows')) ? $this->getSetting('Rows') : '1';
|
private static $defaults = array(
|
||||||
|
'Rows' => 1
|
||||||
$extraFields = new FieldList(
|
);
|
||||||
new FieldGroup(_t('EditableTextField.TEXTLENGTH', 'Text length'),
|
|
||||||
new NumericField($this->getSettingName('MinLength'), "", $min),
|
public function getCMSFields() {
|
||||||
new NumericField($this->getSettingName('MaxLength'), " - ", $max)
|
$this->beforeUpdateCMSFields(function($fields) {
|
||||||
),
|
$fields->addFieldToTab(
|
||||||
new NumericField($this->getSettingName('Rows'), _t('EditableTextField.NUMBERROWS',
|
'Root.Main',
|
||||||
'Number of rows'), $rows)
|
NumericField::create(
|
||||||
);
|
'Rows',
|
||||||
|
_t('EditableTextField.NUMBERROWS', 'Number of rows')
|
||||||
$fields->merge($extraFields);
|
)->setDescription(_t(
|
||||||
|
'EditableTextField.NUMBERROWS_DESCRIPTION',
|
||||||
return $fields;
|
'Fields with more than one row will be generated as a textarea'
|
||||||
|
))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return parent::getCMSFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
public function getFieldValidationOptions() {
|
||||||
|
$fields = parent::getFieldValidationOptions();
|
||||||
|
|
||||||
|
$fields->merge(array(
|
||||||
|
FieldGroup::create(
|
||||||
|
_t('EditableTextField.TEXTLENGTH', 'Allowed text length'),
|
||||||
|
array(
|
||||||
|
NumericField::create('MinLength', false),
|
||||||
|
LiteralField::create('RangeLength', _t("EditableTextField.RANGE_TO", "to")),
|
||||||
|
NumericField::create('MaxLength', false)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return TextareaField|TextField
|
* @return TextareaField|TextField
|
||||||
*/
|
*/
|
||||||
public function getFormField() {
|
public function getFormField() {
|
||||||
|
if($this->Rows > 1) {
|
||||||
$field = NULL;
|
|
||||||
|
|
||||||
if($this->getSetting('Rows') && $this->getSetting('Rows') > 1) {
|
|
||||||
$field = TextareaField::create($this->Name, $this->Title);
|
$field = TextareaField::create($this->Name, $this->Title);
|
||||||
$field->setRows($this->getSetting('Rows'));
|
$field->setRows($this->Rows);
|
||||||
}
|
} else {
|
||||||
else {
|
$field = TextField::create($this->Name, $this->Title, null, $this->MaxLength);
|
||||||
$field = TextField::create($this->Name, $this->Title, null, $this->getSetting('MaxLength'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->Required) {
|
if ($this->Required) {
|
||||||
@ -57,6 +78,8 @@ class EditableTextField extends EditableFormField {
|
|||||||
$field->setAttribute('data-rule-required', 'true');
|
$field->setAttribute('data-rule-required', 'true');
|
||||||
$field->setAttribute('data-msg-required', $errorMessage);
|
$field->setAttribute('data-msg-required', $errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$field->setValue($this->Default);
|
||||||
|
|
||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
@ -71,15 +94,12 @@ class EditableTextField extends EditableFormField {
|
|||||||
*/
|
*/
|
||||||
public function getValidation() {
|
public function getValidation() {
|
||||||
$options = parent::getValidation();
|
$options = parent::getValidation();
|
||||||
|
if($this->MinLength) {
|
||||||
if($this->getSetting('MinLength')) {
|
$options['minlength'] = (int)$this->MinLength;
|
||||||
$options['minlength'] = $this->getSetting('MinLength');
|
}
|
||||||
|
if($this->MaxLength) {
|
||||||
|
$options['maxlength'] = (int)$this->MaxLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->getSetting('MaxLength')) {
|
|
||||||
$options['maxlength'] = $this->getSetting('MaxLength');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
378
code/model/recipients/UserDefinedForm_EmailRecipient.php
Normal file
378
code/model/recipients/UserDefinedForm_EmailRecipient.php
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Form can have multiply members / emails to email the submission
|
||||||
|
* to and custom subjects
|
||||||
|
*
|
||||||
|
* @package userforms
|
||||||
|
*/
|
||||||
|
class UserDefinedForm_EmailRecipient extends DataObject {
|
||||||
|
|
||||||
|
private static $db = array(
|
||||||
|
'EmailAddress' => 'Varchar(200)',
|
||||||
|
'EmailSubject' => 'Varchar(200)',
|
||||||
|
'EmailFrom' => 'Varchar(200)',
|
||||||
|
'EmailReplyTo' => 'Varchar(200)',
|
||||||
|
'EmailBody' => 'Text',
|
||||||
|
'EmailBodyHtml' => 'HTMLText',
|
||||||
|
'EmailTemplate' => 'Varchar',
|
||||||
|
'SendPlain' => 'Boolean',
|
||||||
|
'HideFormData' => 'Boolean',
|
||||||
|
'CustomRulesCondition' => 'Enum("And,Or")'
|
||||||
|
);
|
||||||
|
|
||||||
|
private static $has_one = array(
|
||||||
|
'Form' => 'UserDefinedForm',
|
||||||
|
'SendEmailFromField' => 'EditableFormField',
|
||||||
|
'SendEmailToField' => 'EditableFormField',
|
||||||
|
'SendEmailSubjectField' => 'EditableFormField'
|
||||||
|
);
|
||||||
|
|
||||||
|
private static $has_many = array(
|
||||||
|
'CustomRules' => 'UserDefinedForm_EmailRecipientCondition'
|
||||||
|
);
|
||||||
|
|
||||||
|
private static $summary_fields = array(
|
||||||
|
'EmailAddress',
|
||||||
|
'EmailSubject',
|
||||||
|
'EmailFrom'
|
||||||
|
);
|
||||||
|
|
||||||
|
public function summaryFields() {
|
||||||
|
$fields = parent::summaryFields();
|
||||||
|
if(isset($fields['EmailAddress'])) {
|
||||||
|
$fields['EmailAddress'] = _t('UserDefinedForm.EMAILADDRESS', 'Email');
|
||||||
|
}
|
||||||
|
if(isset($fields['EmailSubject'])) {
|
||||||
|
$fields['EmailSubject'] = _t('UserDefinedForm.EMAILSUBJECT', 'Subject');
|
||||||
|
}
|
||||||
|
if(isset($fields['EmailFrom'])) {
|
||||||
|
$fields['EmailFrom'] = _t('UserDefinedForm.EMAILFROM', 'From');
|
||||||
|
}
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get instance of UserDefinedForm when editing in getCMSFields
|
||||||
|
*
|
||||||
|
* @return UserDefinedFrom
|
||||||
|
*/
|
||||||
|
protected function getFormParent() {
|
||||||
|
$formID = $this->FormID
|
||||||
|
? $this->FormID
|
||||||
|
: Session::get('CMSMain.currentPage');
|
||||||
|
return UserDefinedForm::get()->byID($formID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
if($this->EmailAddress) {
|
||||||
|
return $this->EmailAddress;
|
||||||
|
}
|
||||||
|
if($this->EmailSubject) {
|
||||||
|
return $this->EmailSubject;
|
||||||
|
}
|
||||||
|
return parent::getTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a gridfield config for editing filter rules
|
||||||
|
*
|
||||||
|
* @return GridFieldConfig
|
||||||
|
*/
|
||||||
|
protected function getRulesConfig() {
|
||||||
|
$formFields = $this->getFormParent()->Fields();
|
||||||
|
|
||||||
|
$config = GridFieldConfig::create()
|
||||||
|
->addComponents(
|
||||||
|
new GridFieldButtonRow('before'),
|
||||||
|
new GridFieldToolbarHeader(),
|
||||||
|
new GridFieldAddNewInlineButton(),
|
||||||
|
new GridState_Component(),
|
||||||
|
new GridFieldDeleteAction(),
|
||||||
|
$columns = new GridFieldEditableColumns()
|
||||||
|
);
|
||||||
|
|
||||||
|
$columns->setDisplayFields(array(
|
||||||
|
'ConditionFieldID' => function($record, $column, $grid) use ($formFields) {
|
||||||
|
return DropdownField::create($column, false, $formFields->map('ID', 'Title'));
|
||||||
|
},
|
||||||
|
'ConditionOption' => function($record, $column, $grid) {
|
||||||
|
$options = UserDefinedForm_EmailRecipientCondition::config()->condition_options;
|
||||||
|
return DropdownField::create($column, false, $options);
|
||||||
|
},
|
||||||
|
'ConditionValue' => function($record, $column, $grid) {
|
||||||
|
return TextField::create($column);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldList
|
||||||
|
*/
|
||||||
|
public function getCMSFields() {
|
||||||
|
Requirements::javascript(USERFORMS_DIR . '/javascript/Recipient.js');
|
||||||
|
|
||||||
|
// Determine optional field values
|
||||||
|
$form = $this->getFormParent();
|
||||||
|
|
||||||
|
// predefined choices are also candidates
|
||||||
|
$multiOptionFields = EditableMultipleOptionField::get()->filter('ParentID', $form->ID);
|
||||||
|
|
||||||
|
// if they have email fields then we could send from it
|
||||||
|
$validEmailFromFields = EditableEmailField::get()->filter('ParentID', $form->ID);
|
||||||
|
|
||||||
|
// For the subject, only one-line entry boxes make sense
|
||||||
|
$validSubjectFields = ArrayList::create(
|
||||||
|
EditableTextField::get()
|
||||||
|
->filter('ParentID', $form->ID)
|
||||||
|
->exclude('Rows:GreaterThan', 1)
|
||||||
|
->toArray()
|
||||||
|
);
|
||||||
|
$validSubjectFields->merge($multiOptionFields);
|
||||||
|
|
||||||
|
// To address can only be email fields or multi option fields
|
||||||
|
$validEmailToFields = new ArrayList($validEmailFromFields->toArray());
|
||||||
|
$validEmailToFields->merge($multiOptionFields);
|
||||||
|
|
||||||
|
// Build fieldlist
|
||||||
|
$fields = FieldList::create(Tabset::create('Root')->addExtraClass('EmailRecipientForm'));
|
||||||
|
|
||||||
|
// Configuration fields
|
||||||
|
$fields->addFieldsToTab('Root.EmailDetails', array(
|
||||||
|
// Subject
|
||||||
|
FieldGroup::create(
|
||||||
|
TextField::create('EmailSubject', _t('UserDefinedForm.TYPESUBJECT', 'Type subject'))
|
||||||
|
->setAttribute('style', 'min-width: 400px;'),
|
||||||
|
DropdownField::create(
|
||||||
|
'SendEmailSubjectFieldID',
|
||||||
|
_t('UserDefinedForm.SELECTAFIELDTOSETSUBJECT', '.. or select a field to use as the subject'),
|
||||||
|
$validSubjectFields->map('ID', 'Title')
|
||||||
|
)->setEmptyString('')
|
||||||
|
)
|
||||||
|
->setTitle(_t('UserDefinedForm.EMAILSUBJECT', 'Email subject')),
|
||||||
|
|
||||||
|
// To
|
||||||
|
FieldGroup::create(
|
||||||
|
TextField::create('EmailAddress', _t('UserDefinedForm.TYPETO', 'Type to address'))
|
||||||
|
->setAttribute('style', 'min-width: 400px;'),
|
||||||
|
DropdownField::create(
|
||||||
|
'SendEmailToFieldID',
|
||||||
|
_t('UserDefinedForm.ORSELECTAFIELDTOUSEASTO', '.. or select a field to use as the to address'),
|
||||||
|
$validEmailToFields->map('ID', 'Title')
|
||||||
|
)->setEmptyString(' ')
|
||||||
|
)
|
||||||
|
->setTitle(_t('UserDefinedForm.SENDEMAILTO','Send email to'))
|
||||||
|
->setDescription(_t(
|
||||||
|
'UserDefinedForm.SENDEMAILTO_DESCRIPTION',
|
||||||
|
'You may enter multiple email addresses as a comma separated list.'
|
||||||
|
)),
|
||||||
|
|
||||||
|
|
||||||
|
// From
|
||||||
|
TextField::create('EmailFrom', _t('UserDefinedForm.FROMADDRESS','Send email from'))
|
||||||
|
->setDescription(_t(
|
||||||
|
'UserDefinedForm.EmailFromContent',
|
||||||
|
"The from address allows you to set who the email comes from. On most servers this ".
|
||||||
|
"will need to be set to an email address on the same domain name as your site. ".
|
||||||
|
"For example on yoursite.com the from address may need to be something@yoursite.com. ".
|
||||||
|
"You can however, set any email address you wish as the reply to address."
|
||||||
|
)),
|
||||||
|
|
||||||
|
|
||||||
|
// Reply-To
|
||||||
|
FieldGroup::create(
|
||||||
|
TextField::create('EmailReplyTo', _t('UserDefinedForm.TYPEREPLY', 'Type reply address'))
|
||||||
|
->setAttribute('style', 'min-width: 400px;'),
|
||||||
|
DropdownField::create(
|
||||||
|
'SendEmailFromFieldID',
|
||||||
|
_t('UserDefinedForm.ORSELECTAFIELDTOUSEASFROM', '.. or select a field to use as reply to address'),
|
||||||
|
$validEmailFromFields->map('ID', 'Title')
|
||||||
|
)->setEmptyString(' ')
|
||||||
|
)
|
||||||
|
->setTitle(_t('UserDefinedForm.REPLYADDRESS', 'Email for reply to'))
|
||||||
|
->setDescription(_t(
|
||||||
|
'UserDefinedForm.REPLYADDRESS_DESCRIPTION',
|
||||||
|
'The email address which the recipient is able to \'reply\' to.'
|
||||||
|
))
|
||||||
|
));
|
||||||
|
|
||||||
|
// Only show the preview link if the recipient has been saved.
|
||||||
|
if (!empty($this->EmailTemplate)) {
|
||||||
|
$preview = sprintf(
|
||||||
|
'<p><a href="%s" target="_blank" class="ss-ui-button">%s</a></p><em>%s</em>',
|
||||||
|
"admin/pages/edit/EditForm/field/EmailRecipients/item/{$this->ID}/preview",
|
||||||
|
_t('UserDefinedForm.PREVIEW_EMAIL', 'Preview email'),
|
||||||
|
_t('UserDefinedForm.PREVIEW_EMAIL_DESCRIPTION', 'Note: Unsaved changes will not appear in the preview.')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$preview = sprintf(
|
||||||
|
'<em>%s</em>',
|
||||||
|
_t(
|
||||||
|
'UserDefinedForm.PREVIEW_EMAIL_UNAVAILABLE',
|
||||||
|
'You can preview this email once you have saved the Recipient.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email templates
|
||||||
|
$fields->addFieldsToTab('Root.EmailContent', array(
|
||||||
|
CheckboxField::create('HideFormData', _t('UserDefinedForm.HIDEFORMDATA', 'Hide form data from email?')),
|
||||||
|
CheckboxField::create(
|
||||||
|
'SendPlain',
|
||||||
|
_t('UserDefinedForm.SENDPLAIN', 'Send email as plain text? (HTML will be stripped)')
|
||||||
|
),
|
||||||
|
DropdownField::create(
|
||||||
|
'EmailTemplate',
|
||||||
|
_t('UserDefinedForm.EMAILTEMPLATE', 'Email template'),
|
||||||
|
$this->getEmailTemplateDropdownValues()
|
||||||
|
)->addExtraClass('toggle-html-only'),
|
||||||
|
HTMLEditorField::create('EmailBodyHtml', _t('UserDefinedForm.EMAILBODYHTML','Body'))
|
||||||
|
->addExtraClass('toggle-html-only'),
|
||||||
|
TextareaField::create('EmailBody', _t('UserDefinedForm.EMAILBODY','Body'))
|
||||||
|
->addExtraClass('toggle-plain-only'),
|
||||||
|
LiteralField::create(
|
||||||
|
'EmailPreview',
|
||||||
|
'<div id="EmailPreview" class="field toggle-html-only">' . $preview . '</div>'
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
// Custom rules for sending this field
|
||||||
|
$grid = new GridField(
|
||||||
|
"CustomRules",
|
||||||
|
_t('EditableFormField.CUSTOMRULES', 'Custom Rules'),
|
||||||
|
$this->CustomRules(),
|
||||||
|
$this->getRulesConfig()
|
||||||
|
);
|
||||||
|
$grid->setDescription(_t(
|
||||||
|
'UserDefinedForm.RulesDescription',
|
||||||
|
'Emails will only be sent to the recipient if the custom rules are met. If no rules are defined, this receipient will receive notifications for every submission.'
|
||||||
|
));
|
||||||
|
$fields->addFieldsToTab('Root.CustomRules', array(
|
||||||
|
new DropdownField(
|
||||||
|
'CustomRulesCondition',
|
||||||
|
_t('UserDefinedForm.SENDIF', 'Send condition'),
|
||||||
|
array(
|
||||||
|
'Or' => 'Any conditions are true',
|
||||||
|
'And' => 'All conditions are true'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
$grid
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->extend('updateCMSFields', $fields);
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Member
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function canCreate($member = null) {
|
||||||
|
return $this->Form()->canCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Member
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function canView($member = null) {
|
||||||
|
return $this->Form()->canView();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Member
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function canEdit($member = null) {
|
||||||
|
return $this->Form()->canEdit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Member
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function canDelete($member = null) {
|
||||||
|
return $this->Form()->canDelete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if this recipient may receive notifications for this submission
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @param Form $form
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function canSend($data, $form) {
|
||||||
|
// Skip if no rules configured
|
||||||
|
$customRules = $this->CustomRules();
|
||||||
|
if(!$customRules->count()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check all rules
|
||||||
|
$isAnd = $this->CustomRulesCondition === 'And';
|
||||||
|
foreach($customRules as $customRule) {
|
||||||
|
$matches = $customRule->matches($data, $form);
|
||||||
|
if($isAnd && !$matches) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!$isAnd && $matches) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once all rules are checked
|
||||||
|
return $isAnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure the email template saved against the recipient exists on the file system.
|
||||||
|
*
|
||||||
|
* @param string
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function emailTemplateExists($template = '') {
|
||||||
|
$t = ($template ? $template : $this->EmailTemplate);
|
||||||
|
|
||||||
|
return in_array($t, $this->getEmailTemplateDropdownValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the email body for the current email format
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getEmailBodyContent() {
|
||||||
|
return $this->SendPlain ? $this->EmailBody : $this->EmailBodyHtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of email templates suitable for populating the email template dropdown.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getEmailTemplateDropdownValues() {
|
||||||
|
$templates = array();
|
||||||
|
|
||||||
|
$finder = new SS_FileFinder();
|
||||||
|
$finder->setOption('name_regex', '/^.*\.ss$/');
|
||||||
|
|
||||||
|
$found = $finder->find(BASE_PATH . '/' . UserDefinedForm::config()->email_template_directory);
|
||||||
|
|
||||||
|
foreach ($found as $key => $value) {
|
||||||
|
$template = pathinfo($value);
|
||||||
|
|
||||||
|
$templates[$template['filename']] = $template['filename'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $templates;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares a condition that determines whether an email can be sent to a given recipient
|
||||||
|
*/
|
||||||
|
class UserDefinedForm_EmailRecipientCondition extends DataObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of options
|
||||||
|
*
|
||||||
|
* @config
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $condition_options = array(
|
||||||
|
"IsBlank" => "Is blank",
|
||||||
|
"IsNotBlank" => "Is not blank",
|
||||||
|
"Equals" => "Equals",
|
||||||
|
"NotEquals" => "Doesn't equal"
|
||||||
|
);
|
||||||
|
|
||||||
|
private static $db = array(
|
||||||
|
'ConditionOption' => 'Enum("IsBlank,IsNotBlank,Equals,NotEquals")',
|
||||||
|
'ConditionValue' => 'Varchar'
|
||||||
|
);
|
||||||
|
|
||||||
|
private static $has_one = array(
|
||||||
|
'Parent' => 'UserDefinedForm_EmailRecipient',
|
||||||
|
'ConditionField' => 'EditableFormField'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if this rule matches the given condition
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @param Form $form
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function matches($data, $form) {
|
||||||
|
$fieldName = $this->ConditionField()->Name;
|
||||||
|
$fieldValue = isset($data[$fieldName]) ? $data[$fieldName] : null;
|
||||||
|
switch($this->ConditionOption) {
|
||||||
|
case 'IsBlank':
|
||||||
|
return empty($fieldValue);
|
||||||
|
case 'IsNotBlank':
|
||||||
|
return !empty($fieldValue);
|
||||||
|
default:
|
||||||
|
$matches = is_array($fieldValue)
|
||||||
|
? in_array($this->ConditionValue, $fieldValue)
|
||||||
|
: $this->ConditionValue === (string)$fieldValue;
|
||||||
|
return ($this->ConditionOption === 'Equals') === (bool)$matches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
code/model/recipients/UserFormRecipientEmail.php
Normal file
30
code/model/recipients/UserFormRecipientEmail.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email that gets sent to the people listed in the Email Recipients when a
|
||||||
|
* submission is made.
|
||||||
|
*
|
||||||
|
* @package userforms
|
||||||
|
*/
|
||||||
|
|
||||||
|
class UserFormRecipientEmail extends Email {
|
||||||
|
|
||||||
|
protected $ss_template = "SubmittedFormEmail";
|
||||||
|
|
||||||
|
protected $data;
|
||||||
|
|
||||||
|
public function __construct($submittedFields = null) {
|
||||||
|
parent::__construct($submittedFields = null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the "Reply-To" header with an email address rather than append as
|
||||||
|
* {@link Email::replyTo} does.
|
||||||
|
*
|
||||||
|
* @param string $email The email address to set the "Reply-To" header to
|
||||||
|
*/
|
||||||
|
public function setReplyTo($email) {
|
||||||
|
$this->customHeaders['Reply-To'] = $email;
|
||||||
|
}
|
||||||
|
}
|
51
code/model/recipients/UserFormRecipientItemRequest.php
Normal file
51
code/model/recipients/UserFormRecipientItemRequest.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller that handles requests to EmailRecipient's
|
||||||
|
*
|
||||||
|
* @package userforms
|
||||||
|
*/
|
||||||
|
class UserFormRecipientItemRequest extends GridFieldDetailForm_ItemRequest {
|
||||||
|
|
||||||
|
private static $allowed_actions = array(
|
||||||
|
'edit',
|
||||||
|
'view',
|
||||||
|
'ItemEditForm',
|
||||||
|
'preview'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a preview of the recipient email.
|
||||||
|
*/
|
||||||
|
public function preview() {
|
||||||
|
return $this->customise(new ArrayData(array(
|
||||||
|
'Body' => $this->record->getEmailBodyContent(),
|
||||||
|
'HideFormData' => $this->record->HideFormData,
|
||||||
|
'Fields' => $this->getPreviewFieldData()
|
||||||
|
)))->renderWith($this->record->EmailTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get some placeholder field values to display in the preview
|
||||||
|
* @return ArrayList
|
||||||
|
*/
|
||||||
|
private function getPreviewFieldData() {
|
||||||
|
$data = new ArrayList();
|
||||||
|
|
||||||
|
$fields = $this->record->Form()->Fields()->filter(array(
|
||||||
|
'ClassName:not' => 'EditableLiteralField',
|
||||||
|
'ClassName:not' => 'EditableFormHeading'
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$data->push(new ArrayData(array(
|
||||||
|
'Name' => $field->Name,
|
||||||
|
'Title' => $field->Title,
|
||||||
|
'Value' => '$' . $field->Name,
|
||||||
|
'FormattedValue' => '$' . $field->Name
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,7 @@ class SubmittedFileField extends SubmittedFormField {
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getFormattedValue() {
|
public function getFormattedValue() {
|
||||||
$name = $this->getName();
|
$name = $this->getFileName();
|
||||||
$link = $this->getLink();
|
$link = $this->getLink();
|
||||||
$title = _t('SubmittedFileField.DOWNLOADFILE', 'Download File');
|
$title = _t('SubmittedFileField.DOWNLOADFILE', 'Download File');
|
||||||
|
|
||||||
@ -61,9 +61,9 @@ class SubmittedFileField extends SubmittedFormField {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() {
|
public function getFileName() {
|
||||||
if($this->UploadedFile()) {
|
if($this->UploadedFile()) {
|
||||||
return $this->UploadedFile()->Name;
|
return $this->UploadedFile()->Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
218
code/tasks/UserFormsUpgradeService.php
Normal file
218
code/tasks/UserFormsUpgradeService.php
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service to support upgrade of userforms module
|
||||||
|
*/
|
||||||
|
class UserFormsUpgradeService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $quiet;
|
||||||
|
|
||||||
|
public function run() {
|
||||||
|
$this->log("Upgrading formfield rules and custom settings");
|
||||||
|
|
||||||
|
// List of rules that have been created in all stages
|
||||||
|
$fields = Versioned::get_including_deleted('EditableFormField');
|
||||||
|
foreach($fields as $field) {
|
||||||
|
$this->upgradeField($field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate a versioned field in all stages
|
||||||
|
*
|
||||||
|
* @param EditableFormField $field
|
||||||
|
*/
|
||||||
|
protected function upgradeField(EditableFormField $field) {
|
||||||
|
$this->log("Upgrading formfield ID = ".$field->ID);
|
||||||
|
|
||||||
|
// Check versions this field exists on
|
||||||
|
$filter = sprintf('"EditableFormField"."ID" = \'%d\' AND "Migrated" = 0', $field->ID);
|
||||||
|
$stageField = Versioned::get_one_by_stage('EditableFormField', 'Stage', $filter);
|
||||||
|
$liveField = Versioned::get_one_by_stage('EditableFormField', 'Live', $filter);
|
||||||
|
|
||||||
|
if($stageField) {
|
||||||
|
$this->upgradeFieldInStage($stageField, 'Stage');
|
||||||
|
}
|
||||||
|
|
||||||
|
if($liveField) {
|
||||||
|
$this->upgradeFieldInStage($liveField, 'Live');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate a versioned field in a single stage
|
||||||
|
*
|
||||||
|
* @param EditableFormField $field
|
||||||
|
* @param stage $stage
|
||||||
|
*/
|
||||||
|
protected function upgradeFieldInStage(EditableFormField $field, $stage) {
|
||||||
|
Versioned::reading_stage($stage);
|
||||||
|
|
||||||
|
// Migrate field rules
|
||||||
|
$this->migrateRules($field, $stage);
|
||||||
|
|
||||||
|
// Migrate custom settings
|
||||||
|
$this->migrateCustomSettings($field, $stage);
|
||||||
|
|
||||||
|
// Flag as migrated
|
||||||
|
$field->Migrated = true;
|
||||||
|
$field->write();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate custom rules for the given field
|
||||||
|
*
|
||||||
|
* @param EditableFormField $field
|
||||||
|
* @param string $stage
|
||||||
|
*/
|
||||||
|
protected function migrateRules(EditableFormField $field, $stage) {
|
||||||
|
$rulesData = $field->CustomRules
|
||||||
|
? unserialize($field->CustomRules)
|
||||||
|
: array();
|
||||||
|
|
||||||
|
// Skip blank rules or fields with custom rules already
|
||||||
|
if(empty($rulesData) || $field->DisplayRules()->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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate custom settings for the given field
|
||||||
|
*
|
||||||
|
* @param EditableFormField $field
|
||||||
|
* @param string $stage
|
||||||
|
*/
|
||||||
|
protected function migrateCustomSettings(EditableFormField $field, $stage) {
|
||||||
|
// Custom settings include:
|
||||||
|
// - ExtraClass
|
||||||
|
// - RightTitle
|
||||||
|
// - ShowOnLoad (show or '' are treated as true)
|
||||||
|
//
|
||||||
|
// - CheckedDefault (new field on EditableCheckbox - should be read from old "default" value)
|
||||||
|
// - Default (EditableCheckbox)
|
||||||
|
// - DefaultToToday (EditableDateField)
|
||||||
|
// - Folder (EditableFileField)
|
||||||
|
// - Level (EditableFormHeading)
|
||||||
|
// - HideFromReports (EditableFormHeading / EditableLiteralField)
|
||||||
|
// - Content (EditableLiteralField)
|
||||||
|
// - GroupID (EditableMemberListField)
|
||||||
|
// - MinValue (EditableNumericField)
|
||||||
|
// - MaxValue (EditableNumericField)
|
||||||
|
// - MinLength (EditableTextField)
|
||||||
|
// - MaxLength (EditableTextField)
|
||||||
|
// - Rows (EditableTextField)
|
||||||
|
|
||||||
|
$customSettings = $field->CustomSettings
|
||||||
|
? unserialize($field->CustomSettings)
|
||||||
|
: array();
|
||||||
|
|
||||||
|
// Skip blank rules or fields with custom rules already
|
||||||
|
if(empty($customSettings)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$field->migrateSettings($customSettings);
|
||||||
|
$field->write();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function log($message) {
|
||||||
|
if($this->getQuiet()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(Director::is_cli()) {
|
||||||
|
echo "{$message}\n";
|
||||||
|
} else {
|
||||||
|
echo "{$message}<br />";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if this service should be quiet
|
||||||
|
*
|
||||||
|
* @param bool $quiet
|
||||||
|
* @return $ths
|
||||||
|
*/
|
||||||
|
public function setQuiet($quiet) {
|
||||||
|
$this->quiet = $quiet;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQuiet() {
|
||||||
|
return $this->quiet;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
22
code/tasks/UserFormsUpgradeTask.php
Normal file
22
code/tasks/UserFormsUpgradeTask.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?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");
|
||||||
|
Injector::inst()
|
||||||
|
->create('UserFormsUpgradeService')
|
||||||
|
->setQuiet(false)
|
||||||
|
->run();
|
||||||
|
$this->log("Done");
|
||||||
|
}
|
||||||
|
}
|
@ -1,245 +0,0 @@
|
|||||||
/**
|
|
||||||
* User Defined Form Builder CSS
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
li.class-UserDefinedForm > a .jstree-pageicon { background-position: 0 -64px; }
|
|
||||||
|
|
||||||
.page-icon.class-UserDefinedForm {
|
|
||||||
background-position: 0 -64px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a Field Menu
|
|
||||||
---------------------------------------- */
|
|
||||||
.MenuHolder {
|
|
||||||
color: #999;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
background: #f4f4f4;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.MenuHolder h2 {
|
|
||||||
float: left;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.MenuHolder select {
|
|
||||||
float: left;
|
|
||||||
width: 240px;
|
|
||||||
margin: 18px 0 0 8px;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.MenuHolder .action {
|
|
||||||
float: left;
|
|
||||||
margin: 14px 0 0 4px;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Options / Settings Area
|
|
||||||
---------------------------------------- */
|
|
||||||
.FormOptions {
|
|
||||||
padding: 10px 0 0 0;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
#ShowClearButton, #DisableSaveSubmissions{
|
|
||||||
padding-left:0;
|
|
||||||
}
|
|
||||||
#ShowClearButton label, #DisableSaveSubmissions label{
|
|
||||||
float:left;
|
|
||||||
font-weight:bold;
|
|
||||||
margin-right:43px;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Email Recipient Form
|
|
||||||
---------------------------------------- */
|
|
||||||
.EmailRecipientForm .fieldgroup .fieldgroup-field {
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.EmailRecipientForm .fieldgroup .fieldgroup-field.last {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.EmailRecipientForm .ss-ui-button {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Field Listing
|
|
||||||
---------------------------------------- */
|
|
||||||
.FieldEditor .FieldList {
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.FieldEditor .FieldList .EditableFormField {
|
|
||||||
margin: 2px;
|
|
||||||
padding: 3px 0;
|
|
||||||
border-top: 1px dotted #ccc;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField * {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.FieldEditor .FieldList .EditableFormField .fieldHandler,
|
|
||||||
.FieldEditor .FieldList .EditableFormField .handle {
|
|
||||||
cursor: move;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .fieldInfo {
|
|
||||||
float: left;
|
|
||||||
padding-right: 10px;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .fieldActions {
|
|
||||||
float: left;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .fieldActions a {
|
|
||||||
padding: 0 5px 5px 20px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .moreOptions {
|
|
||||||
background: url(../../cms/images/edit.gif) no-repeat top left;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .moreOptions.showing {
|
|
||||||
color: #666;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .delete {
|
|
||||||
background: url(../../cms/images/delete.gif) no-repeat top left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.FieldEditor .FieldList .EditableFormField input {
|
|
||||||
width: 250px;
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Field Options **/
|
|
||||||
|
|
||||||
.FieldEditor .FieldList .EditableFormField div.extraOptions {
|
|
||||||
display: block;
|
|
||||||
overflow:hidden;
|
|
||||||
margin: 3px 0px 3px 38px;
|
|
||||||
background-color: #F4F4F4;
|
|
||||||
padding: 3px;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .extraOptions .handle {
|
|
||||||
float: left;
|
|
||||||
margin-right: 3px;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .extraOptions ul {
|
|
||||||
padding: 5px 0;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .extraOptions li {
|
|
||||||
padding: 3px 0;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .extraOptions a {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .extraOptions input {
|
|
||||||
font-size: 11px;
|
|
||||||
padding: 2px;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .extraOptions .deleteOption {
|
|
||||||
width: 20px;
|
|
||||||
margin: 4px 0 0 4px;
|
|
||||||
background: none;
|
|
||||||
height: 20px;
|
|
||||||
float: left;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .extraOptions select {
|
|
||||||
width: 221px;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .extraOptions .chzn-drop input {
|
|
||||||
font-size: 12px;
|
|
||||||
padding: 4px 20px 4px 5px;
|
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField a.addableOption,
|
|
||||||
.FieldEditor .FieldList .EditableFormField a.addCondition {
|
|
||||||
background: url(../../cms/images/add.gif) no-repeat top left;
|
|
||||||
padding: 1px 0 2px 20px;
|
|
||||||
font-size: 12px;
|
|
||||||
width: auto;
|
|
||||||
margin-left: 3px;
|
|
||||||
}
|
|
||||||
/* Field Options Group */
|
|
||||||
.FieldEditor .FieldList .fieldOptionsGroup {
|
|
||||||
padding: 4px 8px 8px 8px;
|
|
||||||
margin: 5px;
|
|
||||||
border: 1px solid #bbb;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .fieldOptionsGroup legend {
|
|
||||||
font-size: 15px;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
/* Field Lengths */
|
|
||||||
.FieldEditor .FieldList .EditableFormField .fieldgroupField {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .fieldgroupField label {
|
|
||||||
float: left;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .fieldgroupField input {
|
|
||||||
width: 80px;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .EditableFormField .middleColumn {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
/* CHECKBOX */
|
|
||||||
.FieldEditor .FieldList .EditableFormField .checkbox { }
|
|
||||||
|
|
||||||
.FieldEditor .FieldList .EditableFormField .checkbox input {
|
|
||||||
float: left;
|
|
||||||
width:auto;
|
|
||||||
margin: 0 8px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CUSTOM RULES */
|
|
||||||
.FieldEditor .FieldList .customRules {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .customRules li {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .customRules li.firstField {
|
|
||||||
padding-bottom: 5px;
|
|
||||||
margin: 0 5px;
|
|
||||||
border-bottom: 1px solid #bbb;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .customRules label {
|
|
||||||
float: left;
|
|
||||||
margin: 0;
|
|
||||||
padding: 2px 4px;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .customRules select {
|
|
||||||
float: left;
|
|
||||||
font-size: 11px;
|
|
||||||
width: 120px;
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
.FieldEditor .FieldList .customRules a {
|
|
||||||
background: none;
|
|
||||||
width: 20px;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HIDE */
|
|
||||||
.FieldEditor .FieldList li.EditableFormField .hidden {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Holder to prevent form from collapsing */
|
|
||||||
.FieldEditor .FieldList .removed-form-field {
|
|
||||||
height: 40px;
|
|
||||||
display: block;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
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
|
## Adding fields
|
||||||
|
|
||||||
To add a field to the form, click on the "Form" tab under the "Content" tab in the
|
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
|
Editing Pane. Click the "Add" button then select the type of field you want from the dropdown.
|
||||||
press the "Add" button. You can label any field by typing in the appropriate label field in the backend.
|
Save or publish the form to start editing your new field's properties.
|
||||||
|
|
||||||
![Adding fields](_images/add-fields.png)
|
![Adding fields](_images/add-fields.png)
|
||||||
|
|
||||||
|
@ -8,19 +8,12 @@
|
|||||||
var recipient = {
|
var recipient = {
|
||||||
// Some fields are only visible when HTML email are being sent.
|
// Some fields are only visible when HTML email are being sent.
|
||||||
updateFormatSpecificFields: function () {
|
updateFormatSpecificFields: function () {
|
||||||
var sendPlainChecked = $('#SendPlain').find('input[type="checkbox"]').is(':checked');
|
var sendPlainChecked = $('#SendPlain')
|
||||||
|
.find('input[type="checkbox"]')
|
||||||
|
.is(':checked');
|
||||||
|
|
||||||
// Hide the preview link when 'SendPlain' is selected.
|
$(".field.toggle-html-only")[sendPlainChecked ? 'hide' : 'show']();
|
||||||
$('#EmailPreview')[sendPlainChecked ? 'hide' : 'show']();
|
$(".field.toggle-plain-only")[sendPlainChecked ? 'show' : 'hide']();
|
||||||
|
|
||||||
// Hide the template selector when 'SendPlain' is selected.
|
|
||||||
$('#EmailTemplate')[sendPlainChecked ? 'hide' : 'show']();
|
|
||||||
|
|
||||||
// Hide the HTML editor when 'SendPlain' is selected.
|
|
||||||
$('#EmailBodyHtml')[sendPlainChecked ? 'hide' : 'show']();
|
|
||||||
|
|
||||||
// Show the body teaxtarea when 'SendPlain' is selected.
|
|
||||||
$('#EmailBody')[sendPlainChecked ? 'show' : 'hide']();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,353 +0,0 @@
|
|||||||
/**
|
|
||||||
* Javascript required to power the user defined forms.
|
|
||||||
*
|
|
||||||
* Rewritten from the prototype FieldEditor and constantly
|
|
||||||
* being refactored to be be less specific on the UDF dom.
|
|
||||||
*/
|
|
||||||
(function($) {
|
|
||||||
$(document).ready(function() {
|
|
||||||
/**
|
|
||||||
* Namespace
|
|
||||||
*/
|
|
||||||
var userforms = userforms || {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Messages from UserForms are translatable using i18n.
|
|
||||||
*/
|
|
||||||
userforms.messages = {
|
|
||||||
CONFIRM_DELETE_ALL_SUBMISSIONS: 'All submissions will be permanently removed. Continue?',
|
|
||||||
ERROR_CREATING_FIELD: 'Error creating field',
|
|
||||||
ADDING_FIELD: 'Adding new field',
|
|
||||||
ADDED_FIELD: 'Added new field',
|
|
||||||
HIDE_OPTIONS: 'Hide options',
|
|
||||||
SHOW_OPTIONS: 'Show options',
|
|
||||||
ADDING_OPTION: 'Adding option',
|
|
||||||
ADDED_OPTION: 'Added option',
|
|
||||||
ERROR_CREATING_OPTION: 'Error creating option',
|
|
||||||
REMOVED_OPTION: 'Removed option',
|
|
||||||
ADDING_RULE: 'Adding rule'
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a given translatable string from a passed key. Keys
|
|
||||||
* should be all caps without any spaces.
|
|
||||||
*/
|
|
||||||
userforms.message = function() {
|
|
||||||
en = arguments[1] || userforms.messages[arguments[0]];
|
|
||||||
|
|
||||||
return ss.i18n._t("UserForms."+ arguments[0], en);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the sortable properties of the form as a function
|
|
||||||
* since the application will need to refresh the UI dynamically based
|
|
||||||
* on a number of factors including when the user adds a page or
|
|
||||||
* swaps between pages
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
userforms.update = function() {
|
|
||||||
$("#Fields_fields").sortable({
|
|
||||||
handle: '.fieldHandler',
|
|
||||||
cursor: 'pointer',
|
|
||||||
items: 'li.EditableFormField',
|
|
||||||
placeholder: 'removed-form-field',
|
|
||||||
opacity: 0.6,
|
|
||||||
revert: 'true',
|
|
||||||
change : function (event, ui) {
|
|
||||||
$("#Fields_fields").sortable('refreshPositions');
|
|
||||||
},
|
|
||||||
update : function (event, ui) {
|
|
||||||
var sort = 1;
|
|
||||||
|
|
||||||
$("li.EditableFormField").each(function() {
|
|
||||||
$(this).find(".sortHidden").val(sort++);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".editableOptions").sortable({
|
|
||||||
handle: '.handle',
|
|
||||||
cursor:'pointer',
|
|
||||||
items: 'li',
|
|
||||||
placeholder: 'removed-form-field',
|
|
||||||
opacity: 0.6,
|
|
||||||
revert: true,
|
|
||||||
change : function (event, ui) {
|
|
||||||
$(this).sortable('refreshPositions');
|
|
||||||
},
|
|
||||||
update : function (event, ui) {
|
|
||||||
var sort = 1;
|
|
||||||
$(".editableOptions li").each(function() {
|
|
||||||
$(this).find(".sortOptionHidden").val(sort++);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
userforms.appendToURL = function(url, pathsegmenttobeadded) {
|
|
||||||
var parts = url.match(/([^\?#]*)?(\?[^#]*)?(#.*)?/);
|
|
||||||
for(var i in parts) if(!parts[i]) parts[i] = '';
|
|
||||||
return parts[1] + pathsegmenttobeadded + parts[2] + parts[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Workaround for not refreshing the sort.
|
|
||||||
*
|
|
||||||
* TODO: better solution would to not fire this on every hover but needs to
|
|
||||||
* ensure it doesn't have edge cases. The sledge hammer approach.
|
|
||||||
*/
|
|
||||||
$(".fieldHandler, .handle").live('hover', function() {
|
|
||||||
userforms.update();
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Kick off the UserForms UI
|
|
||||||
*/
|
|
||||||
userforms.update();
|
|
||||||
|
|
||||||
|
|
||||||
$.entwine('udf', function($){
|
|
||||||
|
|
||||||
/*-------------------- FIELD EDITOR ----------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new instance of a field in the current form
|
|
||||||
* area. the type information should all be on this object
|
|
||||||
*/
|
|
||||||
$('div.FieldEditor .MenuHolder .action').entwine({
|
|
||||||
onclick: function(e) {
|
|
||||||
var theform = $("#Form_EditForm"); // edit from page
|
|
||||||
if ( theform.length < 1 ) theform = $("#Form_ItemEditForm"); // edit from modeladmin
|
|
||||||
var form = theform,
|
|
||||||
length = $(".FieldInfo").length + 1,
|
|
||||||
fieldType = $(this).siblings("select").val(),
|
|
||||||
formData = form.serialize()+'&NewID='+ length +"&Type="+ fieldType,
|
|
||||||
fieldEditor = $(this).closest('.FieldEditor');
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
if($("#Fields").hasClass('readonly') || !fieldType) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Due to some very weird behaviout of jquery.metadata, the url have to be double quoted
|
|
||||||
var addURL = fieldEditor.attr('data-add-url').substr(1, fieldEditor.attr('data-add-url').length-2);
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
headers: {"X-Pjax" : 'Partial'},
|
|
||||||
type: "POST",
|
|
||||||
url: addURL,
|
|
||||||
data: formData,
|
|
||||||
success: function(data) {
|
|
||||||
$('#Fields_fields').append(data);
|
|
||||||
|
|
||||||
statusMessage(userforms.message('ADDED_FIELD'));
|
|
||||||
|
|
||||||
var name = $("#Fields_fields li.EditableFormField:last").attr("id").split(' ');
|
|
||||||
|
|
||||||
$("#Fields_fields select.fieldOption").append("<option value='"+ name[2] +"'>New "+ name[2] + "</option>");
|
|
||||||
$("#Fields_fields").sortable('refresh');
|
|
||||||
},
|
|
||||||
error: function(e) {
|
|
||||||
alert(ss.i18n._t('GRIDFIELD.ERRORINTRANSACTION'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a field from the user defined form
|
|
||||||
*/
|
|
||||||
$(".EditableFormField .delete").entwine({
|
|
||||||
onclick: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
var text = $(this).parents("li").find(".fieldInfo .text").val();
|
|
||||||
|
|
||||||
// Remove all the rules with relate to this field
|
|
||||||
$("#Fields_fields .customRules select.fieldOption option").each(function(i, element) {
|
|
||||||
if($(element).text() === text) {
|
|
||||||
// check to see if this is selected. If it is then just remove the whole rule
|
|
||||||
if($(element).parent('select.customRuleField').val() === $(element).val()) {
|
|
||||||
$(element).parents('li.customRule').remove();
|
|
||||||
} else {
|
|
||||||
// otherwise remove the option
|
|
||||||
$(element).remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$(this).parents(".EditableFormField").slideUp(function(){$(this).remove()})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Upon renaming a field we should go through and rename all the
|
|
||||||
* fields in the select fields to use this new field title. We can
|
|
||||||
* just worry about the title text - don't mess around with the keys
|
|
||||||
*/
|
|
||||||
$('.EditableFormField .fieldInfo .text').entwine({
|
|
||||||
onchange: function(e) {
|
|
||||||
var value = $(this).val();
|
|
||||||
var name = $(this).parents("li").attr("id").split(' ');
|
|
||||||
$("#Fields_fields select.fieldOption option").each(function(i, domElement) {
|
|
||||||
if($(domElement).val() === name[2]) {
|
|
||||||
$(domElement).text(value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the more options popdown. Or hide it if we currently have it open
|
|
||||||
*/
|
|
||||||
$(".EditableFormField .moreOptions").entwine({
|
|
||||||
onclick: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
var parent = $(this).parents(".EditableFormField");
|
|
||||||
if(!parent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var extraOptions = parent.children(".extraOptions");
|
|
||||||
if(!extraOptions) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(extraOptions.hasClass('hidden')) {
|
|
||||||
$(this).addClass("showing");
|
|
||||||
$(this).html('Hide options');
|
|
||||||
extraOptions.removeClass('hidden');
|
|
||||||
} else {
|
|
||||||
$(this).removeClass("showing");
|
|
||||||
$(this).html('Show options');
|
|
||||||
extraOptions.addClass('hidden');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a suboption to a radio field or to a dropdown box for example
|
|
||||||
*/
|
|
||||||
$(".EditableFormField .addableOption").entwine({
|
|
||||||
onclick: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
// Give the user some feedback
|
|
||||||
statusMessage(userforms.message('ADDING_OPTION'));
|
|
||||||
|
|
||||||
// variables
|
|
||||||
var options = $(this).parent("li");
|
|
||||||
var action = userforms.appendToURL($("#Form_EditForm").attr("action"), '/field/Fields/addoptionfield');
|
|
||||||
var parent = $(this).attr("rel");
|
|
||||||
var securityID = ($("input[name=SecurityID]").length > 0) ? $("input[name=SecurityID]").first().attr("value") : '';
|
|
||||||
|
|
||||||
// send ajax request to the page
|
|
||||||
$.ajax({
|
|
||||||
type: "GET",
|
|
||||||
url: action,
|
|
||||||
data: 'Parent='+ parent +'&SecurityID='+securityID,
|
|
||||||
// create a new field
|
|
||||||
success: function(msg){
|
|
||||||
options.before(msg);
|
|
||||||
statusMessage(userforms.message('ADDED_OPTION'));
|
|
||||||
},
|
|
||||||
|
|
||||||
// error creating new field
|
|
||||||
error: function(request, text, error) {
|
|
||||||
statusMessage(userforms.message('ERROR_CREATING_OPTION'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a suboption such as an dropdown option or a
|
|
||||||
* checkbox field
|
|
||||||
*/
|
|
||||||
$(".EditableFormField .deleteOption").entwine({
|
|
||||||
onclick: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
// pass the deleted status onto the element
|
|
||||||
$(this).parents("li:first").find("[type=text]:first").attr("value", "field-node-deleted");
|
|
||||||
$(this).parents("li:first").hide();
|
|
||||||
|
|
||||||
// Give the user some feedback
|
|
||||||
statusMessage(userforms.message('REMOVED_OPTION'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom Rules Interface
|
|
||||||
*
|
|
||||||
* Hides the input text field if the conditionOption is 'IsBlank' or 'IsNotBlank'
|
|
||||||
*/
|
|
||||||
$("select.conditionOption").entwine({
|
|
||||||
onchange: function() {
|
|
||||||
var valueInput = $(this).siblings(".ruleValue");
|
|
||||||
if($(this).val() && $(this).val() !== "IsBlank" && $(this).val() !== "IsNotBlank") {
|
|
||||||
valueInput.removeClass("hidden");
|
|
||||||
} else {
|
|
||||||
valueInput.addClass("hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a custom rule
|
|
||||||
*/
|
|
||||||
$(".customRules .deleteCondition").entwine({
|
|
||||||
onclick: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
$(this).parent("li").fadeOut().remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adding a custom rule to a given form
|
|
||||||
*/
|
|
||||||
$(".customRules .addCondition").entwine({
|
|
||||||
onclick: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
// Give the user some feedback
|
|
||||||
statusMessage(userforms.message('ADDING_RULE'));
|
|
||||||
|
|
||||||
// get the fields li which to duplicate
|
|
||||||
var currentRules = $(this).parent("li").parent("ul");
|
|
||||||
var defaultRule = currentRules.children("li.hidden:first");
|
|
||||||
var newRule = defaultRule.clone();
|
|
||||||
|
|
||||||
newRule.children(".customRuleField").each(function(i, domElement) {
|
|
||||||
var currentName = domElement.name.split("][");
|
|
||||||
currentName[3] = currentName[2];
|
|
||||||
currentName[2] = currentRules.children().size() + 1;
|
|
||||||
domElement.name = currentName.join("][");
|
|
||||||
});
|
|
||||||
|
|
||||||
// remove hidden tag
|
|
||||||
newRule.removeClass("hidden");
|
|
||||||
|
|
||||||
// update the fields dropdown
|
|
||||||
var optionChildren = newRule.children("select.fieldOption");
|
|
||||||
optionChildren.empty();
|
|
||||||
|
|
||||||
$("#Fields_fields li.EditableFormField").each(function () {
|
|
||||||
var name = $(this).attr("id").split(' ');
|
|
||||||
var option = $("<option></option>")
|
|
||||||
.attr('value', name[2])
|
|
||||||
.text($(this).find(".text").val());
|
|
||||||
optionChildren
|
|
||||||
.append(option);
|
|
||||||
});
|
|
||||||
|
|
||||||
// append to the list
|
|
||||||
currentRules.append(newRule);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})(jQuery);
|
|
@ -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,11 +0,0 @@
|
|||||||
<li>
|
|
||||||
<img class="handle" src="$ModulePath(framework)/images/drag.gif" alt="<% _t('EditableOption.DRAG', 'Drag to rearrange order of options') %>" />
|
|
||||||
<input type="text" name="{$FieldName}[Title]" value="$Title" />
|
|
||||||
<input type="hidden" class="sortOptionHidden hidden" name="{$FieldName}[Sort]" value="$Sort" />
|
|
||||||
|
|
||||||
<% if canEdit %>
|
|
||||||
<a href="$ID" class="deleteOption"><img src="$ModulePath(framework)/images/delete.gif" alt="<% _t('EditableOption.DELETE', 'Remove this option') %>" /></a>
|
|
||||||
<% else %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('EditableOption.LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
</li>
|
|
@ -1,31 +0,0 @@
|
|||||||
<% require css(userforms/css/FieldEditor.css) %>
|
|
||||||
<% require javascript(userforms/javascript/UserForm.js) %>
|
|
||||||
|
|
||||||
<div class="FieldEditor <% if canEdit %><% else %>readonly<% end_if %>" id="Fields" $AttributesHTML>
|
|
||||||
|
|
||||||
<div class="FieldListHold">
|
|
||||||
<ul class="FieldList" id="Fields_fields">
|
|
||||||
<% loop Fields %>
|
|
||||||
$EditSegment
|
|
||||||
<% end_loop %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<% if canEdit %>
|
|
||||||
<div class="MenuHolder no-change-track">
|
|
||||||
<h2><% _t('FieldEditor.ADD', 'Add') %></h2>
|
|
||||||
|
|
||||||
<select name="AddUserFormField" id="AddUserFormField">
|
|
||||||
<option value=""><% _t('FieldEditor.SELECTAFIELD', 'Select a Field') %></option>
|
|
||||||
|
|
||||||
<% loop CreatableFields %>
|
|
||||||
<option value="$ClassName">$Title</option>
|
|
||||||
<% end_loop %>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<input type="hidden" name="SecurityID" value="$SecurityID" />
|
|
||||||
<input type="submit" class="action" value="<% _t('FieldEditor.ADD', 'Add') %>" />
|
|
||||||
</div>
|
|
||||||
<% end_if %>
|
|
||||||
|
|
||||||
</div>
|
|
@ -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>
|
|
@ -7,11 +7,6 @@
|
|||||||
class EditableFormFieldTest extends FunctionalTest {
|
class EditableFormFieldTest extends FunctionalTest {
|
||||||
|
|
||||||
static $fixture_file = 'userforms/tests/EditableFormFieldTest.yml';
|
static $fixture_file = 'userforms/tests/EditableFormFieldTest.yml';
|
||||||
|
|
||||||
protected $extraDataObjects = array(
|
|
||||||
'ExtendedEditableFormFieldTestOnly',
|
|
||||||
'EditableFormFieldExtensionTestOnly'
|
|
||||||
);
|
|
||||||
|
|
||||||
function testFormFieldPermissions() {
|
function testFormFieldPermissions() {
|
||||||
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
||||||
@ -41,100 +36,6 @@ class EditableFormFieldTest extends FunctionalTest {
|
|||||||
$this->assertFalse($text->canDelete());
|
$this->assertFalse($text->canDelete());
|
||||||
}
|
}
|
||||||
|
|
||||||
function testGettingAndSettingSettings() {
|
|
||||||
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
|
||||||
|
|
||||||
$this->logInWithPermission('ADMIN');
|
|
||||||
|
|
||||||
$this->assertEquals($text->getSettings(), array());
|
|
||||||
$text->setSetting('Test', 'Value');
|
|
||||||
$text->write();
|
|
||||||
|
|
||||||
$this->assertEquals($text->getSetting('Test'), 'Value');
|
|
||||||
$this->assertEquals($text->getSettings(), array('Test' => 'Value'));
|
|
||||||
|
|
||||||
$text->setSetting('Foo', 'Bar');
|
|
||||||
$text->write();
|
|
||||||
|
|
||||||
$this->assertEquals($text->getSetting('Foo'), 'Bar');
|
|
||||||
$this->assertEquals($text->getSettings(), array('Test' => 'Value', 'Foo' => 'Bar'));
|
|
||||||
|
|
||||||
// test overridding an existing setting
|
|
||||||
$text->setSetting('Foo', 'Baz');
|
|
||||||
$text->write();
|
|
||||||
|
|
||||||
$this->assertEquals($text->getSetting('Foo'), 'Baz');
|
|
||||||
$this->assertEquals($text->getSettings(), array('Test' => 'Value', 'Foo' => 'Baz'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function testShowOnLoad() {
|
|
||||||
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
|
||||||
|
|
||||||
$this->logInWithPermission('ADMIN');
|
|
||||||
$this->assertTrue($text->getShowOnLoad());
|
|
||||||
|
|
||||||
$text->setSetting('ShowOnLoad', 'Show');
|
|
||||||
$this->assertTrue($text->getShowOnLoad());
|
|
||||||
|
|
||||||
$text->setSetting('ShowOnLoad', 'Hide');
|
|
||||||
$this->assertFalse($text->getShowOnLoad());
|
|
||||||
|
|
||||||
$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() {
|
function testCustomRules() {
|
||||||
$this->logInWithPermission('ADMIN');
|
$this->logInWithPermission('ADMIN');
|
||||||
$form = $this->objFromFixture('UserDefinedForm', 'custom-rules-form');
|
$form = $this->objFromFixture('UserDefinedForm', 'custom-rules-form');
|
||||||
@ -142,58 +43,18 @@ class EditableFormFieldTest extends FunctionalTest {
|
|||||||
$checkbox = $form->Fields()->find('ClassName', 'EditableCheckbox');
|
$checkbox = $form->Fields()->find('ClassName', 'EditableCheckbox');
|
||||||
$field = $form->Fields()->find('ClassName', 'EditableTextField');
|
$field = $form->Fields()->find('ClassName', 'EditableTextField');
|
||||||
|
|
||||||
$rule = array(
|
$rules = $checkbox->DisplayRules();
|
||||||
'Display' => 'Hide',
|
|
||||||
'ConditionField' => $checkbox->Name,
|
|
||||||
'ConditionOption' => 'HasValue',
|
|
||||||
'Value' => 6
|
|
||||||
);
|
|
||||||
|
|
||||||
$data['CustomRules'] = array(
|
|
||||||
'Rule1' => $rule
|
|
||||||
);
|
|
||||||
|
|
||||||
$field->populateFromPostData($data);
|
|
||||||
|
|
||||||
$rules = $field->CustomRules();
|
|
||||||
|
|
||||||
// form has 2 fields - a checkbox and a text field
|
// form has 2 fields - a checkbox and a text field
|
||||||
// it has 1 rule - when ticked the checkbox hides the text field
|
// it has 1 rule - when ticked the checkbox hides the text field
|
||||||
$this->assertEquals($rules->Count(), 1);
|
$this->assertEquals($rules->Count(), 1);
|
||||||
|
|
||||||
// rules are ArrayDatas not dataobjects
|
|
||||||
// $this->assertDOSEquals(array($rule), $rules);
|
|
||||||
|
|
||||||
$checkboxRule = $rules->First();
|
$checkboxRule = $rules->First();
|
||||||
|
$checkboxRule->ConditionFieldID = $field->ID;
|
||||||
|
|
||||||
$this->assertEquals($checkboxRule->Display, 'Hide');
|
$this->assertEquals($checkboxRule->Display, 'Hide');
|
||||||
$this->assertEquals($checkboxRule->ConditionField, $checkbox->Name);
|
|
||||||
$this->assertEquals($checkboxRule->ConditionOption, 'HasValue');
|
$this->assertEquals($checkboxRule->ConditionOption, 'HasValue');
|
||||||
$this->assertEquals($checkboxRule->Value, '6');
|
$this->assertEquals($checkboxRule->FieldValue, '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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testEditableDropdownField() {
|
function testEditableDropdownField() {
|
||||||
@ -240,15 +101,6 @@ class EditableFormFieldTest extends FunctionalTest {
|
|||||||
$this->assertEquals($title->Value(), "Basic Text Field");
|
$this->assertEquals($title->Value(), "Basic Text Field");
|
||||||
}
|
}
|
||||||
|
|
||||||
function testGettingFieldAndSettingNames() {
|
|
||||||
$text = $this->objFromFixture('EditableTextField', 'basic-text');
|
|
||||||
|
|
||||||
$this->assertEquals($text->getFieldName(), "Fields[". $text->ID ."]");
|
|
||||||
$this->assertEquals($text->getFieldName('Setting'), "Fields[". $text->ID ."][Setting]");
|
|
||||||
|
|
||||||
$this->assertEquals($text->getSettingName('Foo'), "Fields[". $text->ID ."][CustomSettings][Foo]");
|
|
||||||
}
|
|
||||||
|
|
||||||
function testMultipleOptionDuplication() {
|
function testMultipleOptionDuplication() {
|
||||||
$dropdown = $this->objFromFixture('EditableDropdown','basic-dropdown');
|
$dropdown = $this->objFromFixture('EditableDropdown','basic-dropdown');
|
||||||
|
|
||||||
@ -262,70 +114,6 @@ class EditableFormFieldTest extends FunctionalTest {
|
|||||||
$this->assertEquals($orginal->Sort, $option->Sort);
|
$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 */
|
|
||||||
$field = $this->objFromFixture('ExtendedEditableFormFieldTestOnly', 'extended-field');
|
|
||||||
|
|
||||||
// Check db fields
|
|
||||||
$dbFields = $field->stat('db');
|
|
||||||
$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'));
|
|
||||||
$this->assertNotNull($validationField);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFileField() {
|
public function testFileField() {
|
||||||
$fileField = $this->objFromFixture('EditableFileField', 'file-field');
|
$fileField = $this->objFromFixture('EditableFileField', 'file-field');
|
||||||
@ -336,48 +124,3 @@ class EditableFormFieldTest extends FunctionalTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ExtendedEditableFormField
|
|
||||||
* A base EditableFormFieldClass that will be extended with {@link EditableFormFieldExtension}
|
|
||||||
* @mixin EditableFormFieldExtension
|
|
||||||
*/
|
|
||||||
class ExtendedEditableFormFieldTestOnly extends EditableFormField implements TestOnly
|
|
||||||
{
|
|
||||||
private static $extensions = array(
|
|
||||||
'EditableFormFieldExtensionTestOnly'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class EditableFormFieldExtension
|
|
||||||
* Used for testing extensions to EditableFormField and the extended Fields methods
|
|
||||||
* @property EditableFormField owner
|
|
||||||
*/
|
|
||||||
class EditableFormFieldExtensionTestOnly extends DataExtension implements TestOnly
|
|
||||||
{
|
|
||||||
private static $db = array(
|
|
||||||
'TestExtraField' => 'Varchar',
|
|
||||||
'TestValidationField' => 'Boolean'
|
|
||||||
);
|
|
||||||
|
|
||||||
public function updateFieldConfiguration(FieldList $fields)
|
|
||||||
{
|
|
||||||
$extraField = 'TestExtraField';
|
|
||||||
$fields->push(TextField::create(
|
|
||||||
$this->owner->getSettingName($extraField),
|
|
||||||
'Test extra field',
|
|
||||||
$this->owner->getSetting($extraField)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateFieldValidationOptions(FieldList $fields)
|
|
||||||
{
|
|
||||||
$extraField = 'TestValidationField';
|
|
||||||
$fields->push(CheckboxField::create(
|
|
||||||
$this->owner->getSettingName($extraField),
|
|
||||||
'Test validation field',
|
|
||||||
$this->owner->getSetting($extraField)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
|
EditableCustomRule:
|
||||||
|
rule-1:
|
||||||
|
Display: Hide
|
||||||
|
ConditionOption: HasValue
|
||||||
|
FieldValue: 6
|
||||||
|
|
||||||
EditableOption:
|
EditableOption:
|
||||||
option-1:
|
option-1:
|
||||||
Name: Option1
|
Name: Option1
|
||||||
Title: Option 1
|
Title: Option 1
|
||||||
|
|
||||||
option-2:
|
option-2:
|
||||||
Name: Option2
|
Name: Option2
|
||||||
Title: Option 2
|
Title: Option 2
|
||||||
@ -30,110 +36,104 @@ EditableOption:
|
|||||||
option-6:
|
option-6:
|
||||||
Name: Option6
|
Name: Option6
|
||||||
Title: Option 6
|
Title: Option 6
|
||||||
|
|
||||||
UserDefinedForm_EmailRecipient:
|
UserDefinedForm_EmailRecipient:
|
||||||
recipient-1:
|
recipient-1:
|
||||||
EmailAddress: test@example.com
|
EmailAddress: test@example.com
|
||||||
EmailSubject: Email Subject
|
EmailSubject: Email Subject
|
||||||
EmailFrom: no-reply@example.com
|
EmailFrom: no-reply@example.com
|
||||||
|
|
||||||
no-html:
|
no-html:
|
||||||
EmailAddress: nohtml@example.com
|
EmailAddress: nohtml@example.com
|
||||||
EmailSubject: Email Subject
|
EmailSubject: Email Subject
|
||||||
EmailFrom: no-reply@example.com
|
EmailFrom: no-reply@example.com
|
||||||
SendPlain: true
|
SendPlain: true
|
||||||
|
|
||||||
no-data:
|
no-data:
|
||||||
EmailAddress: nodata@example.com
|
EmailAddress: nodata@example.com
|
||||||
EmailSubject: Email Subject
|
EmailSubject: Email Subject
|
||||||
EmailFrom: no-reply@example.com
|
EmailFrom: no-reply@example.com
|
||||||
HideFormData: true
|
HideFormData: true
|
||||||
|
|
||||||
EditableTextField:
|
EditableTextField:
|
||||||
basic-text:
|
basic-text:
|
||||||
Name: basic-text-name
|
Name: basic-text-name
|
||||||
Title: Basic Text Field
|
Title: Basic Text Field
|
||||||
|
|
||||||
basic-text-2:
|
basic-text-2:
|
||||||
Name: basic-text-name
|
Name: basic-text-name
|
||||||
Title: Basic Text Field
|
Title: Basic Text Field
|
||||||
|
|
||||||
required-text:
|
required-text:
|
||||||
Name: required-text-field
|
Name: required-text-field
|
||||||
Title: Required Text Field
|
Title: Required Text Field
|
||||||
CustomErrorMessage: Custom Error Message
|
CustomErrorMessage: Custom Error Message
|
||||||
Required: true
|
Required: true
|
||||||
|
|
||||||
EditableDropdown:
|
EditableDropdown:
|
||||||
basic-dropdown:
|
basic-dropdown:
|
||||||
Name: basic-dropdown
|
Name: basic-dropdown
|
||||||
Title: Basic Dropdown Field
|
Title: Basic Dropdown Field
|
||||||
Options: =>EditableOption.option-1, =>EditableOption.option-2
|
Options: =>EditableOption.option-1, =>EditableOption.option-2
|
||||||
|
|
||||||
department-dropdown:
|
department-dropdown:
|
||||||
Name: department
|
Name: department
|
||||||
Title: Department
|
Title: Department
|
||||||
Options: =>EditableOption.department-1, =>EditableOption.department-2
|
Options: =>EditableOption.department-1, =>EditableOption.department-2
|
||||||
|
|
||||||
EditableCheckbox:
|
EditableCheckbox:
|
||||||
checkbox-1:
|
checkbox-1:
|
||||||
Name: checkbox-1
|
Name: checkbox-1
|
||||||
Title: Checkbox 1
|
Title: Checkbox 1
|
||||||
|
|
||||||
checkbox-2:
|
checkbox-2:
|
||||||
Name: checkbox-1
|
Name: checkbox-1
|
||||||
Title: Checkbox 1
|
Title: Checkbox 1
|
||||||
|
|
||||||
|
checkbox-with-rule:
|
||||||
|
Name: checkbox-with-rule
|
||||||
|
Title: Checkbox with rule
|
||||||
|
DisplayRules: =>EditableCustomRule.rule-1
|
||||||
|
|
||||||
EditableCheckboxGroupField:
|
EditableCheckboxGroupField:
|
||||||
checkbox-group:
|
checkbox-group:
|
||||||
Name: check-box-group
|
Name: check-box-group
|
||||||
Title: Check box group
|
Title: Check box group
|
||||||
Options: =>EditableOption.option-3, =>EditableOption.option-4
|
Options: =>EditableOption.option-3, =>EditableOption.option-4
|
||||||
|
|
||||||
EditableEmailField:
|
EditableEmailField:
|
||||||
email-field:
|
email-field:
|
||||||
Name: email-field
|
Name: email-field
|
||||||
Title: Email
|
Title: Email
|
||||||
|
|
||||||
|
|
||||||
EditableRadioField:
|
EditableRadioField:
|
||||||
radio-field:
|
radio-field:
|
||||||
Name: radio-option
|
Name: radio-option
|
||||||
Title: Radio Option
|
Title: Radio Option
|
||||||
Options: =>EditableOption.option-5, =>EditableOption.option-6
|
Options: =>EditableOption.option-5, =>EditableOption.option-6
|
||||||
|
|
||||||
|
|
||||||
EditableFileField:
|
EditableFileField:
|
||||||
file-field:
|
file-field:
|
||||||
Name: file-uploader
|
Name: file-uploader
|
||||||
Title: Set file
|
Title: Set file
|
||||||
|
|
||||||
ExtendedEditableFormFieldTestOnly:
|
|
||||||
extended-field:
|
|
||||||
Name: extended-field
|
|
||||||
Title: Extended Field
|
|
||||||
TestExtraField: Extra Field
|
|
||||||
TestValidationField: Extra Validation Field
|
|
||||||
|
|
||||||
UserDefinedForm:
|
UserDefinedForm:
|
||||||
basic-form-page:
|
basic-form-page:
|
||||||
Title: User Defined Form
|
Title: User Defined Form
|
||||||
Fields: =>EditableTextField.basic-text
|
Fields: =>EditableTextField.basic-text
|
||||||
EmailRecipients: =>UserDefinedForm_EmailRecipient.recipient-1, =>UserDefinedForm_EmailRecipient.no-html, =>UserDefinedForm_EmailRecipient.no-data
|
EmailRecipients: =>UserDefinedForm_EmailRecipient.recipient-1, =>UserDefinedForm_EmailRecipient.no-html, =>UserDefinedForm_EmailRecipient.no-data
|
||||||
|
|
||||||
form-with-reset-and-custom-action:
|
form-with-reset-and-custom-action:
|
||||||
Title: Form with Reset Action
|
Title: Form with Reset Action
|
||||||
SubmitButtonText: Custom Button
|
SubmitButtonText: Custom Button
|
||||||
ShowClearButton: true
|
ShowClearButton: true
|
||||||
|
|
||||||
validation-form:
|
validation-form:
|
||||||
Title: Validation Form
|
Title: Validation Form
|
||||||
Fields: =>EditableTextField.required-text
|
Fields: =>EditableTextField.required-text
|
||||||
|
|
||||||
custom-rules-form:
|
custom-rules-form:
|
||||||
Title: 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:
|
empty-form:
|
||||||
Title: 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
|
// load the form
|
||||||
$this->get($form->URLSegment);
|
$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
|
// should have a submitted form field now
|
||||||
$submitted = DataObject::get('SubmittedFormField', "\"Name\" = 'basic-text-name'");
|
$submitted = DataObject::get('SubmittedFormField', "\"Name\" = 'basic-text-name'");
|
||||||
@ -106,7 +106,7 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
|||||||
|
|
||||||
$controller = new UserDefinedFormControllerTest_Controller($form);
|
$controller = new UserDefinedFormControllerTest_Controller($form);
|
||||||
|
|
||||||
$fields = $controller->getFormFields();
|
$fields = $controller->Form()->getFormFields();
|
||||||
|
|
||||||
$this->assertEquals($fields->Count(), 1);
|
$this->assertEquals($fields->Count(), 1);
|
||||||
|
|
||||||
@ -116,26 +116,26 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
|||||||
|
|
||||||
UserDefinedForm::config()->required_identifier = "*";
|
UserDefinedForm::config()->required_identifier = "*";
|
||||||
|
|
||||||
$fields = $controller->getFormFields();
|
$fields = $controller->Form()->getFormFields();
|
||||||
|
|
||||||
$this->assertEquals($fields->First()->getCustomValidationMessage()->getValue(), 'Custom Error Message');
|
$this->assertEquals($fields->First()->getCustomValidationMessage()->getValue(), 'Custom Error Message');
|
||||||
$this->assertEquals($fields->First()->Title(), 'Required Text Field <span class=\'required-identifier\'>*</span>');
|
$this->assertEquals($fields->First()->Title(), 'Required Text Field <span class=\'required-identifier\'>*</span>');
|
||||||
|
|
||||||
// test custom right title
|
// test custom right title
|
||||||
$field = $form->Fields()->First();
|
$field = $form->Fields()->First();
|
||||||
$field->setSetting('RightTitle', 'Right Title');
|
$field->RightTitle = 'Right Title';
|
||||||
$field->write();
|
$field->write();
|
||||||
|
|
||||||
$controller = new UserDefinedFormControllerTest_Controller($form);
|
$controller = new UserDefinedFormControllerTest_Controller($form);
|
||||||
$fields = $controller->getFormFields();
|
$fields = $controller->Form()->getFormFields();
|
||||||
|
|
||||||
$this->assertEquals($fields->First()->RightTitle(), "Right Title");
|
$this->assertEquals($fields->First()->RightTitle(), "Right Title");
|
||||||
|
|
||||||
// test empty form
|
// test empty form
|
||||||
$emptyForm = $this->objFromFixture('UserDefinedForm', 'empty-form');
|
$emptyForm = $this->objFromFixture('UserDefinedForm', 'empty-form');
|
||||||
$controller = new UserDefinedFormControllerTest_Controller($emptyForm);
|
$controller = new UserDefinedFormControllerTest_Controller($emptyForm);
|
||||||
|
|
||||||
$this->assertFalse($controller->Form());
|
$this->assertFalse($controller->Form()->getFormFields()->exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
function testGetFormActions() {
|
function testGetFormActions() {
|
||||||
@ -143,7 +143,7 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
|||||||
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
|
$form = $this->objFromFixture('UserDefinedForm', 'basic-form-page');
|
||||||
|
|
||||||
$controller = new UserDefinedFormControllerTest_Controller($form);
|
$controller = new UserDefinedFormControllerTest_Controller($form);
|
||||||
$actions = $controller->getFormActions();
|
$actions = $controller->Form()->getFormActions();
|
||||||
|
|
||||||
// by default will have 1 submit button which links to process
|
// by default will have 1 submit button which links to process
|
||||||
$expected = new FieldList(new FormAction('process', 'Submit'));
|
$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
|
// the custom popup should have a reset button and a custom text
|
||||||
$custom = $this->objFromFixture('UserDefinedForm', 'form-with-reset-and-custom-action');
|
$custom = $this->objFromFixture('UserDefinedForm', 'form-with-reset-and-custom-action');
|
||||||
$controller = new UserDefinedFormControllerTest_Controller($custom);
|
$controller = new UserDefinedFormControllerTest_Controller($custom);
|
||||||
|
$actions = $controller->Form()->getFormActions();
|
||||||
$actions = $controller->getFormActions();
|
|
||||||
|
|
||||||
$expected = new FieldList(new FormAction('process', 'Custom Button'));
|
$expected = new FieldList(new FormAction('process', 'Custom Button'));
|
||||||
$expected->push(new ResetFormAction("clearForm", "Clear"));
|
$expected->push(new ResetFormAction("clearForm", "Clear"));
|
||||||
|
|
||||||
$this->assertEquals($actions, $expected);
|
$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() {
|
function testRenderingIntoFormTemplate() {
|
||||||
$form = $this->setupFormFrontend();
|
$form = $this->setupFormFrontend();
|
||||||
|
|
||||||
@ -210,7 +201,7 @@ class UserDefinedFormControllerTest extends FunctionalTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkTemplateIsCorrect($parser) {
|
function checkTemplateIsCorrect($parser) {
|
||||||
$this->assertArrayHasKey(0, $parser->getBySelector('form#Form_Form'));
|
$this->assertArrayHasKey(0, $parser->getBySelector('form#UserForm_Form'));
|
||||||
|
|
||||||
// check for the input
|
// check for the input
|
||||||
$this->assertArrayHasKey(0, $parser->getBySelector('input.text'));
|
$this->assertArrayHasKey(0, $parser->getBySelector('input.text'));
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
class UserDefinedFormTest extends FunctionalTest {
|
class UserDefinedFormTest extends FunctionalTest {
|
||||||
|
|
||||||
static $fixture_file = 'userforms/tests/UserDefinedFormTest.yml';
|
static $fixture_file = 'UserDefinedFormTest.yml';
|
||||||
|
|
||||||
|
|
||||||
function testRollbackToVersion() {
|
function testRollbackToVersion() {
|
||||||
|
@ -121,27 +121,22 @@ UserDefinedForm_EmailRecipientCondition:
|
|||||||
blank-rule:
|
blank-rule:
|
||||||
ConditionOption: IsBlank
|
ConditionOption: IsBlank
|
||||||
ConditionField: =>EditableTextField.your-name-field
|
ConditionField: =>EditableTextField.your-name-field
|
||||||
|
|
||||||
not-blank-rule:
|
not-blank-rule:
|
||||||
ConditionOption: IsNotBlank
|
ConditionOption: IsNotBlank
|
||||||
ConditionField: =>EditableTextField.address-field
|
ConditionField: =>EditableTextField.address-field
|
||||||
|
|
||||||
equals-rule:
|
equals-rule:
|
||||||
ConditionOption: Equals
|
ConditionOption: Equals
|
||||||
ConditionField: =>EditableTextField.street-field
|
ConditionField: =>EditableTextField.street-field
|
||||||
ConditionValue: 'Matches Equals'
|
ConditionValue: 'Matches Equals'
|
||||||
|
|
||||||
not-equals-rule:
|
not-equals-rule:
|
||||||
ConditionOption: NotEquals
|
ConditionOption: NotEquals
|
||||||
ConditionField: =>EditableTextField.city-field
|
ConditionField: =>EditableTextField.city-field
|
||||||
ConditionValue: 'Matches Not Equals'
|
ConditionValue: 'Matches Not Equals'
|
||||||
|
|
||||||
# filtered recipient 2
|
# filtered recipient 2
|
||||||
group-equals-rule:
|
group-equals-rule:
|
||||||
ConditionOption: Equals
|
ConditionOption: Equals
|
||||||
ConditionField: =>EditableCheckboxGroupField.colour-checkbox-group
|
ConditionField: =>EditableCheckboxGroupField.colour-checkbox-group
|
||||||
ConditionValue: Red
|
ConditionValue: Red
|
||||||
|
|
||||||
group-not-equals-rule:
|
group-not-equals-rule:
|
||||||
ConditionOption: NotEquals
|
ConditionOption: NotEquals
|
||||||
ConditionField: =>EditableCheckboxGroupField.colour-checkbox-group
|
ConditionField: =>EditableCheckboxGroupField.colour-checkbox-group
|
||||||
|
216
tests/UserFormsUpgradeServiceTest.php
Normal file
216
tests/UserFormsUpgradeServiceTest.php
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class UserFormsUpgradeServiceTest extends SapphireTest {
|
||||||
|
|
||||||
|
static $fixture_file = 'UserFormsUpgradeServiceTest.yml';
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
Config::inst()->update('UserDefinedForm', 'upgrade_on_build', false);
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// Assign rules programatically
|
||||||
|
$field1 = $this->objFromFixture('EditableTextField', 'text1');
|
||||||
|
$field2 = $this->objFromFixture('EditableTextField', 'text2');
|
||||||
|
$field3 = $this->objFromFixture('EditableTextField', 'text3');
|
||||||
|
|
||||||
|
$field3->CustomRules = serialize(array(
|
||||||
|
array(
|
||||||
|
'Display' => 'Show',
|
||||||
|
'ConditionField' => $field1->Name,
|
||||||
|
'ConditionOption' => 'IsBlank',
|
||||||
|
'Value' => ''
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Display' => 'Hide',
|
||||||
|
'ConditionField' => $field2->Name,
|
||||||
|
'ConditionOption' => 'HasValue',
|
||||||
|
'Value' => 'bob'
|
||||||
|
)
|
||||||
|
));
|
||||||
|
$field3->write();
|
||||||
|
|
||||||
|
// Assign settings programatically
|
||||||
|
$field4 = $this->objFromFixture('EditableTextField', 'text4');
|
||||||
|
$field4->CustomSettings = serialize(array(
|
||||||
|
'MinLength' => 20,
|
||||||
|
'MaxLength' => 100,
|
||||||
|
'Rows' => 4,
|
||||||
|
'ExtraClass' => 'special class',
|
||||||
|
'RightTitle' => 'My Field',
|
||||||
|
'ShowOnLoad' => '',
|
||||||
|
'Default' => 'Enter your text here'
|
||||||
|
));
|
||||||
|
$field4->write();
|
||||||
|
|
||||||
|
$numeric1 = $this->objFromFixture('EditableNumericField', 'numeric1');
|
||||||
|
$numeric1->CustomSettings = serialize(array(
|
||||||
|
'RightTitle' => 'Number of %',
|
||||||
|
'Default' => 1,
|
||||||
|
'MinValue' => 1,
|
||||||
|
'MaxValue' => 100,
|
||||||
|
'ShowOnLoad' => 'Show'
|
||||||
|
));
|
||||||
|
$numeric1->write();
|
||||||
|
|
||||||
|
$group1 = $this->objFromFixture('Group', 'group1');
|
||||||
|
$members1 = $this->objFromFixture('EditableMemberListField', 'members1');
|
||||||
|
$members1->CustomSettings = serialize(array(
|
||||||
|
'RightTitle' => 'Select group',
|
||||||
|
'GroupID' => $group1->ID,
|
||||||
|
'ShowOnLoad' => 'Hide'
|
||||||
|
));
|
||||||
|
$members1->write();
|
||||||
|
|
||||||
|
$literal1 = $this->objFromFixture('EditableLiteralField', 'literal1');
|
||||||
|
$literal1->CustomSettings = serialize(array(
|
||||||
|
'HideFromReports' => 1,
|
||||||
|
'RightTitle' => 'Literal',
|
||||||
|
'Content' => '<p>Content</p>',
|
||||||
|
'ShowOnLoad' => true
|
||||||
|
));
|
||||||
|
$literal1->write();
|
||||||
|
|
||||||
|
$heading1 = $this->objFromFixture('EditableFormHeading', 'heading1');
|
||||||
|
$heading1->CustomSettings = serialize(array(
|
||||||
|
'RightTitle' => 'Right',
|
||||||
|
'Level' => 3,
|
||||||
|
'HideFromReports' => true,
|
||||||
|
'ShowOnLoad' => false
|
||||||
|
));
|
||||||
|
$heading1->write();
|
||||||
|
|
||||||
|
$folder = $this->objFromFixture('Folder', 'folder1');
|
||||||
|
$file1 = $this->objFromFixture('EditableFileField', 'file1');
|
||||||
|
$file1->CustomSettings = serialize(array(
|
||||||
|
'RightTitle' => 'File field',
|
||||||
|
'Folder' => $folder->ID
|
||||||
|
));
|
||||||
|
$file1->write();
|
||||||
|
|
||||||
|
$date1 = $this->objFromFixture('EditableDateField', 'date1');
|
||||||
|
$date1->CustomSettings = serialize(array(
|
||||||
|
'RightTitle' => 'Date field',
|
||||||
|
'DefaultToToday' => '1'
|
||||||
|
));
|
||||||
|
$date1->write();
|
||||||
|
|
||||||
|
$checkbox1 = $this->objFromFixture('EditableCheckbox', 'checkbox1');
|
||||||
|
$checkbox1->CustomSettings = serialize(array(
|
||||||
|
'Default' => true,
|
||||||
|
'RightTitle' => 'Check this'
|
||||||
|
));
|
||||||
|
$checkbox1->write();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return UserFormsUpgradeService;
|
||||||
|
*/
|
||||||
|
protected function getService() {
|
||||||
|
return singleton('UserFormsUpgradeService');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests migration of custom rules
|
||||||
|
*/
|
||||||
|
public function testCustomRulesMigration() {
|
||||||
|
$service = $this->getService();
|
||||||
|
$service->setQuiet(true);
|
||||||
|
$service->run();
|
||||||
|
|
||||||
|
$field1 = $this->objFromFixture('EditableTextField', 'text1');
|
||||||
|
$field2 = $this->objFromFixture('EditableTextField', 'text2');
|
||||||
|
$field3 = $this->objFromFixture('EditableTextField', 'text3');
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array(
|
||||||
|
'Display' => 'Show',
|
||||||
|
'ConditionFieldID' => $field1->ID,
|
||||||
|
'ConditionOption' => 'IsBlank'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'Display' => 'Hide',
|
||||||
|
'ConditionFieldID' => $field2->ID,
|
||||||
|
'ConditionOption' => 'HasValue',
|
||||||
|
'FieldValue' => 'bob'
|
||||||
|
)
|
||||||
|
), $field3->DisplayRules());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests migration of all custom settings
|
||||||
|
*/
|
||||||
|
public function testCustomSettingsMigration() {
|
||||||
|
$service = $this->getService();
|
||||||
|
$service->setQuiet(true);
|
||||||
|
$service->run();
|
||||||
|
|
||||||
|
$group1 = $this->objFromFixture('Group', 'group1');
|
||||||
|
$form = $this->objFromFixture('UserDefinedForm', 'form-with-settings');
|
||||||
|
$folder = $this->objFromFixture('Folder', 'folder1');
|
||||||
|
|
||||||
|
$this->assertDOSEquals(array(
|
||||||
|
array(
|
||||||
|
'ClassName' => 'EditableTextField',
|
||||||
|
'Title' => 'Text with rule',
|
||||||
|
'MinLength' => 20,
|
||||||
|
'MaxLength' => 100,
|
||||||
|
'Rows' => 4,
|
||||||
|
'ExtraClass' => 'special class',
|
||||||
|
'RightTitle' => 'My Field',
|
||||||
|
'ShowOnLoad' => true,
|
||||||
|
'Default' => 'Enter your text here',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'ClassName' => 'EditableNumericField',
|
||||||
|
'Title' => 'Numeric 1',
|
||||||
|
'RightTitle' => 'Number of %',
|
||||||
|
'Default' => 1,
|
||||||
|
'MinValue' => 1,
|
||||||
|
'MaxValue' => 100,
|
||||||
|
'ShowOnLoad' => true,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'ClassName' => 'EditableMemberListField',
|
||||||
|
'Title' => 'Members 1',
|
||||||
|
'RightTitle' => 'Select group',
|
||||||
|
'GroupID' => $group1->ID,
|
||||||
|
'ShowOnLoad' => false,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'ClassName' => 'EditableLiteralField',
|
||||||
|
'Title' => 'Literal 1',
|
||||||
|
'HideFromReports' => true,
|
||||||
|
'RightTitle' => 'Literal',
|
||||||
|
'Content' => '<p>Content</p>',
|
||||||
|
'ShowOnLoad' => true,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'ClassName' => 'EditableFormHeading',
|
||||||
|
'Title' => 'Heading 1',
|
||||||
|
'RightTitle' => 'Right',
|
||||||
|
'Level' => 3,
|
||||||
|
'HideFromReports' => true,
|
||||||
|
'ShowOnLoad' => false,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'ClassName' => 'EditableFileField',
|
||||||
|
'Title' => 'File 1',
|
||||||
|
'RightTitle' => 'File field',
|
||||||
|
'FolderID' => $folder->ID,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'ClassName' => 'EditableDateField',
|
||||||
|
'Title' => 'Date 1',
|
||||||
|
'RightTitle' => 'Date field',
|
||||||
|
'DefaultToToday' => true,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'ClassName' => 'EditableCheckbox',
|
||||||
|
'Title' => 'Checkbox 1',
|
||||||
|
'CheckedDefault' => true,
|
||||||
|
'RightTitle' => 'Check this',
|
||||||
|
),
|
||||||
|
), $form->Fields());
|
||||||
|
}
|
||||||
|
}
|
57
tests/UserFormsUpgradeServiceTest.yml
Normal file
57
tests/UserFormsUpgradeServiceTest.yml
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
Group:
|
||||||
|
group1:
|
||||||
|
Title: 'Awesome Group'
|
||||||
|
|
||||||
|
Folder:
|
||||||
|
folder1:
|
||||||
|
Title: 'Folder 1'
|
||||||
|
|
||||||
|
EditableTextField:
|
||||||
|
text1:
|
||||||
|
Name: text1
|
||||||
|
Title: 'First field'
|
||||||
|
text2:
|
||||||
|
Name: text2
|
||||||
|
Title: 'Second field'
|
||||||
|
text3:
|
||||||
|
Name: text3
|
||||||
|
Title: 'Third field'
|
||||||
|
text4:
|
||||||
|
Name: textwithrule
|
||||||
|
Title: 'Text with rule'
|
||||||
|
EditableNumericField:
|
||||||
|
numeric1:
|
||||||
|
Name: numeric1
|
||||||
|
Title: 'Numeric 1'
|
||||||
|
EditableMemberListField:
|
||||||
|
members1:
|
||||||
|
Name: members1
|
||||||
|
Title: 'Members 1'
|
||||||
|
EditableLiteralField:
|
||||||
|
literal1:
|
||||||
|
Name: literal1
|
||||||
|
Title: 'Literal 1'
|
||||||
|
EditableFormHeading:
|
||||||
|
heading1:
|
||||||
|
Name: heading1
|
||||||
|
Title: 'Heading 1'
|
||||||
|
EditableFileField:
|
||||||
|
file1:
|
||||||
|
Name: file1
|
||||||
|
Title: 'File 1'
|
||||||
|
EditableDateField:
|
||||||
|
date1:
|
||||||
|
Name: date1
|
||||||
|
Title: 'Date 1'
|
||||||
|
EditableCheckbox:
|
||||||
|
checkbox1:
|
||||||
|
Name: checkbox1
|
||||||
|
Title: 'Checkbox 1'
|
||||||
|
|
||||||
|
UserDefinedForm:
|
||||||
|
form-with-rules:
|
||||||
|
Title: 'User Defined Form'
|
||||||
|
Fields: =>EditableTextField.text1,=>EditableTextField.text2,=>EditableTextField.text3
|
||||||
|
form-with-settings:
|
||||||
|
Title: 'Form with custom settings'
|
||||||
|
Fields: =>EditableTextField.text4,=>EditableNumericField.numeric1,=>EditableMemberListField.members1,=>EditableLiteralField.literal1,=>EditableFormHeading.heading1,=>EditableFileField.file1,=>EditableDateField.date1,=>EditableCheckbox.checkbox1
|
Loading…
Reference in New Issue
Block a user