2008-09-29 05:18:23 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Allows CMS user to create forms dynamically.
|
2009-04-15 06:23:43 +02:00
|
|
|
*
|
|
|
|
* @package userforms
|
2008-09-29 05:18:23 +02:00
|
|
|
*/
|
|
|
|
class FieldEditor extends FormField {
|
|
|
|
|
2009-05-22 01:31:46 +02:00
|
|
|
protected $hasFormOptions = true;
|
2009-05-14 23:40:03 +02:00
|
|
|
|
2008-09-29 05:18:23 +02:00
|
|
|
function FieldHolder() {
|
|
|
|
return $this->renderWith("FieldEditor");
|
|
|
|
}
|
|
|
|
|
2009-05-14 23:40:03 +02:00
|
|
|
/**
|
2009-06-08 06:42:17 +02:00
|
|
|
* Can a user edit this field?
|
|
|
|
* @return boolean
|
2009-05-14 23:40:03 +02:00
|
|
|
*/
|
|
|
|
public function canEdit() {
|
2009-06-08 06:42:17 +02:00
|
|
|
if($this->readonly) return false;
|
2009-05-14 23:40:03 +02:00
|
|
|
return $this->form->getRecord()->canEdit();
|
|
|
|
}
|
2009-05-28 10:31:10 +02:00
|
|
|
|
2009-06-08 06:42:17 +02:00
|
|
|
/**
|
|
|
|
* Can a user delete this field?
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public function canDelete() {
|
|
|
|
if($this->readonly) return false;
|
|
|
|
return $this->form->getRecord()->canDelete();
|
|
|
|
}
|
|
|
|
|
|
|
|
function performReadonlyTransformation() {
|
2009-06-08 08:17:15 +02:00
|
|
|
$clone = clone $this;
|
|
|
|
$clone->readonly = true;
|
|
|
|
$fields = $clone->Fields();
|
2009-06-08 06:42:17 +02:00
|
|
|
if($fields) foreach($fields as $field) {
|
|
|
|
$field->setReadonly();
|
|
|
|
}
|
|
|
|
|
2009-06-08 08:17:15 +02:00
|
|
|
return $clone->customise(array('Fields' => $fields));
|
2009-06-08 06:42:17 +02:00
|
|
|
}
|
|
|
|
|
2009-05-28 10:31:10 +02:00
|
|
|
/**
|
|
|
|
* Return the Form Fields for the user forms
|
|
|
|
*
|
|
|
|
* @return DataObjectSet
|
|
|
|
*/
|
2008-09-29 05:18:23 +02:00
|
|
|
function Fields() {
|
2009-04-17 04:26:40 +02:00
|
|
|
Requirements::css("userforms/css/FieldEditor.css");
|
2009-04-18 04:49:46 +02:00
|
|
|
Requirements::javascript("jsparty/jquery/ui/ui.core.js");
|
|
|
|
Requirements::javascript("jsparty/jquery/ui/ui.sortable.js");
|
2009-04-17 04:26:40 +02:00
|
|
|
Requirements::javascript("userforms/javascript/UserForm.js");
|
2009-06-08 08:17:15 +02:00
|
|
|
|
|
|
|
// Don't return any fields unless we actually have the dependent parameters set on the form field
|
|
|
|
if($this->form && $this->form->getRecord() && $this->name) {
|
|
|
|
$relationName = $this->name;
|
|
|
|
$fields = $this->form->getRecord()->$relationName();
|
2008-09-29 05:18:23 +02:00
|
|
|
|
2009-06-08 08:17:15 +02:00
|
|
|
if($fields) {
|
|
|
|
foreach($fields as $field) {
|
|
|
|
if(!$this->canEdit()) {
|
|
|
|
if(is_a($field, 'FormField')) {
|
|
|
|
$fields->remove($field);
|
|
|
|
$fields->push($field->performReadonlyTransformation());
|
|
|
|
}
|
2009-06-08 06:42:17 +02:00
|
|
|
}
|
2009-06-08 08:17:15 +02:00
|
|
|
$field->setEditor($this);
|
2009-05-14 23:40:03 +02:00
|
|
|
}
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
2009-06-08 08:17:15 +02:00
|
|
|
return $fields;
|
|
|
|
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
2009-06-08 06:42:17 +02:00
|
|
|
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
|
|
|
|
2009-03-25 03:06:28 +01:00
|
|
|
/**
|
|
|
|
* Return a DataObjectSet of all the addable fields to populate
|
|
|
|
* the add field menu
|
|
|
|
*
|
|
|
|
* @return DataObjectSet
|
|
|
|
*/
|
|
|
|
function CreatableFields() {
|
|
|
|
$fields = ClassInfo::subclassesFor('EditableFormField');
|
|
|
|
|
|
|
|
if($fields) {
|
|
|
|
array_shift($fields); // get rid of subclass 0
|
2009-05-06 05:34:40 +02:00
|
|
|
asort($fields); // get in order
|
2009-03-25 03:06:28 +01:00
|
|
|
$output = new DataObjectSet();
|
|
|
|
foreach($fields as $field => $title) {
|
|
|
|
// get the nice title and strip out field
|
2009-05-06 05:34:40 +02:00
|
|
|
$niceTitle = trim(eval("return $title::\$singular_name;"));
|
2009-04-27 02:20:20 +02:00
|
|
|
if($niceTitle) {
|
2009-04-21 07:10:39 +02:00
|
|
|
$output->push(new ArrayData(array(
|
2009-04-25 03:14:32 +02:00
|
|
|
'ClassName' => $field,
|
2009-04-21 07:10:39 +02:00
|
|
|
'Title' => "$niceTitle"
|
|
|
|
)));
|
|
|
|
}
|
2009-03-25 03:06:28 +01:00
|
|
|
}
|
|
|
|
return $output;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2009-04-27 02:20:20 +02:00
|
|
|
|
2009-04-17 04:26:40 +02:00
|
|
|
/**
|
|
|
|
* Handles saving the page. Needs to keep an eye on fields
|
|
|
|
* and options which have been removed / added
|
|
|
|
*
|
|
|
|
* @param DataObject Record to Save it In
|
|
|
|
*/
|
2008-09-29 05:18:23 +02:00
|
|
|
function saveInto(DataObject $record) {
|
|
|
|
$name = $this->name;
|
|
|
|
$fieldSet = $record->$name();
|
|
|
|
|
2009-04-15 00:59:46 +02:00
|
|
|
// @todo shouldn't we deal with customFormActions on that object?
|
2009-05-28 10:31:10 +02:00
|
|
|
$record->EmailOnSubmit = isset($_REQUEST[$name]['EmailOnSubmit']) ? "1" : "0";
|
2009-04-19 09:34:30 +02:00
|
|
|
$record->SubmitButtonText = isset($_REQUEST[$name]['SubmitButtonText']) ? $_REQUEST[$name]['SubmitButtonText'] : "";
|
2009-04-15 00:59:46 +02:00
|
|
|
$record->ShowClearButton = isset($_REQUEST[$name]['ShowClearButton']) ? "1" : "0";
|
2008-09-29 05:18:23 +02:00
|
|
|
|
|
|
|
// store the field IDs and delete the missing fields
|
|
|
|
// alternatively, we could delete all the fields and re add them
|
|
|
|
$missingFields = array();
|
2009-04-17 04:26:40 +02:00
|
|
|
|
2009-05-12 03:48:04 +02:00
|
|
|
foreach($fieldSet as $existingField) {
|
|
|
|
$missingFields[$existingField->ID] = $existingField;
|
|
|
|
}
|
2009-04-17 04:26:40 +02:00
|
|
|
|
2009-05-28 10:45:25 +02:00
|
|
|
if(isset($_REQUEST[$name]) && is_array($_REQUEST[$name])) {
|
2009-05-28 10:31:10 +02:00
|
|
|
foreach($_REQUEST[$name] as $newEditableID => $newEditableData) {
|
2009-05-12 03:48:04 +02:00
|
|
|
if(!is_numeric($newEditableID)) continue;
|
|
|
|
|
2009-05-28 10:31:10 +02:00
|
|
|
// get it from the db
|
|
|
|
$editable = DataObject::get_by_id('EditableFormField', $newEditableID);
|
2009-05-22 01:31:46 +02:00
|
|
|
|
2009-05-28 10:31:10 +02:00
|
|
|
// 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)) {
|
2009-04-17 04:26:40 +02:00
|
|
|
unset($missingFields[$editable->ID]);
|
|
|
|
}
|
2009-05-28 10:31:10 +02:00
|
|
|
|
|
|
|
// set form id
|
2009-04-17 04:26:40 +02:00
|
|
|
if($editable->ParentID == 0) {
|
|
|
|
$editable->ParentID = $record->ID;
|
|
|
|
}
|
2009-05-28 10:31:10 +02:00
|
|
|
|
|
|
|
// save data
|
2009-04-17 04:26:40 +02:00
|
|
|
$editable->populateFromPostData($newEditableData);
|
|
|
|
}
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
|
|
|
}
|
2009-04-17 04:26:40 +02:00
|
|
|
|
2008-09-29 05:18:23 +02:00
|
|
|
// remove the fields not saved
|
2009-05-28 10:40:23 +02:00
|
|
|
if($this->canEdit()) {
|
|
|
|
foreach($missingFields as $removedField) {
|
|
|
|
if(is_numeric($removedField->ID)) {
|
|
|
|
// check we can edit this
|
2009-05-28 10:31:10 +02:00
|
|
|
$removedField->delete();
|
|
|
|
}
|
|
|
|
}
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
2009-04-17 04:26:40 +02:00
|
|
|
|
2008-09-29 05:18:23 +02:00
|
|
|
if($record->hasMethod('customFormSave')) {
|
2009-05-22 01:31:46 +02:00
|
|
|
$record->customFormSave($_REQUEST[$name], $record);
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
|
|
|
|
2009-05-22 01:31:46 +02:00
|
|
|
if($record->hasMethod('processNewFormFields')) {
|
2008-09-29 05:18:23 +02:00
|
|
|
$record->processNewFormFields();
|
|
|
|
}
|
|
|
|
}
|
2009-04-17 04:26:40 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a field to the field editor. Called via a ajax get request
|
|
|
|
* from the userdefinedform javascript
|
|
|
|
*
|
|
|
|
* @return bool|html
|
|
|
|
*/
|
|
|
|
public function addfield() {
|
2008-09-29 05:18:23 +02:00
|
|
|
// get the last field in this form editor
|
|
|
|
$parentID = $this->form->getRecord()->ID;
|
|
|
|
|
2009-04-17 04:26:40 +02:00
|
|
|
if($parentID) {
|
|
|
|
$parentID = Convert::raw2sql($parentID); // who knows what could happen
|
2009-05-12 03:48:04 +02:00
|
|
|
|
|
|
|
if(defined('Database::USE_ANSI_SQL')) {
|
|
|
|
$highestSort = DB::query("SELECT MAX(\"Sort\") FROM \"EditableFormField\" WHERE \"ParentID\" = '$parentID'");
|
|
|
|
} else {
|
|
|
|
$highestSort = DB::query("SELECT MAX(Sort) FROM EditableFormField WHERE ParentID = '$parentID'");
|
|
|
|
}
|
|
|
|
|
2009-04-17 04:26:40 +02:00
|
|
|
$sort = $highestSort->value() + 1;
|
|
|
|
|
2009-04-25 03:14:32 +02:00
|
|
|
$className = (isset($_REQUEST['Type'])) ? $_REQUEST['Type'] : '';
|
2009-06-08 06:53:42 +02:00
|
|
|
if(!$className) user_error('Please select a field type to created', E_USER_WARNING);
|
2009-04-25 03:14:32 +02:00
|
|
|
|
2009-04-17 04:26:40 +02:00
|
|
|
if(is_subclass_of($className, "EditableFormField")) {
|
2009-04-20 01:52:44 +02:00
|
|
|
$field = new $className();
|
|
|
|
$field->write();
|
|
|
|
$field->ParentID = $this->form->getRecord()->ID;
|
2009-04-20 03:02:26 +02:00
|
|
|
$field->Name = $field->class . $field->ID;
|
2009-04-20 01:52:44 +02:00
|
|
|
$field->Sort = $sort;
|
|
|
|
$field->write();
|
|
|
|
return $field->EditSegment();
|
2009-04-17 04:26:40 +02:00
|
|
|
}
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
2009-04-17 04:26:40 +02:00
|
|
|
return false;
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
|
|
|
|
2009-04-17 04:26:40 +02:00
|
|
|
/**
|
|
|
|
* Return the html for a field option such as a
|
|
|
|
* dropdown field or a radio check box field
|
|
|
|
*
|
|
|
|
* @return bool|html
|
|
|
|
*/
|
|
|
|
public function addoptionfield() {
|
|
|
|
// passed via the ajax
|
|
|
|
$parent = (isset($_REQUEST['Parent'])) ? $_REQUEST['Parent'] : false;
|
2009-05-06 05:34:40 +02:00
|
|
|
|
2009-04-17 04:26:40 +02:00
|
|
|
// work out the sort by getting the sort of the last field in the form +1
|
|
|
|
if($parent) {
|
|
|
|
$sql_parent = Convert::raw2sql($parent);
|
2009-05-12 03:48:04 +02:00
|
|
|
|
|
|
|
if(defined('Database::USE_ANSI_SQL')) {
|
|
|
|
$highestSort = DB::query("SELECT MAX(\"Sort\") FROM \"EditableOption\" WHERE \"ParentID\" = '$sql_parent'");
|
|
|
|
} else {
|
|
|
|
$highestSort = DB::query("SELECT MAX(Sort) FROM EditableOption WHERE ParentID = '$sql_parent'");
|
|
|
|
}
|
|
|
|
|
2009-04-17 04:26:40 +02:00
|
|
|
$sort = $highestSort->value() + 1;
|
|
|
|
|
|
|
|
if($parent) {
|
|
|
|
$object = new EditableOption();
|
|
|
|
$object->write();
|
|
|
|
$object->ParentID = $parent;
|
|
|
|
$object->Sort = $sort;
|
|
|
|
$object->Name = 'option' . $object->ID;
|
|
|
|
$object->write();
|
|
|
|
return $object->EditSegment();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
2009-04-24 00:52:08 +02:00
|
|
|
|
2009-05-22 01:31:46 +02:00
|
|
|
function setHasFormOptions($bool){
|
|
|
|
$this->hasFormOptions = $bool;
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
|
|
|
|
2009-05-22 01:31:46 +02:00
|
|
|
function hasFormOptions(){
|
|
|
|
return $this->hasFormOptions;
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function FormOptions() {
|
2009-05-22 01:31:46 +02:00
|
|
|
if($this->hasFormOptions()){
|
2009-04-14 04:06:18 +02:00
|
|
|
if($this->form->getRecord()->hasMethod('customFormActions')) {
|
|
|
|
$newFields = $this->form->getRecord()->customFormActions($this->readonly);
|
2009-05-22 01:31:46 +02:00
|
|
|
|
|
|
|
foreach($newFields as $newField) {
|
|
|
|
$newField->setName("{$this->name}[{$newField->Name()}]" );
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
2009-04-14 04:06:18 +02:00
|
|
|
if($this->readonly) {
|
|
|
|
$newFields = $newFields->makeReadonly();
|
|
|
|
}
|
|
|
|
return $newFields;
|
2008-09-29 05:18:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
?>
|