mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 17:05:42 +02:00
FEATURE: added ability to have rules on userdefined form fields
This commit is contained in:
parent
4b1a806444
commit
d592ed005f
@ -281,11 +281,13 @@ class UserDefinedForm_Controller extends Page_Controller {
|
||||
$fields = new FieldSet();
|
||||
$fieldValidation = array();
|
||||
$fieldValidationRules = array();
|
||||
|
||||
$CustomDisplayRules = "";
|
||||
$defaults = "";
|
||||
$this->SubmitButtonText = ($this->SubmitButtonText) ? $this->SubmitButtonText : _t('UserDefinedForm.SUBMITBUTTON', 'Submit');
|
||||
|
||||
if($this->Fields()) {
|
||||
foreach($this->Fields() as $field) {
|
||||
|
||||
$fieldToAdd = $field->getFormField();
|
||||
$fieldValidationOptions = array();
|
||||
|
||||
@ -310,9 +312,58 @@ class UserDefinedForm_Controller extends Page_Controller {
|
||||
if($fieldValidationOptions) {
|
||||
$fieldValidationRules[$field->Name] = $fieldValidationOptions;
|
||||
}
|
||||
|
||||
// Is this Field Show by Default
|
||||
if(!$field->ShowOnLoad) {
|
||||
$defaults .= "$(\"#" . $field->Name . "\").hide();\n";
|
||||
}
|
||||
|
||||
// Check for field dependencies / default
|
||||
if($field->Dependencies()) {
|
||||
|
||||
foreach($field->Dependencies() as $dependency) {
|
||||
if(is_array($dependency) && isset($dependency['ConditionField']) && $dependency['ConditionField'] != "") {
|
||||
// get the field which is effected
|
||||
$formName = Convert::raw2sql($dependency['ConditionField']);
|
||||
$formFieldWatch = DataObject::get_one("EditableFormField", "Name = '$formName'");
|
||||
if(!$formFieldWatch) break;
|
||||
|
||||
$fieldToWatch = "$(\"#Form_Form_".$dependency['ConditionField']."\")";
|
||||
|
||||
// show or hide?
|
||||
$view = (isset($dependency['Display']) && $dependency['Display'] == "Show") ? "show" : "hide";
|
||||
$opposite = ($view == "show") ? "hide" : "show";
|
||||
|
||||
$Action = ($formFieldWatch->ClassName == "EditableTextField") ? "keyup" : "change";
|
||||
|
||||
switch($dependency['ConditionOption']) {
|
||||
case 'IsNotBlank':
|
||||
$matches = '!= ""';
|
||||
break;
|
||||
case 'IsBlank':
|
||||
$matches = '== ""';
|
||||
break;
|
||||
case 'HasValue':
|
||||
$matches = '== "'. $dependency['Value'] .'"';
|
||||
break;
|
||||
default:
|
||||
$matches = '!= "'. $dependency['Value'] .'"';
|
||||
break;
|
||||
}
|
||||
// put it all together
|
||||
$CustomDisplayRules .= $fieldToWatch.".$Action(function() {
|
||||
if($(this).val() ". $matches ." ) {
|
||||
$(\"#". $field->Name ."\").".$view."();
|
||||
}
|
||||
else {
|
||||
$(\"#". $field->Name ."\").".$opposite."();
|
||||
}
|
||||
});";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
|
||||
|
||||
// Keep track of the referer
|
||||
@ -332,14 +383,17 @@ class UserDefinedForm_Controller extends Page_Controller {
|
||||
$form->loadDataFrom($this->failover);
|
||||
|
||||
$FormName = $form->FormName();
|
||||
|
||||
|
||||
// Set the Form Name
|
||||
$rules = $this->array2json($fieldValidationRules);
|
||||
$messages = $this->array2json($fieldValidation);
|
||||
|
||||
|
||||
// set the custom script for this form
|
||||
Requirements::customScript(<<<JS
|
||||
(function($) {
|
||||
$(document).ready(function() {
|
||||
$defaults
|
||||
$("#$FormName").validate({
|
||||
errorClass: "required",
|
||||
messages:
|
||||
@ -349,6 +403,7 @@ class UserDefinedForm_Controller extends Page_Controller {
|
||||
rules:
|
||||
$rules
|
||||
});
|
||||
$CustomDisplayRules
|
||||
});
|
||||
})(jQuery);
|
||||
JS
|
||||
@ -372,7 +427,7 @@ JS
|
||||
$value = (is_bool($value)) ? $value : "\"$value\"";
|
||||
$result[] = "$key:$value \n";
|
||||
}
|
||||
return (isset($result)) ? "{\n".implode( ', ', $result ) ."} \n": '';
|
||||
return (isset($result)) ? "{\n".implode( ', ', $result ) ."} \n": '{}';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,8 +17,9 @@ class EditableFormField extends DataObject {
|
||||
"Required" => "Boolean",
|
||||
"CanDelete" => "Boolean",
|
||||
"CustomParameter" => "Varchar",
|
||||
"OptionallyDisplay" => "Boolean",
|
||||
"CustomErrorMessage" => "Varchar(255)"
|
||||
"CustomErrorMessage" => "Varchar(255)",
|
||||
"CustomRules" => "Text",
|
||||
"ShowOnLoad" => "Boolean",
|
||||
);
|
||||
|
||||
static $defaults = array(
|
||||
@ -99,6 +100,56 @@ class EditableFormField extends DataObject {
|
||||
public function showExtraOptions() {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Return the Custom Validation fields for this
|
||||
* field for the CMS
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function Dependencies() {
|
||||
return ($this->CustomRules) ? unserialize($this->CustomRules) : array();
|
||||
}
|
||||
/**
|
||||
* Return the custom validation fields for the field
|
||||
*
|
||||
* @return DataObjectSet
|
||||
*/
|
||||
public function CustomRules() {
|
||||
$output = new DataObjectSet();
|
||||
$fields = $this->Parent()->Fields();
|
||||
|
||||
// add the default add
|
||||
$output->push(new ArrayData(array(
|
||||
'Name' => $this->Name(),
|
||||
'AddableOption' => true,
|
||||
'Fields' => $fields
|
||||
)));
|
||||
|
||||
// check for existing ones
|
||||
if($this->CustomRules) {
|
||||
$rules = unserialize($this->CustomRules);
|
||||
if($rules) {
|
||||
foreach($rules as $rule => $data) {
|
||||
// recreate all the field object to prevent caching
|
||||
$outputFields = new DataObjectSet();
|
||||
foreach($fields as $field) {
|
||||
$new = clone $field;
|
||||
$new->isSelected = ($new->Name == $data['ConditionField']) ? true : false;
|
||||
$outputFields->push($new);
|
||||
}
|
||||
$output->push(new ArrayData(array(
|
||||
'Name' => $this->Name(),
|
||||
'Display' => $data['Display'],
|
||||
'Fields' => $outputFields,
|
||||
'ConditionField' => $data['ConditionField'],
|
||||
'ConditionOption' => $data['ConditionOption'],
|
||||
'Value' => $data['Value']
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
function makeReadonly() {
|
||||
$this->readonly = true;
|
||||
@ -117,10 +168,23 @@ class EditableFormField extends DataObject {
|
||||
return "<input type=\"text\" class=\"text\" title=\"("._t('EditableFormField.ENTERQUESTION', 'Enter Question').")\" value=\"$titleAttr\" name=\"Fields[{$this->ID}][Title]\"$readOnlyAttr />";
|
||||
}
|
||||
|
||||
function Name() {
|
||||
/**
|
||||
* Return the base name for this form field in the
|
||||
* form builder
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function Name() {
|
||||
return "Fields[".$this->ID."]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Fix this - shouldn't name be returning name?!?
|
||||
*/
|
||||
public function BaseName() {
|
||||
return $this->Name;
|
||||
}
|
||||
|
||||
/**
|
||||
* How to save the data submitted in this field into
|
||||
* the database object which this field represents.
|
||||
@ -140,6 +204,28 @@ class EditableFormField extends DataObject {
|
||||
$this->CanDelete = (isset($data['CanDelete']) && !$data['CanDelete']) ? 0 : 1;
|
||||
$this->Name = $this->class.$this->ID;
|
||||
$this->CustomErrorMessage = (isset($data['CustomErrorMessage'])) ? $data['CustomErrorMessage'] : "";
|
||||
$this->CustomRules = "";
|
||||
$this->ShowOnLoad = (isset($data['ShowOnLoad']) && $data['ShowOnLoad'] == "Show") ? 1 : 0;
|
||||
|
||||
// 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->write();
|
||||
}
|
||||
|
||||
@ -148,6 +234,7 @@ class EditableFormField extends DataObject {
|
||||
$baseName = "Fields[$this->ID]";
|
||||
$extraOptions = new FieldSet();
|
||||
|
||||
// Is this field required
|
||||
if(!$this->Parent()->hasMethod('hideExtraOption')){
|
||||
$extraOptions->push(new CheckboxField($baseName . "[Required]", _t('EditableFormField.REQUIRED', 'Required?'), $this->Required));
|
||||
}
|
||||
@ -167,12 +254,9 @@ class EditableFormField extends DataObject {
|
||||
$extraOptions = $extraOptions->makeReadonly();
|
||||
}
|
||||
|
||||
// support for optionally display field
|
||||
// $extraOptions->push(new CheckboxField($baseName ."[OptionallyDisplay]", _t('EditableFormField.OPTIONALLYDISPLAY', 'Optionally Display Field'), $this->OptionallyDisplay));
|
||||
|
||||
// support for custom error messaging
|
||||
// custom error messaging
|
||||
$extraOptions->push(new TextField($baseName.'[CustomErrorMessage]', _t('EditableFormField.CUSTOMERROR','Custom Error Message'), $this->CustomErrorMessage));
|
||||
|
||||
|
||||
return $extraOptions;
|
||||
}
|
||||
|
||||
@ -201,12 +285,7 @@ class EditableFormField extends DataObject {
|
||||
* @todo: escape the string
|
||||
*/
|
||||
function filterClause( $value ) {
|
||||
// Not filtering on this field
|
||||
|
||||
if( $value == '-1' )
|
||||
return "";
|
||||
else
|
||||
return "`{$this->name}` = '$value'";
|
||||
return ($value == '-1') ? "" : "`{$this->name}` = '$value'";
|
||||
}
|
||||
|
||||
function showInReports() {
|
||||
|
@ -202,7 +202,7 @@ class FieldEditor extends FormField {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function setHaveFormOptions($bool){
|
||||
$this->haveFormOptions = $bool;
|
||||
}
|
||||
|
@ -113,6 +113,9 @@
|
||||
padding: 3px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
#Fields_fields .EditableFormField .extraOptions a {
|
||||
background: none;
|
||||
}
|
||||
#Fields_fields .EditableFormField .extraOptions input {
|
||||
font-size: 11px;
|
||||
padding: 2px;
|
||||
@ -137,7 +140,37 @@
|
||||
margin: 0 8px 0 0;
|
||||
}
|
||||
|
||||
|
||||
/* CUSTOM RULES */
|
||||
#Fields_fields .customRules {
|
||||
clear: both;
|
||||
}
|
||||
#Fields_fields .customRules li {
|
||||
clear: both;
|
||||
}
|
||||
#Fields_fields .customRules li.firstField {
|
||||
padding-bottom: 5px;
|
||||
margin: 0 5px;
|
||||
border-bottom: 1px solid #bbb;
|
||||
}
|
||||
#Fields_fields .customRules label {
|
||||
float: left;
|
||||
margin: 0;
|
||||
padding: 2px 4px;
|
||||
font-size: 11px;
|
||||
}
|
||||
#Fields_fields .customRules select {
|
||||
float: left;
|
||||
font-size: 11px;
|
||||
width: 120px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
#Fields_fields .customRules a {
|
||||
background: none;
|
||||
width: 20px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* HIDE */
|
||||
#Fields_fields li.EditableFormField .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
@ -55,6 +55,13 @@
|
||||
success: function(msg){
|
||||
$('#Fields_fields').append(msg);
|
||||
statusMessage(ss.i18n._t('UserForms.ADDEDNEWFIELD', 'Added New Field'));
|
||||
|
||||
//update the internal lists
|
||||
var name = $("#Fields_fields li.EditableFormField:last").attr("id").split(' ');
|
||||
|
||||
//$("#Fields_fields select.fieldOption").each(function(i, domElement) {
|
||||
// $(domElement).append("<option='"+ name[2] +"'>New "+ name[2] + "</option>");
|
||||
//});
|
||||
},
|
||||
|
||||
// error creating new field
|
||||
@ -62,8 +69,22 @@
|
||||
statusMessage(ss.i18n._t('UserForms.ERRORCREATINGFIELD', 'Error Creating Field'));
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* 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').livequery('change', function() {
|
||||
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
|
||||
@ -93,6 +114,21 @@
|
||||
* Delete a field from the user defined form
|
||||
*/
|
||||
$(".EditableFormField .delete").livequery('click', function() {
|
||||
// remove all the rules with relate to this field
|
||||
var text = $(this).parents("li").find(".fieldInfo .text").val();
|
||||
$("#Fields_fields .customRules select.fieldOption option").each(function(i, domElement) {
|
||||
if($(domElement).text() == text) {
|
||||
|
||||
// check to see if this is selected. If it is then just remove the whole rule
|
||||
if($(domElement).parent('select.customRuleField').val() == $(domElement).val()) {
|
||||
$(domElement).parents('li.customRule').remove();
|
||||
}
|
||||
// otherwise remove the option
|
||||
else {
|
||||
$(domElement).remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
$(this).parents(".EditableFormField").remove();
|
||||
return false;
|
||||
});
|
||||
@ -198,6 +234,57 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Custom Rules Interface
|
||||
*/
|
||||
$(".customRules .conditionOption").livequery('change', function(){
|
||||
var valueInput = $(this).siblings(".ruleValue");
|
||||
if($(this).val() == "ValueNot" || $(this).val() == "HasValue") {
|
||||
valueInput.show();
|
||||
}
|
||||
else {
|
||||
valueInput.hide();
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Delete a custom rule
|
||||
*/
|
||||
$(".customRules .deleteCondition").livequery('click', function() {
|
||||
$(this).parent("li").fadeOut().remove();
|
||||
});
|
||||
/**
|
||||
* Adding a custom rule to a given form
|
||||
*/
|
||||
$(".customRules .addCondition").livequery('click', function() {
|
||||
|
||||
// Give the user some feedback
|
||||
statusMessage(ss.i18n._t('UserForms.ADDINGNEWRULE', 'Adding New Rule'));
|
||||
// get the parent li which to duplicate
|
||||
var parent = $(this).parent("li");
|
||||
var grandParent = parent.parent("ul");
|
||||
var newCondition = parent.clone();
|
||||
|
||||
// remove add icon
|
||||
newCondition.find(".addCondition").hide();
|
||||
newCondition.find("a.hidden").removeClass("hidden");
|
||||
|
||||
newCondition.children(".customRuleField").each(function(i, domElement) {
|
||||
// go through and fix names. We need to insert an id number into the middle of them at least
|
||||
$(domElement).val($(parent).find("select").eq(i).val());
|
||||
var currentName = domElement.name.split("][");
|
||||
currentName[3] = currentName[2];
|
||||
currentName[2] = grandParent.children().size() + 1;
|
||||
domElement.name = currentName.join("][");
|
||||
});
|
||||
grandParent.append(newCondition);
|
||||
|
||||
// clear fields
|
||||
parent.each(function(i, domElement) {
|
||||
$(domElement).find(".customRuleField").val("");
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
})
|
||||
(jQuery);
|
@ -1,4 +1,5 @@
|
||||
<li class="$ClassName EditableFormField" id="$Name.Attr EditableItem_$Pos">
|
||||
<!-- JS Relys on EditableFormField as a class - and the 3 ids in this order - do not change -->
|
||||
<li class="$ClassName EditableFormField" id="$Name.Attr EditableItem_$Pos $BaseName">
|
||||
<div class="fieldInfo">
|
||||
<% if isReadonly %>
|
||||
<img class="fieldHandler" src="sapphire/images/drag_readonly.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
||||
@ -43,10 +44,27 @@
|
||||
<% end_if %>
|
||||
<% end_if %>
|
||||
</ul>
|
||||
|
||||
|
||||
<% control ExtraOptions %>
|
||||
$FieldHolder
|
||||
<% end_control %>
|
||||
|
||||
<div class="customRules">
|
||||
<h4>Custom Rules</h4>
|
||||
<select name="$Name.Attr[ShowOnLoad]">
|
||||
<option value="Show" <% if ShowOnLoad %>selected="selected"<% end_if %>><% _t('SHOW', 'Show') %></option>
|
||||
<option value="Hide" <% if ShowOnLoad %><% else %>selected="selected"<% end_if %>><% _t('HIDE', 'Hide') %></option>
|
||||
</select>
|
||||
<label class="left">Field On Default</label>
|
||||
|
||||
<ul id="$Name.Attr-customRules">
|
||||
<% control CustomRules %>
|
||||
<li class="customRule">
|
||||
<% include CustomRule %>
|
||||
</li>
|
||||
<% end_control %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
|
26
templates/Includes/CustomRule.ss
Normal file
26
templates/Includes/CustomRule.ss
Normal file
@ -0,0 +1,26 @@
|
||||
<select class="displayOption customRuleField" name="{$Name}[CustomRules]<% if First %><% else %><% if Pos %>[$Pos]<% end_if %><% end_if %>[Display]">
|
||||
<option value="Show" <% if Display = Show %>selected="selected"<% end_if %>><% _t('SHOWTHISFIELD', 'Show This Field') %></option>
|
||||
<option value="Hide" <% if Display = Hide %><% if First %><% else %>selected="selected"<% end_if %><% end_if %>><% _t('HIDETHISFIELD', 'Hide This Field') %></option>
|
||||
</select>
|
||||
|
||||
<label><% _t('WHEN', 'When') %></label>
|
||||
<select class="fieldOption customRuleField" name="{$Name}[CustomRules]<% if First %><% else %><% if Pos %>[$Pos]<% end_if %><% end_if %>[ConditionField]">
|
||||
<option value="" selected="selected"></option>
|
||||
<% control Fields %>
|
||||
<option value="$BaseName" <% if isSelected %>selected="selected"<% end_if %>>$Title</option>
|
||||
<% end_control %>
|
||||
</select>
|
||||
|
||||
<label><% _t('IS', 'Is') %></label>
|
||||
<select class="conditionOption customRuleField" name="{$Name}[CustomRules]<% if First %><% else %><% if Pos %>[$Pos]<% end_if %><% end_if %>[ConditionOption]">
|
||||
<option value=""></option>
|
||||
<option value="IsBlank" <% if ConditionOption = IsBlank %>selected="selected"<% end_if %>><% _t('BLANK', 'Blank') %></option>
|
||||
<option value="IsNotBlank" <% if ConditionOption = IsNotBlank %>selected="selected"<% end_if %>><% _t('NOTBLANK', 'Not Blank') %></option>
|
||||
<option value="HasValue" <% if ConditionOption = HasValue %>selected="selected"<% end_if %>><% _t('VALUE', 'Value') %></option>
|
||||
<option value="ValueNot" <% if ConditionOption = ValueNot %>selected="selected"<% end_if %>><% _t('NOTVALUE', 'Not Value') %></option>
|
||||
</select>
|
||||
|
||||
<input type="text" class="ruleValue <% if Value %><% else %>hidden<% end_if %> customRuleField" name="{$Name}[CustomRules]<% if First %><% else %><% if Pos %>[$Pos]<% end_if %><% end_if %>[Value]" value="$Value" />
|
||||
|
||||
<a href="#" class="addCondition <% if First %><% else %>hidden<% end_if %>" title="<% _t('ADD', 'Add') %>"><img src="cms/images/add.gif" alt="<% _t('ADD', 'Add') %>" /></a>
|
||||
<a href="#" class="deleteCondition <% if First %>hidden<% end_if %>" title="<% _t('DELETE', 'Delete') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete') %>" /></a>
|
Loading…
Reference in New Issue
Block a user