ENHANCEMENT: rewrote the user defined forms cms JS into jquery. ENHANCEMENT: rewrote templates and removed dulicate code. APICHANGE: created parent class for EditableFormField, EditableOption and EditableMultiOption to prevent code duplication. MINOR: added icon for literal field. MINOR: added quick unit test. MINOR: removed dulicate images
@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* EditableButton
|
* EditableButton
|
||||||
* Allows a user to modify the text on the button
|
* Allows a user to modify the text on a button html element
|
||||||
* @package forms
|
*
|
||||||
* @subpackage fieldeditor
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableButton extends FormField {
|
class EditableButton extends FormField {
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
/**
|
/**
|
||||||
* EditableCheckbox
|
* EditableCheckbox
|
||||||
* A user modifiable checkbox on a UserDefinedForm
|
* A user modifiable checkbox on a UserDefinedForm
|
||||||
* @package forms
|
*
|
||||||
* @subpackage fieldeditor
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableCheckbox extends EditableFormField {
|
class EditableCheckbox extends EditableFormField {
|
||||||
|
|
||||||
|
@ -1,90 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* EditableDropdown
|
* EditableCheckboxGroup
|
||||||
|
*
|
||||||
* Represents a set of selectable radio buttons
|
* Represents a set of selectable radio buttons
|
||||||
* @package forms
|
*
|
||||||
* @subpackage fieldeditor
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableCheckboxGroupField extends EditableFormField {
|
class EditableCheckboxGroupField extends EditableMultipleOptionField {
|
||||||
|
|
||||||
protected $readonly;
|
|
||||||
|
|
||||||
function ReadonlyOption() {
|
|
||||||
$this->readonly = true;
|
|
||||||
return $this->Option();
|
|
||||||
}
|
|
||||||
|
|
||||||
function isReadonly() {
|
|
||||||
return $this->readonly;
|
|
||||||
}
|
|
||||||
|
|
||||||
static $has_many = array(
|
|
||||||
"Options" => "EditableCheckboxOption"
|
|
||||||
);
|
|
||||||
|
|
||||||
static $singular_name = "Checkbox group";
|
static $singular_name = "Checkbox group";
|
||||||
|
|
||||||
static $plural_name = "Checkbox groups";
|
static $plural_name = "Checkbox groups";
|
||||||
|
|
||||||
function duplicate() {
|
|
||||||
$clonedNode = parent::duplicate();
|
|
||||||
|
|
||||||
foreach( $this->Options() as $field ) {
|
|
||||||
$newField = $field->duplicate();
|
|
||||||
$newField->ParentID = $clonedNode->ID;
|
|
||||||
$newField->write();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $clonedNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
function delete() {
|
|
||||||
$options = $this->Options();
|
|
||||||
|
|
||||||
foreach( $options as $option )
|
|
||||||
$option->delete();
|
|
||||||
|
|
||||||
parent::delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
function EditSegment() {
|
|
||||||
return $this->renderWith( $this->class );
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateFromPostData( $data ) {
|
|
||||||
parent::populateFromPostData( $data );
|
|
||||||
|
|
||||||
$fieldSet = $this->Options();
|
|
||||||
|
|
||||||
$deletedOptions = explode( ',', $data['Deleted'] );
|
|
||||||
$optionNumber = 0;
|
|
||||||
|
|
||||||
// store default, etc
|
|
||||||
foreach($fieldSet as $option) {
|
|
||||||
if($deletedOptions && array_search($option->ID, $deletedOptions) !== false) {
|
|
||||||
$option->delete();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($data[$option->ID])) {
|
|
||||||
$option->populateFromPostData( $data[$option->ID] );
|
|
||||||
}
|
|
||||||
|
|
||||||
unset( $data[$option->ID] );
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($data as $tempID => $optionData) {
|
|
||||||
if(!$tempID || !is_array($optionData) || empty($optionData) || !preg_match('/^_?\d+$/', $tempID)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// what will we name the new option?
|
|
||||||
$newOption = new EditableCheckboxOption();
|
|
||||||
$newOption->Name = 'option' . (string)$optionNumber++;
|
|
||||||
$newOption->ParentID = $this->ID;
|
|
||||||
$newOption->populateFromPostData($optionData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function DefaultOption() {
|
function DefaultOption() {
|
||||||
$defaultOption = 0;
|
$defaultOption = 0;
|
||||||
|
|
||||||
@ -98,14 +25,6 @@ class EditableCheckboxGroupField extends EditableFormField {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFormField() {
|
|
||||||
return $this->createField();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFilterField() {
|
|
||||||
return $this->createField( true );
|
|
||||||
}
|
|
||||||
|
|
||||||
function createField($asFilter = false) {
|
function createField($asFilter = false) {
|
||||||
$optionSet = $this->Options();
|
$optionSet = $this->Options();
|
||||||
$options = array();
|
$options = array();
|
||||||
@ -127,7 +46,7 @@ class EditableCheckboxGroupField extends EditableFormField {
|
|||||||
$entries = array($data[$this->Name]);
|
$entries = array($data[$this->Name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$selectedOptions = DataObject::get('EditableCheckboxOption', "ParentID={$this->ID} AND ID IN (" . implode(',', $entries) . ")");
|
$selectedOptions = DataObject::get('EditableOption', "ParentID={$this->ID} AND ID IN (" . implode(',', $entries) . ")");
|
||||||
foreach($selectedOptions as $selected) {
|
foreach($selectedOptions as $selected) {
|
||||||
if(!$result) {
|
if(!$result) {
|
||||||
$result = $selected->Title;
|
$result = $selected->Title;
|
||||||
@ -138,11 +57,6 @@ class EditableCheckboxGroupField extends EditableFormField {
|
|||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TemplateOption() {
|
|
||||||
$option = new EditableCheckboxOption();
|
|
||||||
return $option->EditSegment();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
@ -1,82 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* EditableDropdownOption
|
|
||||||
* Represents a single entry in an EditableRadioField
|
|
||||||
* @package forms
|
|
||||||
* @subpackage fieldeditor
|
|
||||||
*/
|
|
||||||
class EditableCheckboxOption extends DataObject {
|
|
||||||
static $default_sort = "Sort";
|
|
||||||
|
|
||||||
// add required here?
|
|
||||||
static $db = array(
|
|
||||||
"Name" => "Varchar",
|
|
||||||
"Title" => "Varchar",
|
|
||||||
"Default" => "Boolean",
|
|
||||||
"Sort" => "Int"
|
|
||||||
);
|
|
||||||
static $has_one = array(
|
|
||||||
"Parent" => "EditableCheckboxGroupField",
|
|
||||||
);
|
|
||||||
|
|
||||||
static $singular_name = "Checkbox option";
|
|
||||||
static $plural_name = "Checkbox options";
|
|
||||||
|
|
||||||
function EditSegment() {
|
|
||||||
return $this->renderWith('EditableFormFieldOption');
|
|
||||||
}
|
|
||||||
|
|
||||||
function TitleField() {
|
|
||||||
return new TextField( "Fields[{$this->ParentID}][{$this->ID}][Title]", null, $this->Title );
|
|
||||||
}
|
|
||||||
|
|
||||||
function Name() {
|
|
||||||
return "Fields[{$this->ParentID}][{$this->ID}]";
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateFromPostData($data) {
|
|
||||||
$this->Title = $data['Title'];
|
|
||||||
if(isset($data['Default'])) {
|
|
||||||
$this->setField('Default', $data['Default']);
|
|
||||||
}
|
|
||||||
$this->Sort = $data['Sort'];
|
|
||||||
$this->write();
|
|
||||||
}
|
|
||||||
|
|
||||||
function Option() {
|
|
||||||
// return new radio field
|
|
||||||
/*$title = Convert::raw2att( $this->Title );
|
|
||||||
|
|
||||||
$default = "";
|
|
||||||
|
|
||||||
if( $this->getField('Default') )
|
|
||||||
$default = '+';
|
|
||||||
else
|
|
||||||
$default = '-';
|
|
||||||
|
|
||||||
//Debug::show($this);
|
|
||||||
return '<input type="text" name="Fields['.$this->ParentID.']['.$this->ID.'][Title]" value="'.$default.$title.'" />';*/
|
|
||||||
|
|
||||||
return $this->EditSegment();
|
|
||||||
}
|
|
||||||
|
|
||||||
function ReadonlyOption() {
|
|
||||||
$this->readonly = true;
|
|
||||||
return $this->EditSegment();
|
|
||||||
}
|
|
||||||
|
|
||||||
function DefaultSelect() {
|
|
||||||
if( $this->readonly )
|
|
||||||
$disabled = " disabled=\"disabled\"";
|
|
||||||
else
|
|
||||||
$disabled = '';
|
|
||||||
|
|
||||||
if( $this->getField('Default') )
|
|
||||||
$default = " checked=\"checked\"";
|
|
||||||
else
|
|
||||||
$default = '';
|
|
||||||
|
|
||||||
return "<input class=\"checkbox\" type=\"checkbox\" name=\"Fields[{$this->ParentID}][{$this->ID}][Default]\" value=\"1\"".$disabled.$default." />";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
@ -1,9 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* EditableDateField
|
* EditableDateField
|
||||||
|
*
|
||||||
* Allows a user to add a date field to the Field Editor
|
* Allows a user to add a date field to the Field Editor
|
||||||
* @package forms
|
*
|
||||||
* @subpackage fieldeditor
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableDateField extends EditableFormField {
|
class EditableDateField extends EditableFormField {
|
||||||
static $singular_name = 'Date field';
|
static $singular_name = 'Date field';
|
||||||
@ -19,19 +20,6 @@ class EditableDateField extends EditableFormField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function populateFromPostData($data) {
|
function populateFromPostData($data) {
|
||||||
/*if( !empty( $data['Default'] ) && !preg_match( '/^\d{4}-\d{2}-\d{2}$/', $data['Default'] ) ) {
|
|
||||||
if( empty( $data['Year'] ) || !is_numeric( $data['Year'] ) ) $data['Year'] = '2001';
|
|
||||||
if( empty( $data['Month'] ) || !is_numeric( $data['Month'] ) ) $data['Month'] = '01';
|
|
||||||
if( empty( $data['Day'] ) || !is_numeric( $data['Day'] ) ) $data['Day'] = '01';
|
|
||||||
|
|
||||||
// unset( $data['Default'] );
|
|
||||||
$data['Default'] = $data['Year'] . '-' . $data['Month'] . '-' . $data['Day'];
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*echo "ERROR:";
|
|
||||||
Debug::show( $data );
|
|
||||||
die();*/
|
|
||||||
|
|
||||||
$fieldPrefix = 'Default-';
|
$fieldPrefix = 'Default-';
|
||||||
|
|
||||||
if( empty( $data['Default'] ) && !empty( $data[$fieldPrefix.'Year'] ) && !empty( $data[$fieldPrefix.'Month'] ) && !empty( $data[$fieldPrefix.'Day'] ) )
|
if( empty( $data['Default'] ) && !empty( $data[$fieldPrefix.'Year'] ) && !empty( $data[$fieldPrefix.'Month'] ) && !empty( $data[$fieldPrefix.'Day'] ) )
|
||||||
|
@ -1,102 +1,25 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* EditableDropdown
|
* EditableDropdown
|
||||||
|
*
|
||||||
* Represents a modifiable dropdown box on a form
|
* Represents a modifiable dropdown box on a form
|
||||||
* @package forms
|
*
|
||||||
* @subpackage fieldeditor
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableDropdown extends EditableFormField {
|
class EditableDropdown extends EditableMultipleOptionField {
|
||||||
|
|
||||||
static $has_many = array(
|
|
||||||
"Options" => "EditableDropdownOption"
|
|
||||||
);
|
|
||||||
|
|
||||||
static $singular_name = 'Dropdown';
|
static $singular_name = 'Dropdown';
|
||||||
|
|
||||||
static $plural_name = 'Dropdowns';
|
static $plural_name = 'Dropdowns';
|
||||||
|
|
||||||
function delete() {
|
|
||||||
$options = $this->Options();
|
|
||||||
|
|
||||||
foreach( $options as $option )
|
|
||||||
$option->delete();
|
|
||||||
|
|
||||||
parent::delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
function EditSegment() {
|
|
||||||
return $this->renderWith( $this->class );
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateFromPostData( $data ) {
|
|
||||||
|
|
||||||
parent::populateFromPostData( $data );
|
|
||||||
|
|
||||||
$fieldSet = $this->Options();
|
|
||||||
|
|
||||||
$deletedOptions = explode( ',', $data['Deleted'] );
|
|
||||||
|
|
||||||
// store default, etc
|
|
||||||
foreach( $fieldSet as $option ) {
|
|
||||||
|
|
||||||
if( $deletedOptions && array_search( $option->ID, $deletedOptions ) !== false ) {
|
|
||||||
$option->delete();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($option) && isset($data[$option->ID])) {
|
|
||||||
$option->setField('Default', isset($data['Default']) ? ($option->ID == $data['Default']) : false);
|
|
||||||
$option->populateFromPostData( $data[$option->ID] );
|
|
||||||
}
|
|
||||||
|
|
||||||
unset( $data[$option->ID] );
|
|
||||||
}
|
|
||||||
|
|
||||||
$optionNumber = 0;
|
|
||||||
foreach( $data as $tempID => $optionData ) {
|
|
||||||
|
|
||||||
if( !$tempID || !is_array( $optionData ) || empty( $optionData ) || !preg_match('/^_?\d+$/', $tempID ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// what will we name the new option?
|
|
||||||
$newOption = new EditableDropdownOption();
|
|
||||||
$newOption->Name = 'option' . (string)$optionNumber++;
|
|
||||||
$newOption->ParentID = $this->ID;
|
|
||||||
if(isset($data['Default'])) {
|
|
||||||
$newOption->setField('Default', $tempID == $data['Default']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( Director::is_ajax() ) {
|
|
||||||
$fieldID = $this->ID;
|
|
||||||
$fieldEditorName = $this->editor ? $this->editor->Name() : 'Fields';
|
|
||||||
$prefix = $fieldEditorName . '[' . $fieldID . ']';
|
|
||||||
$newID = $newOption->ID;
|
|
||||||
$newSort = $newOption->Sort;
|
|
||||||
echo "\$('". $fieldEditorName . "[$fieldID]').updateOption('$prefix','$tempID','$newID','$newSort');";
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !$optionData['Sort'] ) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$newOption->populateFromPostData( $optionData );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFormField() {
|
|
||||||
return $this->createField();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFilterField() {
|
|
||||||
return $this->createField( true );
|
|
||||||
}
|
|
||||||
|
|
||||||
function createField($asFilter = false) {
|
function createField($asFilter = false) {
|
||||||
$optionSet = $this->Options();
|
$optionSet = $this->Options();
|
||||||
$options = array();
|
$options = array();
|
||||||
|
|
||||||
if( $asFilter )
|
if($asFilter) {
|
||||||
$options['-1'] = "(Any)";
|
$options['-1'] = "(Any)";
|
||||||
|
}
|
||||||
$defaultOption = '-1';
|
$defaultOption = '-1';
|
||||||
|
|
||||||
foreach( $optionSet as $option ) {
|
foreach( $optionSet as $option ) {
|
||||||
@ -107,21 +30,5 @@ class EditableDropdown extends EditableFormField {
|
|||||||
return new DropdownField( $this->Name, $this->Title, $options, $defaultOption );
|
return new DropdownField( $this->Name, $this->Title, $options, $defaultOption );
|
||||||
}
|
}
|
||||||
|
|
||||||
function TemplateOption() {
|
|
||||||
$option = new EditableDropdownOption();
|
|
||||||
return $option->EditSegment();
|
|
||||||
}
|
|
||||||
|
|
||||||
function duplicate() {
|
|
||||||
$clonedNode = parent::duplicate();
|
|
||||||
|
|
||||||
foreach( $this->Options() as $field ) {
|
|
||||||
$newField = $field->duplicate();
|
|
||||||
$newField->ParentID = $clonedNode->ID;
|
|
||||||
$newField->write();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $clonedNode;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* EditableDropdownOption
|
|
||||||
* Represents a single entry in an EditableDropdown
|
|
||||||
* @package forms
|
|
||||||
* @subpackage fieldeditor
|
|
||||||
*/
|
|
||||||
class EditableDropdownOption extends DataObject {
|
|
||||||
protected $readonly;
|
|
||||||
|
|
||||||
function ReadonlyOption() {
|
|
||||||
$this->readonly = true;
|
|
||||||
return $this->EditSegment();
|
|
||||||
}
|
|
||||||
|
|
||||||
function isReadonly() {
|
|
||||||
return $this->readonly;
|
|
||||||
}
|
|
||||||
|
|
||||||
static $default_sort = "Sort";
|
|
||||||
|
|
||||||
// add required here?
|
|
||||||
static $db = array(
|
|
||||||
"Name" => "Varchar",
|
|
||||||
"Title" => "Varchar",
|
|
||||||
"Default" => "Boolean",
|
|
||||||
"Sort" => "Int"
|
|
||||||
);
|
|
||||||
static $has_one = array(
|
|
||||||
"Parent" => "EditableDropdown",
|
|
||||||
);
|
|
||||||
|
|
||||||
static $singular_name = 'Dropdown option';
|
|
||||||
static $plural_name = 'Dropdown options';
|
|
||||||
|
|
||||||
function EditSegment() {
|
|
||||||
return $this->renderWith('EditableFormFieldOption');
|
|
||||||
}
|
|
||||||
|
|
||||||
function TitleField() {
|
|
||||||
return new TextField( "Fields[{$this->ParentID}][{$this->ID}][Title]", null, $this->Title );
|
|
||||||
}
|
|
||||||
|
|
||||||
function Name() {
|
|
||||||
return "Fields[{$this->ParentID}][{$this->ID}]";
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateFromPostData( $data ) {
|
|
||||||
$this->Title = $data['Title'];
|
|
||||||
$this->Sort = $data['Sort'];
|
|
||||||
$this->write();
|
|
||||||
}
|
|
||||||
|
|
||||||
function Option() {
|
|
||||||
// return new radio field
|
|
||||||
/*$title = $this->Title;
|
|
||||||
|
|
||||||
$default = "";
|
|
||||||
|
|
||||||
if( $this->getField('Default') )
|
|
||||||
$default = 'class="default"';
|
|
||||||
|
|
||||||
//Debug::show($this);
|
|
||||||
return '<input type="text" name="Fields['.$this->ParentID.']['.$this->ID.'][Title]" value="'.$title.'" '.$default.' />';*/
|
|
||||||
|
|
||||||
return $this->EditSegment();
|
|
||||||
}
|
|
||||||
|
|
||||||
function DefaultSelect() {
|
|
||||||
$disabled = ($this->readonly) ? " disabled=\"disabled\"" : '';
|
|
||||||
|
|
||||||
$default = ($this->Parent()->getField('Default') == $this->ID) ? " checked=\"checked\"" : "";
|
|
||||||
|
|
||||||
return "<input class=\"radio\" type=\"radio\" name=\"Fields[{$this->ParentID}][Default]\" value=\"{$this->ID}\"".$disabled.$default." />";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
@ -1,9 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* EditableEmailField
|
* EditableEmailField
|
||||||
|
*
|
||||||
* Allow users to define a validating editable email field for a UserDefinedForm
|
* Allow users to define a validating editable email field for a UserDefinedForm
|
||||||
* @package forms
|
*
|
||||||
* @subpackage fieldeditor
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableEmailField extends EditableFormField {
|
class EditableEmailField extends EditableFormField {
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Allows a user to add a field that can be used to upload a file
|
* Allows a user to add a field that can be used to upload a file
|
||||||
* @package forms
|
*
|
||||||
* @subpackage fieldeditor
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableFileField extends EditableFormField {
|
class EditableFileField extends EditableFormField {
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Represents an editable form field
|
* Represents the base class of a editable form field
|
||||||
* @package forms
|
* object like {@link EditableTextField}.
|
||||||
* @subpackage fieldeditor
|
*
|
||||||
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableFormField extends DataObject {
|
class EditableFormField extends DataObject {
|
||||||
|
|
||||||
@ -15,7 +16,8 @@ class EditableFormField extends DataObject {
|
|||||||
"Sort" => "Int",
|
"Sort" => "Int",
|
||||||
"Required" => "Boolean",
|
"Required" => "Boolean",
|
||||||
"CanDelete" => "Boolean",
|
"CanDelete" => "Boolean",
|
||||||
"CustomParameter" => "Varchar"
|
"CustomParameter" => "Varchar",
|
||||||
|
"OptionallyDisplay" => "Boolean"
|
||||||
);
|
);
|
||||||
|
|
||||||
static $defaults = array(
|
static $defaults = array(
|
||||||
@ -26,19 +28,36 @@ class EditableFormField extends DataObject {
|
|||||||
"Parent" => "SiteTree",
|
"Parent" => "SiteTree",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool Is this field readonly to the user
|
||||||
|
*/
|
||||||
protected $readonly;
|
protected $readonly;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FieldEditor The current editor
|
||||||
|
*/
|
||||||
protected $editor;
|
protected $editor;
|
||||||
|
|
||||||
function setEditor( $editor ) {
|
/**
|
||||||
$this->editor = $editor;
|
* Construct a new EditableFormField Object.
|
||||||
}
|
*
|
||||||
|
* @param array|null $record This will be null for a new database record.
|
||||||
function __construct( $record = null, $isSingleton = false ) {
|
* @param boolean $isSingleton This this to true if this is a singleton() object, a stub for calling methods.
|
||||||
|
*/
|
||||||
|
public function __construct($record = null, $isSingleton = false) {
|
||||||
$this->setField('Default', -1);
|
$this->setField('Default', -1);
|
||||||
parent::__construct( $record, $isSingleton );
|
parent::__construct( $record, $isSingleton );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the FieldEditor object for this field.
|
||||||
|
*
|
||||||
|
* @param FieldEditor The Editor window you wish to use
|
||||||
|
*/
|
||||||
|
protected function setEditor($editor) {
|
||||||
|
$this->editor = $editor;
|
||||||
|
}
|
||||||
|
|
||||||
function EditSegment() {
|
function EditSegment() {
|
||||||
return $this->renderWith('EditableFormField');
|
return $this->renderWith('EditableFormField');
|
||||||
}
|
}
|
||||||
@ -51,6 +70,26 @@ class EditableFormField extends DataObject {
|
|||||||
return $this->class;
|
return $this->class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether or not this field has addable options
|
||||||
|
* such as a dropdown field or radio set
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasAddableOptions() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether or not this field needs to show the extra
|
||||||
|
* options dropdown list
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function showExtraOptions() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function makeReadonly() {
|
function makeReadonly() {
|
||||||
$this->readonly = true;
|
$this->readonly = true;
|
||||||
return $this;
|
return $this;
|
||||||
@ -62,15 +101,8 @@ class EditableFormField extends DataObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function TitleField() {
|
function TitleField() {
|
||||||
// return new TextField( "Fields[".$this->ID."][Title]", null, $this->Title );
|
|
||||||
$titleAttr = Convert::raw2att($this->Title);
|
$titleAttr = Convert::raw2att($this->Title);
|
||||||
$readOnlyAttr = '';
|
$readOnlyAttr = ($this->readonly) ? ' disabled="disabled"' : '';
|
||||||
|
|
||||||
if( $this->readonly ) {
|
|
||||||
$readOnlyAttr = ' disabled="disabled"';
|
|
||||||
} else {
|
|
||||||
$readOnlyAttr = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return "<input type=\"text\" class=\"text\" title=\"("._t('EditableFormField.ENTERQUESTION', 'Enter Question').")\" value=\"$titleAttr\" name=\"Fields[{$this->ID}][Title]\"$readOnlyAttr />";
|
return "<input type=\"text\" class=\"text\" title=\"("._t('EditableFormField.ENTERQUESTION', 'Enter Question').")\" value=\"$titleAttr\" name=\"Fields[{$this->ID}][Title]\"$readOnlyAttr />";
|
||||||
}
|
}
|
||||||
@ -79,25 +111,23 @@ class EditableFormField extends DataObject {
|
|||||||
return "Fields[".$this->ID."]";
|
return "Fields[".$this->ID."]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*function getName() {
|
/**
|
||||||
return "field" . $this->ID;
|
* How to save the data submitted in this field into
|
||||||
}*/
|
* the database object which this field represents.
|
||||||
|
*
|
||||||
function populateFromPostData( $data ) {
|
* Any class's which call this should also call
|
||||||
|
* {@link parent::populateFromPostData()} to ensure
|
||||||
$this->Title = isset($data['Title']) ? $data['Title']: "";
|
* that this method is called
|
||||||
|
*
|
||||||
if(isset($data['Default'])) {
|
* @access public
|
||||||
$this->setField('Default', $data['Default']);
|
*/
|
||||||
}
|
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->Sort = isset($data['Sort']) ? $data['Sort'] : null;
|
||||||
$this->CustomParameter = isset($data['CustomParameter']) ? $data['CustomParameter'] : null;
|
$this->CustomParameter = isset($data['CustomParameter']) ? $data['CustomParameter'] : null;
|
||||||
$this->Required = !empty($data['Required']) ? 1 : 0;
|
$this->Required = !empty($data['Required']) ? 1 : 0;
|
||||||
$this->CanDelete = (isset($data['CanDelete']) && !$data['CanDelete']) ? 0 : 1;
|
$this->CanDelete = (isset($data['CanDelete']) && !$data['CanDelete']) ? 0 : 1;
|
||||||
$this->write();
|
|
||||||
|
|
||||||
// The field must be written to ensure a unique ID.
|
|
||||||
$this->Name = $this->class.$this->ID;
|
$this->Name = $this->class.$this->ID;
|
||||||
$this->write();
|
$this->write();
|
||||||
}
|
}
|
||||||
@ -109,19 +139,25 @@ class EditableFormField extends DataObject {
|
|||||||
|
|
||||||
if(!$this->Parent()->hasMethod('hideExtraOption')){
|
if(!$this->Parent()->hasMethod('hideExtraOption')){
|
||||||
$extraOptions->push(new CheckboxField($baseName . "[Required]", _t('EditableFormField.REQUIRED', 'Required?'), $this->Required));
|
$extraOptions->push(new CheckboxField($baseName . "[Required]", _t('EditableFormField.REQUIRED', 'Required?'), $this->Required));
|
||||||
}elseif( !$this->Parent()->hideExtraOption( 'Required' ) ){
|
}
|
||||||
|
elseif(!$this->Parent()->hideExtraOption('Required')){
|
||||||
$extraOptions->push(new CheckboxField($baseName . "[Required]", _t('EditableFormField.REQUIRED', 'Required?'), $this->Required));
|
$extraOptions->push(new CheckboxField($baseName . "[Required]", _t('EditableFormField.REQUIRED', 'Required?'), $this->Required));
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->Parent()->hasMethod('getExtraOptionsForField')) {
|
if($this->Parent()->hasMethod('getExtraOptionsForField')) {
|
||||||
$extraFields = $this->Parent()->getExtraOptionsForField($this);
|
$extraFields = $this->Parent()->getExtraOptionsForField($this);
|
||||||
|
|
||||||
foreach( $extraFields as $extraField )
|
foreach($extraFields as $extraField) {
|
||||||
$extraOptions->push($extraField);
|
$extraOptions->push($extraField);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( $this->readonly )
|
if($this->readonly) {
|
||||||
$extraOptions = $extraOptions->makeReadonly();
|
$extraOptions = $extraOptions->makeReadonly();
|
||||||
|
}
|
||||||
|
|
||||||
|
// support for optionally display field
|
||||||
|
// $extraOptions->push(new CheckboxField($baseName ."[OptionallyDisplay]", _t('EditableFormField.OPTIONALLYDISPLAY', 'Optionally Display Field'), $this->OptionallyDisplay));
|
||||||
|
|
||||||
return $extraOptions;
|
return $extraOptions;
|
||||||
}
|
}
|
||||||
@ -159,7 +195,6 @@ class EditableFormField extends DataObject {
|
|||||||
|
|
||||||
protected function parsePrepopulateValue( $value ) {
|
protected function parsePrepopulateValue( $value ) {
|
||||||
$paramList = explode( ',', $value );
|
$paramList = explode( ',', $value );
|
||||||
|
|
||||||
$paramMap = array();
|
$paramMap = array();
|
||||||
|
|
||||||
foreach( $paramList as $param ) {
|
foreach( $paramList as $param ) {
|
||||||
@ -170,33 +205,20 @@ class EditableFormField extends DataObject {
|
|||||||
} else if( isset( $paramMap[$match[1]] ) ) {
|
} else if( isset( $paramMap[$match[1]] ) ) {
|
||||||
$paramMap[$match[1]] = array( $paramMap[$match[1]] );
|
$paramMap[$match[1]] = array( $paramMap[$match[1]] );
|
||||||
$paramMap[$match[1]][] = $match[2];
|
$paramMap[$match[1]][] = $match[2];
|
||||||
//Debug::message( $match[1] . '[]=' . $match[2] );
|
|
||||||
} else {
|
} else {
|
||||||
$paramMap[$match[1]] = $match[2];
|
$paramMap[$match[1]] = $match[2];
|
||||||
//Debug::message( $match[1] . '=' . $match[2] );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//Debug::message('Invalid: ' . $param );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//Debug::show( $paramMap );
|
|
||||||
|
|
||||||
return $paramMap;
|
return $paramMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function prepopulateFromMap( $paramMap ) {
|
protected function prepopulateFromMap( $paramMap ) {
|
||||||
//Debug::show( $paramMap );
|
|
||||||
//Debug::show( $this->stat('db') );
|
|
||||||
|
|
||||||
foreach($paramMap as $field => $fieldValue) {
|
foreach($paramMap as $field => $fieldValue) {
|
||||||
if( /*$this->hasField( $field ) &&*/ !is_array( $fieldValue ) ) {
|
if(!is_array($fieldValue)) {
|
||||||
$this->$field = $fieldValue;
|
$this->$field = $fieldValue;
|
||||||
// Debug::message( 'Set ' . $field . ':'. $fieldValue );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Type() {
|
function Type() {
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Allows an editor to insert a generic heading into a field
|
* Allows an editor to insert a generic heading into a field
|
||||||
* @package forms
|
*
|
||||||
* @subpackage fieldeditor
|
* @subpackage userforms
|
||||||
*/
|
*/
|
||||||
class EditableFormHeading extends EditableFormField {
|
class EditableFormHeading extends EditableFormField {
|
||||||
|
|
||||||
static $singular_name = 'Form heading';
|
static $singular_name = 'Form heading';
|
||||||
|
|
||||||
static $plural_name = 'Form headings';
|
static $plural_name = 'Form headings';
|
||||||
|
|
||||||
function getFormField() {
|
function getFormField() {
|
||||||
// TODO customise this
|
|
||||||
$labelField = new LabelField('FormHeadingLabel',$this->Title);
|
$labelField = new LabelField('FormHeadingLabel',$this->Title);
|
||||||
$labelField->addExtraClass('FormHeading');
|
$labelField->addExtraClass('FormHeading');
|
||||||
return $labelField;
|
return $labelField;
|
||||||
@ -18,5 +19,9 @@ class EditableFormHeading extends EditableFormField {
|
|||||||
function showInReports() {
|
function showInReports() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showExtraOptions() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Editable Spam Protecter Field. Used with the User Defined Forms module (if
|
* Editable Literal Field. A literal field is just a blank slate where
|
||||||
* installed) to allow the user to have captcha fields with their custom forms
|
* you can add your own HTML / Images / Flash
|
||||||
*
|
*
|
||||||
* @package SpamProtection
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class EditableLiteralField extends EditableFormField {
|
class EditableLiteralField extends EditableFormField {
|
||||||
@ -14,15 +14,10 @@ class EditableLiteralField extends EditableFormField {
|
|||||||
);
|
);
|
||||||
|
|
||||||
static $singular_name = 'HTML Block';
|
static $singular_name = 'HTML Block';
|
||||||
|
|
||||||
static $plural_name = 'HTML Blocks';
|
static $plural_name = 'HTML Blocks';
|
||||||
|
|
||||||
function __construct( $record = null, $isSingleton = false ) {
|
|
||||||
|
|
||||||
parent::__construct( $record, $isSingleton );
|
|
||||||
}
|
|
||||||
|
|
||||||
function ExtraOptions() {
|
function ExtraOptions() {
|
||||||
|
|
||||||
// eventually replace hard-coded "Fields"?
|
// eventually replace hard-coded "Fields"?
|
||||||
$baseName = "Fields[$this->ID]";
|
$baseName = "Fields[$this->ID]";
|
||||||
|
|
||||||
@ -33,32 +28,13 @@ class EditableLiteralField extends EditableFormField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function populateFromPostData($data) {
|
function populateFromPostData($data) {
|
||||||
|
|
||||||
$this->Content = $data['Content'];
|
$this->Content = $data['Content'];
|
||||||
parent::populateFromPostData($data);
|
parent::populateFromPostData($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFormField() {
|
|
||||||
return $this->createField();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFilterField() {
|
|
||||||
return $this->createField(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createField() {
|
function createField() {
|
||||||
return new LiteralField("LiteralField[$this->ID]",
|
return new LiteralField("LiteralField[$this->ID]",
|
||||||
"<div class='field text'><label class='left'>$this->Title</label><div class='middleColumn literalFieldArea'>". $this->Content."</div></div>");
|
"<div class='field text'><label class='left'>$this->Title</label><div class='middleColumn literalFieldArea'>". $this->Content."</div></div>");
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Populates the default fields.
|
|
||||||
*/
|
|
||||||
function DefaultField() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function EditSegment() {
|
|
||||||
return $this->renderWith( $this->class );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Creates an editable field that displays members in a given group
|
* Creates an editable field that displays members in a given group
|
||||||
* @package forms
|
*
|
||||||
* @subpackage fieldeditor
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableMemberListField extends EditableFormField {
|
class EditableMemberListField extends EditableFormField {
|
||||||
|
|
||||||
|
160
code/editor/EditableMultipleOptionField.php
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for multiple option fields such as dropdowns and
|
||||||
|
* radio sets. Implemented as a class but you would not create
|
||||||
|
* one of these directly, rather you would instantiate a subclass
|
||||||
|
* such as EditableDropdownField
|
||||||
|
*
|
||||||
|
* @todo Make it would make more sense to have dropdownfield and
|
||||||
|
* checkboxset just transformations on this class
|
||||||
|
*
|
||||||
|
* @package userforms
|
||||||
|
*/
|
||||||
|
|
||||||
|
class EditableMultipleOptionField extends EditableFormField {
|
||||||
|
|
||||||
|
static $db = array();
|
||||||
|
|
||||||
|
static $has_one = array();
|
||||||
|
|
||||||
|
static $has_many = array(
|
||||||
|
"Options" => "EditableOption"
|
||||||
|
);
|
||||||
|
|
||||||
|
protected $readonly;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all the options attached to this field before
|
||||||
|
* deleting the field. Keeps stray options from floating
|
||||||
|
* around
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function delete() {
|
||||||
|
$options = $this->Options();
|
||||||
|
if($options) {
|
||||||
|
foreach($options as $option) {
|
||||||
|
$option->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent::delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duplicate a pages content. We need to make sure all
|
||||||
|
* the fields attached to that page go with it
|
||||||
|
*
|
||||||
|
* @return DataObject a Clone of this node
|
||||||
|
*/
|
||||||
|
public function duplicate() {
|
||||||
|
$clonedNode = parent::duplicate();
|
||||||
|
|
||||||
|
if($this->Options()) {
|
||||||
|
foreach($this->Options() as $field) {
|
||||||
|
$newField = $field->duplicate();
|
||||||
|
$newField->ParentID = $clonedNode->ID;
|
||||||
|
$newField->write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 Array Data
|
||||||
|
*/
|
||||||
|
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 dropdown field or radio set
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasAddableOptions() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this multipleoptionfield to readonly
|
||||||
|
*/
|
||||||
|
protected function ReadonlyOption() {
|
||||||
|
$this->readonly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this multipleoption field readonly to the user
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isReadonly() {
|
||||||
|
return $this->readonly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the form field for this object in the front
|
||||||
|
* end form view
|
||||||
|
*
|
||||||
|
* @return FormField
|
||||||
|
*/
|
||||||
|
public function getFormField() {
|
||||||
|
return $this->createField();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the form field as a field suitable for insertion
|
||||||
|
* into the filter form
|
||||||
|
*
|
||||||
|
* @return FormField
|
||||||
|
*/
|
||||||
|
public function getFilterField() {
|
||||||
|
return $this->createField(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the correct form field for this object. Note this
|
||||||
|
* does a transformation between being a field on the form and
|
||||||
|
* a field in the filter search form
|
||||||
|
*
|
||||||
|
* This should be extended on your subclass
|
||||||
|
*
|
||||||
|
* @param bool - Filter Field?
|
||||||
|
* @return UserError - You should implement it on your subclass
|
||||||
|
*/
|
||||||
|
public function createField($filter = false) {
|
||||||
|
return user_error('Please implement createField() on '. $this->class, E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checkbox to show if this option is the default option selected
|
||||||
|
* in the form
|
||||||
|
*
|
||||||
|
* @return HTML
|
||||||
|
*/
|
||||||
|
public function DefaultSelect() {
|
||||||
|
$disabled = ($this->readonly) ? " disabled=\"disabled\"" : '';
|
||||||
|
$default = ($this->Parent()->getField('Default') == $this->ID) ? " checked=\"checked\"" : '';
|
||||||
|
|
||||||
|
return "<input class=\"radio\" type=\"radio\" name=\"Fields[{$this->ParentID}][Default]\" value=\"{$this->ID}\"".$disabled.$default." />";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
71
code/editor/EditableOption.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Class for EditableOption Fields such as the ones used in
|
||||||
|
* dropdown fields and in radio check box groups
|
||||||
|
*
|
||||||
|
* @package userforms
|
||||||
|
*/
|
||||||
|
|
||||||
|
class EditableOption extends DataObject {
|
||||||
|
|
||||||
|
static $default_sort = "Sort";
|
||||||
|
|
||||||
|
static $db = array(
|
||||||
|
"Name" => "Varchar",
|
||||||
|
"Title" => "Varchar",
|
||||||
|
"Default" => "Boolean",
|
||||||
|
"Sort" => "Int"
|
||||||
|
);
|
||||||
|
|
||||||
|
static $has_one = array(
|
||||||
|
"Parent" => "EditableMultipleOptionField",
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template for the editing view of this option field
|
||||||
|
*/
|
||||||
|
public function EditSegment() {
|
||||||
|
return $this->renderWith('EditableOption');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Title Field for this object
|
||||||
|
*
|
||||||
|
* @return FormField
|
||||||
|
*/
|
||||||
|
public function TitleField() {
|
||||||
|
return new TextField("Fields[{$this->ParentID}][{$this->ID}][Title]", null, $this->Title );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of this field in the form
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public function Name() {
|
||||||
|
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->write();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make this option readonly
|
||||||
|
*/
|
||||||
|
public function ReadonlyOption() {
|
||||||
|
$this->readonly = true;
|
||||||
|
return $this->EditSegment();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
@ -1,102 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* EditableDropdown
|
* EditableRadioField
|
||||||
|
*
|
||||||
* Represents a set of selectable radio buttons
|
* Represents a set of selectable radio buttons
|
||||||
* @package forms
|
*
|
||||||
* @subpackage fieldeditor
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableRadioField extends EditableFormField {
|
class EditableRadioField extends EditableMultipleOptionField {
|
||||||
|
|
||||||
static $has_many = array(
|
|
||||||
"Options" => "EditableRadioOption"
|
|
||||||
);
|
|
||||||
|
|
||||||
static $singular_name = 'Radio field';
|
static $singular_name = 'Radio field';
|
||||||
|
|
||||||
static $plural_name = 'Radio fields';
|
static $plural_name = 'Radio fields';
|
||||||
|
|
||||||
function delete() {
|
|
||||||
$options = $this->Options();
|
|
||||||
|
|
||||||
foreach( $options as $option )
|
|
||||||
$option->delete();
|
|
||||||
|
|
||||||
parent::delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
function duplicate() {
|
|
||||||
$clonedNode = parent::duplicate();
|
|
||||||
|
|
||||||
foreach( $this->Options() as $field ) {
|
|
||||||
$newField = $field->duplicate();
|
|
||||||
$newField->ParentID = $clonedNode->ID;
|
|
||||||
$newField->write();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $clonedNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
function EditSegment() {
|
|
||||||
return $this->renderWith( $this->class );
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateFromPostData( $data ) {
|
|
||||||
parent::populateFromPostData( $data );
|
|
||||||
|
|
||||||
$fieldSet = $this->Options();
|
|
||||||
$deletedOptions = explode( ',', $data['Deleted'] );
|
|
||||||
|
|
||||||
//Debug::show( $deletedOptions );
|
|
||||||
|
|
||||||
// store default, etc
|
|
||||||
foreach( $fieldSet as $option ) {
|
|
||||||
|
|
||||||
//Debug::show( $option );
|
|
||||||
|
|
||||||
if( $deletedOptions && array_search( $option->ID, $deletedOptions ) !== false ) {
|
|
||||||
$option->delete();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( $data[$option->ID] ) {
|
|
||||||
$option->setField( 'Default', $option->ID == $data['Default'] );
|
|
||||||
$option->populateFromPostData( $data[$option->ID] );
|
|
||||||
}
|
|
||||||
|
|
||||||
unset( $data[$option->ID] );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug::show( $data );
|
|
||||||
|
|
||||||
foreach( $data as $tempID => $optionData ) {
|
|
||||||
|
|
||||||
$optionNumber = 0;
|
|
||||||
|
|
||||||
if( !$tempID || !is_array( $optionData ) || empty( $optionData ) || !preg_match('/^_?\d+$/', $tempID ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// what will we name the new option?
|
|
||||||
$newOption = new EditableRadioOption();
|
|
||||||
$newOption->Name = sprintf( 'option%d', $optionNumber++ );
|
|
||||||
$newOption->ParentID = $this->ID;
|
|
||||||
$newOption->setField( 'Default', $tempID == $data['Default'] );
|
|
||||||
$newOption->populateFromPostData( $optionData );
|
|
||||||
|
|
||||||
// $mail .= "NEW: " . $optionData['Title'] . "\n";
|
|
||||||
|
|
||||||
if( Director::is_ajax() ) {
|
|
||||||
$fieldID = $this->ID;
|
|
||||||
$fieldEditorName = $this->editor ? $this->editor->Name() : 'Fields';
|
|
||||||
$prefix = $fieldEditorName . '[' . $fieldID . ']';
|
|
||||||
$newID = $newOption->ID;
|
|
||||||
$newSort = $newOption->Sort;
|
|
||||||
echo "\$('". $fieldEditorName . "[$fieldID]').updateOption('$prefix','$tempID','$newID','$newSort');";
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !$newOption->Title )
|
|
||||||
user_error('Added blank option '.$tempID, E_USER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function DefaultOption() {
|
function DefaultOption() {
|
||||||
$defaultOption = 0;
|
$defaultOption = 0;
|
||||||
|
|
||||||
@ -110,14 +25,6 @@ class EditableRadioField extends EditableFormField {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFormField() {
|
|
||||||
return $this->createField();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFilterField() {
|
|
||||||
return $this->createField( true );
|
|
||||||
}
|
|
||||||
|
|
||||||
function createField( $asFilter = false ) {
|
function createField( $asFilter = false ) {
|
||||||
$optionSet = $this->Options();
|
$optionSet = $this->Options();
|
||||||
$options = array();
|
$options = array();
|
||||||
@ -136,52 +43,5 @@ class EditableRadioField extends EditableFormField {
|
|||||||
// return radiofields
|
// return radiofields
|
||||||
return new OptionsetField($this->Name, $this->Title, $options, $defaultOption);
|
return new OptionsetField($this->Name, $this->Title, $options, $defaultOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepopulate( $value ) {
|
|
||||||
|
|
||||||
$options = $this->Options();
|
|
||||||
|
|
||||||
$paramMap = $this->parsePrepopulateValue( $value );
|
|
||||||
|
|
||||||
// find options and add them
|
|
||||||
$optionNumber = 0;
|
|
||||||
foreach( $paramMap['Options'] as $newOption ) {
|
|
||||||
if( preg_match( '/([^:]+)[:](.*)/', $newOption, $match ) ) {
|
|
||||||
$newOptionValue = $match[1];
|
|
||||||
$newOptionTitle = $match[2];
|
|
||||||
|
|
||||||
$newOptionTitle = preg_replace('/__/', ' ', $newOptionTitle );
|
|
||||||
|
|
||||||
$newOption = $this->createOption(
|
|
||||||
'option' . (string)$optionNumber,
|
|
||||||
$newOptionTitle,
|
|
||||||
'new-' . (string)$optionNumber,
|
|
||||||
$newOption['Sort'],
|
|
||||||
$optionNumber == 1,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
$optionNumber++;
|
|
||||||
$options->addWithoutWrite( $newOption );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function createOption( $name, $title, $id, $sort = 0, $isDefault = false ) {
|
|
||||||
$newOption = new EditableRadioOption();
|
|
||||||
$newOption->Name = $name;
|
|
||||||
$newOption->Title = $title;
|
|
||||||
$newOption->ID = $id;
|
|
||||||
$newOption->Sort = $sort;
|
|
||||||
$newOption->setField('Default', $isDefault ? '1' : '0');
|
|
||||||
|
|
||||||
return $newOption;
|
|
||||||
}
|
|
||||||
|
|
||||||
function TemplateOption() {
|
|
||||||
$option = new EditableRadioOption();
|
|
||||||
$option->ParentID = $this->ID;
|
|
||||||
return $option->EditSegment();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* EditableDropdownOption
|
|
||||||
* Represents a single entry in an EditableRadioField
|
|
||||||
* @package forms
|
|
||||||
* @subpackage fieldeditor
|
|
||||||
*/
|
|
||||||
class EditableRadioOption extends DataObject {
|
|
||||||
protected $readonly;
|
|
||||||
|
|
||||||
function ReadonlyOption() {
|
|
||||||
$this->readonly = true;
|
|
||||||
return $this->EditSegment();
|
|
||||||
}
|
|
||||||
|
|
||||||
function isReadonly() {
|
|
||||||
return $this->readonly;
|
|
||||||
}
|
|
||||||
|
|
||||||
static $default_sort = "Sort";
|
|
||||||
|
|
||||||
// add required here?
|
|
||||||
static $db = array(
|
|
||||||
"Name" => "Varchar",
|
|
||||||
"Title" => "Varchar",
|
|
||||||
"Default" => "Boolean",
|
|
||||||
"Value" => "Varchar",
|
|
||||||
"Sort" => "Int"
|
|
||||||
);
|
|
||||||
static $has_one = array(
|
|
||||||
"Parent" => "EditableRadioField",
|
|
||||||
);
|
|
||||||
|
|
||||||
static $singular_name = 'Radio option';
|
|
||||||
static $plural_name = 'Radio options';
|
|
||||||
|
|
||||||
function EditSegment() {
|
|
||||||
return $this->renderWith('EditableFormFieldOption');
|
|
||||||
}
|
|
||||||
|
|
||||||
function TitleField() {
|
|
||||||
return new TextField( "Fields[{$this->ParentID}][{$this->ID}][Title]", null, $this->Title );
|
|
||||||
}
|
|
||||||
|
|
||||||
function Name() {
|
|
||||||
return "Fields[{$this->ParentID}][{$this->ID}]";
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateFromPostData( $data ) {
|
|
||||||
$this->Title = $data['Title'];
|
|
||||||
$this->Sort = $data['Sort'];
|
|
||||||
$this->write();
|
|
||||||
}
|
|
||||||
|
|
||||||
function Option() {
|
|
||||||
// return new radio field
|
|
||||||
/*$title = Convert::raw2att( $this->Title );
|
|
||||||
|
|
||||||
$default = "";
|
|
||||||
|
|
||||||
if( $this->getField('Default') )
|
|
||||||
$default = '+';
|
|
||||||
else
|
|
||||||
$default = '-';
|
|
||||||
|
|
||||||
//Debug::show($this);
|
|
||||||
return '<input type="text" name="Fields['.$this->ParentID.']['.$this->ID.'][Title]" value="'.$default.$title.'" />';*/
|
|
||||||
|
|
||||||
return $this->EditSegment();
|
|
||||||
}
|
|
||||||
|
|
||||||
function DefaultSelect() {
|
|
||||||
$disabled = ($this->readonly) ? " disabled=\"disabled\"" : '';
|
|
||||||
|
|
||||||
if($this->Parent()->getField('Default') == $this->ID) {
|
|
||||||
$default = " checked=\"checked\"";
|
|
||||||
} else {
|
|
||||||
$default = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return "<input class=\"radio\" type=\"radio\" name=\"Fields[{$this->ParentID}][Default]\" value=\"{$this->ID}\"".$disabled.$default." />";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
@ -1,9 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* EditableTextField
|
* EditableTextField
|
||||||
* This control represents a user-defined field in a user defined form
|
*
|
||||||
* @package forms
|
* This control represents a user-defined text field in a user defined form
|
||||||
* @subpackage fieldeditor
|
*
|
||||||
|
* @package userforms
|
||||||
*/
|
*/
|
||||||
class EditableTextField extends EditableFormField {
|
class EditableTextField extends EditableFormField {
|
||||||
|
|
||||||
|
@ -27,8 +27,8 @@ class FieldEditor extends FormField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Fields() {
|
function Fields() {
|
||||||
Requirements::css("userform/css/FieldEditor.css");
|
Requirements::css("userforms/css/FieldEditor.css");
|
||||||
Requirements::javascript("userform/javascript/FieldEditor.js");
|
Requirements::javascript("userforms/javascript/UserForm.js");
|
||||||
|
|
||||||
$relationName = $this->name;
|
$relationName = $this->name;
|
||||||
|
|
||||||
@ -75,10 +75,16 @@ class FieldEditor extends FormField {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
function saveInto(DataObject $record) {
|
function saveInto(DataObject $record) {
|
||||||
|
|
||||||
$name = $this->name;
|
$name = $this->name;
|
||||||
|
|
||||||
$fieldSet = $record->$name();
|
$fieldSet = $record->$name();
|
||||||
|
|
||||||
// @todo shouldn't we deal with customFormActions on that object?
|
// @todo shouldn't we deal with customFormActions on that object?
|
||||||
@ -95,27 +101,18 @@ class FieldEditor extends FormField {
|
|||||||
$missingFields[$existingField->ID] = $existingField;
|
$missingFields[$existingField->ID] = $existingField;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the new fields to the database
|
|
||||||
if($_REQUEST[$name]){
|
if($_REQUEST[$name]){
|
||||||
foreach( array_keys( $_REQUEST[$name] ) as $newEditableID ) {
|
foreach( array_keys( $_REQUEST[$name] ) as $newEditableID ) {
|
||||||
$newEditableData = $_REQUEST[$name][$newEditableID];
|
$newEditableData = $_REQUEST[$name][$newEditableID];
|
||||||
|
|
||||||
// `ParentID`=0 is for the new page
|
|
||||||
$editable = DataObject::get_one('EditableFormField', "(`ParentID`='{$record->ID}' OR `ParentID`=0) AND `EditableFormField`.`ID`='$newEditableID'" );
|
$editable = DataObject::get_one('EditableFormField', "(`ParentID`='{$record->ID}' OR `ParentID`=0) AND `EditableFormField`.`ID`='$newEditableID'" );
|
||||||
|
|
||||||
// check if we are updating an existing field
|
// check if we are updating an existing field. One odd thing is a 'deleted' field
|
||||||
if( $editable && isset($missingFields[$editable->ID]))
|
// still exists in the post data (ID) so we need to check for type.
|
||||||
|
if($editable && isset($missingFields[$editable->ID]) && isset($newEditableData['Type'])) {
|
||||||
|
// check if it has been labelled as deleted
|
||||||
|
if(isset($newEditableData['Title']) && $newEditableData['Title'] != 'field-node-deleted') {
|
||||||
unset($missingFields[$editable->ID]);
|
unset($missingFields[$editable->ID]);
|
||||||
|
|
||||||
// create a new object
|
|
||||||
// this should now be obsolete
|
|
||||||
if(!$editable && !empty($newEditableData['Type']) && class_exists($newEditableData['Type'])) {
|
|
||||||
$editable = new $newEditableData['Type']();
|
|
||||||
$editable->ID = 0;
|
|
||||||
$editable->ParentID = $record->ID;
|
|
||||||
|
|
||||||
if(!is_subclass_of($editable, 'EditableFormField')) {
|
|
||||||
$editable = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +121,6 @@ class FieldEditor extends FormField {
|
|||||||
$editable->ParentID = $record->ID;
|
$editable->ParentID = $record->ID;
|
||||||
}
|
}
|
||||||
$editable->populateFromPostData($newEditableData);
|
$editable->populateFromPostData($newEditableData);
|
||||||
//$editable->write();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,55 +133,70 @@ class FieldEditor extends FormField {
|
|||||||
if($record->hasMethod('customFormSave')) {
|
if($record->hasMethod('customFormSave')) {
|
||||||
$record->customFormSave( $_REQUEST[$name], $record );
|
$record->customFormSave( $_REQUEST[$name], $record );
|
||||||
}
|
}
|
||||||
//$record->writeWithoutVersion();
|
|
||||||
|
|
||||||
if($record->hasMethod( 'processNewFormFields')) {
|
if($record->hasMethod( 'processNewFormFields')) {
|
||||||
$record->processNewFormFields();
|
$record->processNewFormFields();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addfield() {
|
/**
|
||||||
|
* Add a field to the field editor. Called via a ajax get request
|
||||||
|
* from the userdefinedform javascript
|
||||||
|
*
|
||||||
|
* @return bool|html
|
||||||
|
*/
|
||||||
|
public function addfield() {
|
||||||
// get the last field in this form editor
|
// get the last field in this form editor
|
||||||
$parentID = $this->form->getRecord()->ID;
|
$parentID = $this->form->getRecord()->ID;
|
||||||
$lastField = DataObject::get('EditableFormField', "`ParentID`='$parentID'", "`Sort` DESC", null, 1 );
|
|
||||||
|
|
||||||
$nextSort = 1;
|
if($parentID) {
|
||||||
|
$parentID = Convert::raw2sql($parentID); // who knows what could happen
|
||||||
// the new sort value is the value of the last sort + 1 if a field exists
|
$highestSort = DB::query("SELECT MAX(Sort) FROM EditableFormField WHERE ParentID = '$parentID'");
|
||||||
if( $lastField )
|
$sort = $highestSort->value() + 1;
|
||||||
$nextSort += $lastField->Sort;
|
|
||||||
|
|
||||||
$className = "Editable" . ucfirst($_REQUEST['Type']);
|
$className = "Editable" . ucfirst($_REQUEST['Type']);
|
||||||
$name = $this->name;
|
$name = $this->name;
|
||||||
if(is_subclass_of($className, "EditableFormField")) {
|
if(is_subclass_of($className, "EditableFormField")) {
|
||||||
$e = new $className();
|
$e = new $className();
|
||||||
// $fields = $this->form->getRecord()->$name()->Count();
|
|
||||||
// $e->Name = $this->name . "[NewFields][]";
|
|
||||||
// Debug::show($fields);
|
|
||||||
|
|
||||||
/*if( $this->form->getRecord()->hasMethod('addField') )
|
|
||||||
$this->form->getRecord()->addField( $e );
|
|
||||||
else*/
|
|
||||||
$e->ParentID = $this->form->getRecord()->ID;
|
|
||||||
|
|
||||||
//Debug::show($e);
|
|
||||||
$e->write();
|
$e->write();
|
||||||
//$e->ID = "new-" . ( $_REQUEST['NewID'] + 1 );
|
$e->ParentID = $this->form->getRecord()->ID;
|
||||||
$e->Name = $e->class . $e->ID;
|
$e->Name = $e->class . $e->ID;
|
||||||
$e->write();
|
$e->write();
|
||||||
|
|
||||||
return $e->EditSegment();
|
return $e->EditSegment();
|
||||||
} else {
|
|
||||||
user_error("FieldEditor::addfield: Tried to create a field of class '$className'", E_USER_ERROR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function adddropdownfield() {
|
/**
|
||||||
return $this->addNewField( new EditableDropdown() );
|
* 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;
|
||||||
|
$text = (isset($_REQUEST['Text'])) ? $_REQUEST['Text'] : "";
|
||||||
|
|
||||||
function addcheckboxfield() {
|
// work out the sort by getting the sort of the last field in the form +1
|
||||||
return $this->addNewField( new EditableCheckbox() );
|
if($parent) {
|
||||||
|
$sql_parent = Convert::raw2sql($parent);
|
||||||
|
$highestSort = DB::query("SELECT MAX(Sort) FROM EditableOption WHERE ParentID = '$sql_parent'");
|
||||||
|
$sort = $highestSort->value() + 1;
|
||||||
|
|
||||||
|
if($parent) {
|
||||||
|
$object = new EditableOption();
|
||||||
|
$object->write();
|
||||||
|
$object->ParentID = $parent;
|
||||||
|
$object->Sort = $sort;
|
||||||
|
$object->Name = 'option' . $object->ID;
|
||||||
|
$object->Title = $text;
|
||||||
|
$object->write();
|
||||||
|
return $object->EditSegment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $haveFormOptions = true;
|
protected $haveFormOptions = true;
|
||||||
|
@ -73,7 +73,7 @@ div.FieldEditor div.MenuHolder {
|
|||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.FieldEditor ul li {
|
div.FieldEditor .MenuHolder ul li {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,12 +121,10 @@ div.EditableFormField.mouseOver {
|
|||||||
margin-left: 0px;
|
margin-left: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.EditableFormField div.ExtraOptions {
|
div.EditableFormField div.extraOptions {
|
||||||
display: none;
|
display: none;
|
||||||
margin: 3px 0px 3px 57px;
|
margin: 3px 0px 3px 57px;
|
||||||
background-color: #EEEEEE;
|
background-color: #EEEEEE;
|
||||||
/* IE has background issues without this */
|
|
||||||
/*position: relative;*/
|
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,10 +149,7 @@ div.EditableDateField div.FieldDefault input {
|
|||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
#right #Form_EditForm div.EditableMultiOptionFormField div.FieldDefault ul.EditableDropdownOptions {
|
#right #Form_EditForm div.EditableMultiOptionFormField div.FieldDefault ul.EditableDropdownOptions {
|
||||||
border: solid 1px #7F9DB9;
|
|
||||||
/* IE */
|
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
/* display: none; */
|
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
images/editableliteralfield.png
Normal file
After Width: | Height: | Size: 731 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
@ -1,555 +0,0 @@
|
|||||||
FieldEditor = Class.create();
|
|
||||||
FieldEditor.applyTo('div.FieldEditor');
|
|
||||||
FieldEditor.prototype = {
|
|
||||||
initialize: function() {
|
|
||||||
FieldEditorField.applyToChildren(this, 'div.EditableFormField');
|
|
||||||
FieldEditorHeadingField.applyToChildren(this, 'div.EditableFormHeading');
|
|
||||||
FieldEditorRadioField.applyToChildren(this, 'div.EditableRadioField');
|
|
||||||
FieldEditorCheckboxGroupField.applyToChildren(this, 'div.EditableCheckboxGroupField');
|
|
||||||
FieldEditorDropdown.applyToChildren(this, 'div.EditableDropdown');
|
|
||||||
FieldEditorEmailField.applyToChildren(this, 'div.EditableEmailField');
|
|
||||||
FieldEditorTextField.applyToChildren(this, 'div.EditableTextField');
|
|
||||||
|
|
||||||
if( !Element.hasClassName( this, 'readonly' ) ) {
|
|
||||||
Sortable.create('Fields_fields', {tag: 'div', handle:'handle'});
|
|
||||||
$('Form_EditForm').observeMethod('BeforeSave', this.beforeSave.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
sortFields: function() {
|
|
||||||
var fieldEditor = $('Fields_fields');
|
|
||||||
|
|
||||||
if(fieldEditor) {
|
|
||||||
|
|
||||||
var i, j, div, field, editables = fieldEditor.childNodes;
|
|
||||||
|
|
||||||
for( i = 0; div = editables[i]; i++ ) {
|
|
||||||
if(div.getElementsByTagName) {
|
|
||||||
var fields = div.getElementsByTagName('input');
|
|
||||||
/*fields[fields.length - 1].value = i;*/
|
|
||||||
for( j = 0; field = fields.item(j); j++ ) {
|
|
||||||
if( field.name == div.id + '[Sort]' ) {
|
|
||||||
field.value = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeSave: function() {
|
|
||||||
var fieldEditor = $('Fields_fields');
|
|
||||||
|
|
||||||
if(fieldEditor) {
|
|
||||||
this.sortFields();
|
|
||||||
|
|
||||||
var children = $('Fields_fields').childNodes;
|
|
||||||
|
|
||||||
for( var i = 0; i < children.length; ++i ) {
|
|
||||||
var child = children[i];
|
|
||||||
|
|
||||||
if( child.beforeSave )
|
|
||||||
child.beforeSave();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deleteOption: function( optionToRemove ) {
|
|
||||||
var fields = document.getElementById('Fields_fields');
|
|
||||||
fields.removeChild(optionToRemove);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldEditorField = Class.create();
|
|
||||||
|
|
||||||
FieldEditorField.prototype = {
|
|
||||||
initialize: function() {
|
|
||||||
var fieldInfoDiv = this.findDescendant( 'div', 'FieldInfo' );
|
|
||||||
|
|
||||||
this.titleField = this.findDescendant( 'input', 'text');
|
|
||||||
|
|
||||||
this.titleField.onchange = this.changeTitle.bind(this);
|
|
||||||
this.titleField.onblur = this.changeTitle.bind(this);
|
|
||||||
this.titleField.onfocus = this.focusTitle.bind(this);
|
|
||||||
|
|
||||||
this.titleField.onchange();
|
|
||||||
|
|
||||||
var links = fieldInfoDiv.getElementsByTagName('a');
|
|
||||||
this.toggler = this.findDescendant( 'a', 'toggler' );
|
|
||||||
this.fieldInfo = this.getElementsByTagName('div')[0];
|
|
||||||
|
|
||||||
|
|
||||||
this.toggler.onclick = this.toggle.bind(this);
|
|
||||||
this.extraOptions = this.getExtraOptions();
|
|
||||||
this.visible = false;
|
|
||||||
this.deleteButton = this.findDescendant('a', 'delete');
|
|
||||||
|
|
||||||
//this.style.height = "auto";
|
|
||||||
|
|
||||||
if( this.deleteButton )
|
|
||||||
this.deleteButton.onclick = this.confirmDelete.bind(this);
|
|
||||||
},
|
|
||||||
toggle: function() {
|
|
||||||
// this.parentNode.autoSize();
|
|
||||||
|
|
||||||
if( this.visible )
|
|
||||||
this.hide();
|
|
||||||
else
|
|
||||||
this.show();
|
|
||||||
|
|
||||||
this.fieldInfo.style.display = 'block';
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
show: function() {
|
|
||||||
/*this.style.height = "";
|
|
||||||
this.style.overflow = "";*/
|
|
||||||
|
|
||||||
if( this.selectedOption )
|
|
||||||
this.selectedOption.checked = true;
|
|
||||||
|
|
||||||
this.visible = true;
|
|
||||||
// var extraOptions = this.getExtraOptions();
|
|
||||||
// if( this.extraOptions )
|
|
||||||
this.extraOptions.style.display = 'block';
|
|
||||||
},
|
|
||||||
hide: function() {
|
|
||||||
|
|
||||||
this.visible = false;
|
|
||||||
// var extraOptions = this.getExtraOptions();
|
|
||||||
//if( this.extraOptions )
|
|
||||||
this.extraOptions.style.display = 'none';
|
|
||||||
},
|
|
||||||
getExtraOptions: function() {
|
|
||||||
var extraOptions = this.findDescendant('div', 'ExtraOptions');
|
|
||||||
|
|
||||||
if( extraOptions.parentNode != this )
|
|
||||||
alert("Found extra options but not this parent (" + this.id + ")");
|
|
||||||
|
|
||||||
return extraOptions;
|
|
||||||
},
|
|
||||||
confirmDelete: function() {
|
|
||||||
if( confirm( 'Are you sure you want to delete this field from the form?' ) )
|
|
||||||
this.parentNode.parentNode.parentNode.deleteOption( this );
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
findDescendant: function( tag, clsName, element ) {
|
|
||||||
|
|
||||||
if( !element )
|
|
||||||
element = this;
|
|
||||||
|
|
||||||
var descendants = element.getElementsByTagName(tag);
|
|
||||||
|
|
||||||
for( var i = 0; i < descendants.length; i++ ) {
|
|
||||||
var el = descendants[i];
|
|
||||||
// alert(el.tagName + ' ' + el.className);
|
|
||||||
|
|
||||||
if( tag.toUpperCase() == el.tagName && el.className.indexOf( clsName ) != -1 )
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
focusTitle: function() {
|
|
||||||
if( this.titleField && this.titleField.value == this.titleField.title )
|
|
||||||
this.titleField.value = '';
|
|
||||||
},
|
|
||||||
changeTitle: function() {
|
|
||||||
if( this.titleField && this.titleField.value == '' )
|
|
||||||
this.titleField.value = this.titleField.title;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldEditorHeadingField = Class.extend('FieldEditorField');
|
|
||||||
|
|
||||||
FieldEditorHeadingField.prototype = {
|
|
||||||
initialize: function() {
|
|
||||||
this.FieldEditorField.initialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldEditorEmailField = Class.extend('FieldEditorField');
|
|
||||||
|
|
||||||
|
|
||||||
FieldEditorEmailField.prototype = {
|
|
||||||
initialize: function() {
|
|
||||||
this.extraOptions = this.getExtraOptions();
|
|
||||||
this.defaultText = this.getDefaultText();
|
|
||||||
|
|
||||||
this.FieldEditorField.initialize();
|
|
||||||
},
|
|
||||||
getDefaultText: function() {
|
|
||||||
var defaultField = this.getDefaultField();
|
|
||||||
if(defaultField) {
|
|
||||||
var j, nestedChild, nestedChildren = defaultField.childNodes;
|
|
||||||
for( j=0; nestedChild = nestedChildren[j]; j++) {
|
|
||||||
if (nestedChild.className == 'defaultText' )
|
|
||||||
{
|
|
||||||
return nestedChild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getDefaultField: function() {
|
|
||||||
|
|
||||||
var i, child, children = this.getElementsByTagName('div');
|
|
||||||
for( i = 0; child = children[i]; i++){
|
|
||||||
if(child.className == 'FieldDefault'){
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FieldEditorTextField = Class.extend('FieldEditorField');
|
|
||||||
FieldEditorTextField.prototype = {
|
|
||||||
initialize: function() {
|
|
||||||
this.FieldEditorField.initialize();
|
|
||||||
this.defaultText = this.getDefaultText();
|
|
||||||
this.numRows = this.extraOptions.getElementsByTagName('input')[3];
|
|
||||||
if(this.numRows) {
|
|
||||||
this.numRows.onchange = this.changedRows.bind(this);
|
|
||||||
this.oldNumRows = eval(this.numRows.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
changedRows: function() {
|
|
||||||
var newNumRows = eval(this.numRows.value);
|
|
||||||
|
|
||||||
// TODO Show that the field is actually longer than 5 rows
|
|
||||||
if( newNumRows > 5 )
|
|
||||||
newNumRows == 5;
|
|
||||||
|
|
||||||
if( this.oldNumRows == newNumRows )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( newNumRows < 1 )
|
|
||||||
newNumRows = 1;
|
|
||||||
|
|
||||||
// resize/convert the textarea
|
|
||||||
var newType = '';
|
|
||||||
|
|
||||||
if( newNumRows == 1 )
|
|
||||||
newType = 'input';
|
|
||||||
else
|
|
||||||
newType = 'textarea'
|
|
||||||
|
|
||||||
var newDefaultText = document.createElement(newType);
|
|
||||||
newDefaultText.className = this.defaultText.className;
|
|
||||||
newDefaultText.value = this.defaultText.value;
|
|
||||||
newDefaultText.id = this.defaultText.id;
|
|
||||||
newDefaultText.name = this.defaultText.name;
|
|
||||||
|
|
||||||
if( newDefaultText.rows )
|
|
||||||
newDefaultText.rows = newNumRows;
|
|
||||||
|
|
||||||
//Does not work any more
|
|
||||||
//this.replaceChild( newDefaultText, this.defaultText );
|
|
||||||
|
|
||||||
//instead, using the following code
|
|
||||||
var defaultField = this.getDefaultField();
|
|
||||||
defaultField.replaceChild(newDefaultText, this.defaultText);
|
|
||||||
|
|
||||||
//keep other codes.
|
|
||||||
this.defaultText = newDefaultText;
|
|
||||||
this.oldNumRows = newNumRows;
|
|
||||||
},
|
|
||||||
getDefaultText: function() {
|
|
||||||
var defaultField = this.getDefaultField();
|
|
||||||
|
|
||||||
if(defaultField) {
|
|
||||||
var j, nestedChild, nestedChildren = defaultField.childNodes;
|
|
||||||
for( j=0; nestedChild = nestedChildren[j]; j++) {
|
|
||||||
|
|
||||||
if (nestedChild.className == 'defaultText' )
|
|
||||||
{
|
|
||||||
return nestedChild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getDefaultField: function() {
|
|
||||||
var i, child, children = this.getElementsByTagName('div');
|
|
||||||
for( i = 0; child = children[i]; i++){
|
|
||||||
if(child.className == 'FieldDefault'){
|
|
||||||
return child.getElementsByTagName('div')[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This should extend FieldEditorField
|
|
||||||
*/
|
|
||||||
FieldEditorRadioField = Class.extend('FieldEditorField');
|
|
||||||
|
|
||||||
FieldEditorRadioField.prototype = {
|
|
||||||
initialize: function() {
|
|
||||||
this.FieldEditorField.initialize();
|
|
||||||
|
|
||||||
this.hiddenFields = this.findDescendant( 'div', 'hidden' );
|
|
||||||
|
|
||||||
var dropdownBox = this.findDescendant( 'div', 'EditableDropdownBox' );
|
|
||||||
|
|
||||||
this.optionList = dropdownBox.getElementsByTagName('ul')[0];
|
|
||||||
var options = this.optionList.getElementsByTagName('li');
|
|
||||||
|
|
||||||
if( options && options.length > 0 ) {
|
|
||||||
this.addOptionField = options[options.length - 1];
|
|
||||||
|
|
||||||
if( typeof this.addOptionField != 'undefined' && this.addOptionField.className != "AddDropdownOption" )
|
|
||||||
this.addOptionField = null;
|
|
||||||
|
|
||||||
// bind each option's delete link
|
|
||||||
for( var i = 0; i < options.length - 1; i++ ) {
|
|
||||||
var option = options[i];
|
|
||||||
|
|
||||||
var links = option.getElementsByTagName('a');
|
|
||||||
|
|
||||||
links[0].onclick = this.removeOption.bindAsEventListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind method to add option at the bottom of the list
|
|
||||||
if( this.addOptionField ) {
|
|
||||||
this.addOptionLink = this.addOptionField.getElementsByTagName('a')[0];
|
|
||||||
this.addOptionTitle = this.addOptionField.getElementsByTagName('input')[0];
|
|
||||||
this.addOptionLink.onclick = this.addOption.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !Element.hasClassName( $('Fields'), 'readonly' ) ) {
|
|
||||||
Sortable.create(this.optionList.id,{handle:'handle',tag:'li',only:'EditableFormFieldOption'});
|
|
||||||
}
|
|
||||||
this.FieldEditorField.initialize();
|
|
||||||
|
|
||||||
// find the Delete field
|
|
||||||
var hiddenFields = this.getElementsByTagName('input');
|
|
||||||
|
|
||||||
for( var i = 0; i < hiddenFields.length; i++ ) {
|
|
||||||
var field = hiddenFields[i];
|
|
||||||
if( field.name.indexOf('[Deleted\]' ) != -1 )
|
|
||||||
this.deletedOptions = field;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.selectedOption = null;
|
|
||||||
|
|
||||||
$('Form_EditForm').observeMethod('BeforeSave', this.beforeSave.bind(this));
|
|
||||||
},
|
|
||||||
firstElement: function( el ) {
|
|
||||||
|
|
||||||
var node = el.firstChild;
|
|
||||||
|
|
||||||
while( !node.tagName )
|
|
||||||
node = node.nextSibling;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
},
|
|
||||||
createOption: function( title, id, selected ) {
|
|
||||||
var templateNode = this.firstElement( this.hiddenFields );
|
|
||||||
var newOptionNode = templateNode.cloneNode( true );
|
|
||||||
|
|
||||||
var newNodeChildren = newOptionNode.childNodes;
|
|
||||||
|
|
||||||
for( var i = 0; i < newNodeChildren.length; i++ ) {
|
|
||||||
|
|
||||||
var child = newNodeChildren[i];
|
|
||||||
|
|
||||||
if( !child.tagName )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// input elements
|
|
||||||
if( child.tagName.toLowerCase() == 'input' ) {
|
|
||||||
|
|
||||||
if( child.className == 'text' ) {
|
|
||||||
child.name = this.id + '[' + id + '][Title]';
|
|
||||||
child.value = title;
|
|
||||||
} else if( child.type == 'checkbox' )
|
|
||||||
child.name = this.id + '[' + id + '][Default]';
|
|
||||||
else if( child.type == 'radio' ) {
|
|
||||||
child.value = id;
|
|
||||||
} else if( child.type == 'hidden' ) {
|
|
||||||
child.name = this.id + '[' + id + '][Sort]';
|
|
||||||
child.value = -1;
|
|
||||||
}
|
|
||||||
} else if ( child.tagName.toLowerCase() == 'a' ) {
|
|
||||||
child.onclick = this.removeOption.bindAsEventListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.optionList.insertBefore( newOptionNode, this.addOptionField );
|
|
||||||
},
|
|
||||||
removeOption: function( event ) {
|
|
||||||
|
|
||||||
var target = event.srcElement;
|
|
||||||
|
|
||||||
if( !target )
|
|
||||||
target = event.target;
|
|
||||||
|
|
||||||
var entry = target.parentNode.parentNode;
|
|
||||||
var id = entry.id;
|
|
||||||
|
|
||||||
if( !id.match( '/^[0-9]+$/' ) ) {
|
|
||||||
if( this.deletedOptions.value )
|
|
||||||
this.deletedOptions.value += ',';
|
|
||||||
|
|
||||||
this.deletedOptions.value += id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the child from the options
|
|
||||||
this.optionList.removeChild( entry );
|
|
||||||
|
|
||||||
// remove the child from the dropdown
|
|
||||||
/*for( var i = 0; i < this.dropdown.length; i++ ) {
|
|
||||||
if( this.dropdown.options[i].text == title ) {
|
|
||||||
this.dropdown.remove(i);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if( !Element.hasClassName( $('Fields'), 'readonly' ) )
|
|
||||||
Sortable.create(this.optionList.id,{handle:'handle',tag:'li',only:'EditableFormFieldOption'});
|
|
||||||
|
|
||||||
// return false so it doesn't follow the link
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
addOption: function() {
|
|
||||||
if( this.addOptionTitle.value.length == 0 )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// The IDs come from the database and are the ID of the actual record
|
|
||||||
// client-side, we will need a unique identifier that can be differentiated
|
|
||||||
// from the actual database IDs, unless we just drop all records and
|
|
||||||
// recreate them
|
|
||||||
var newID = '_' + this.optionList.childNodes.length;
|
|
||||||
|
|
||||||
this.createOption( this.addOptionTitle.value, newID, this.optionList.childNodes.length == 0 );
|
|
||||||
|
|
||||||
if( !Element.hasClassName( $('Fields'), 'readonly' ) )
|
|
||||||
Sortable.create(this.optionList.id,{handle:'handle',tag:'li',only:'EditableFormFieldOption'});
|
|
||||||
|
|
||||||
this.addOptionTitle.value = '';
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
beforeSave: function() {
|
|
||||||
this.sortOptions();
|
|
||||||
},
|
|
||||||
sortOptions: function() {
|
|
||||||
var inputTags = this.optionList.getElementsByTagName('input');
|
|
||||||
|
|
||||||
var i,item,sort=0;
|
|
||||||
for(i=0;item=inputTags[i];i++) {
|
|
||||||
if(item.name.match(/\[Sort\]$/) ) {
|
|
||||||
item.value = sort++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectOption: function(newOption) {
|
|
||||||
|
|
||||||
if( this.selectedOption )
|
|
||||||
this.selectedOption.checked = false;
|
|
||||||
|
|
||||||
newOption.checked = true;
|
|
||||||
this.selectedOption = newOption;
|
|
||||||
},
|
|
||||||
selectOptionEvent: function(event) {
|
|
||||||
if(event.srcElement)
|
|
||||||
this.selectOption(event.srcElement);
|
|
||||||
else
|
|
||||||
this.selectOption(event.target);
|
|
||||||
},
|
|
||||||
updateOption: function( prefix, tempID, newID, newSort ) {
|
|
||||||
var options = this.optionList.childNodes;
|
|
||||||
|
|
||||||
for( var i = 0; i < options.length; i++ ) {
|
|
||||||
var option = options[i];
|
|
||||||
|
|
||||||
var fields = option.getElementsByTagName('input');
|
|
||||||
|
|
||||||
for( var j = 0; j < fields.length; j++ ) {
|
|
||||||
var field = fields[j];
|
|
||||||
|
|
||||||
var oldPrefix = prefix + '[' + tempID + ']';
|
|
||||||
var newPrefix = prefix + '[' + newID + ']';
|
|
||||||
|
|
||||||
if( field.name.indexOf( oldPrefix ) == 0 ) {
|
|
||||||
|
|
||||||
if( field.name.match( /\[Sort\]$/ ) )
|
|
||||||
field.value = newSort;
|
|
||||||
|
|
||||||
// rename the field
|
|
||||||
field.name = newPrefix + field.name.substring( oldPrefix.length );
|
|
||||||
|
|
||||||
} else if( field.name == prefix + '[Default]' ) {
|
|
||||||
field.value = newID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldEditorCheckboxGroupField = Class.extend('FieldEditorRadioField');
|
|
||||||
|
|
||||||
FieldEditorDropdown = Class.extend('FieldEditorRadioField');
|
|
||||||
|
|
||||||
Behaviour.register({
|
|
||||||
|
|
||||||
'div.FieldEditor ul.Menu li a': {
|
|
||||||
urlForFieldMethod: function(methodName) {
|
|
||||||
return this.ownerForm().action + '/field/Fields/' + methodName + '?NewID=' + this.numNewFields;
|
|
||||||
},
|
|
||||||
ownerForm: function() {
|
|
||||||
var f = this.parentNode;
|
|
||||||
while(f && f.tagName.toLowerCase() != 'form') f = f.parentNode;
|
|
||||||
return f;
|
|
||||||
},
|
|
||||||
|
|
||||||
onclick: function() {
|
|
||||||
// get the ID of the field editor here
|
|
||||||
|
|
||||||
if( Element.hasClassName( $('Fields'), 'readonly' ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
action = this.urlForFieldMethod("addfield") + "&Type=" + this.id + ($('SecurityID') ? '&SecurityID=' + $('SecurityID').value : '');;
|
|
||||||
|
|
||||||
statusMessage('Adding new field' );
|
|
||||||
|
|
||||||
new Ajax.Request(action, {
|
|
||||||
method: 'get',
|
|
||||||
onFailure: reportError,
|
|
||||||
onSuccess: this.appendNewField.bind(this)
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
appendNewField: function(response) {
|
|
||||||
this.numNewFields++;
|
|
||||||
|
|
||||||
var el = document.createElement('div');
|
|
||||||
el.innerHTML = response.responseText;
|
|
||||||
|
|
||||||
var i=0;
|
|
||||||
while(!el.childNodes[i].tagName) i++;
|
|
||||||
var newField = el.childNodes[i];
|
|
||||||
$('Fields_fields').appendChild(newField);
|
|
||||||
|
|
||||||
// Behaviour.debug();
|
|
||||||
if(newField) {
|
|
||||||
Behaviour.apply(newField,true);
|
|
||||||
FieldEditor.applyTo('div.FieldEditor');
|
|
||||||
}
|
|
||||||
|
|
||||||
// do we want to make sorting explicit?
|
|
||||||
Sortable.create('Fields_fields', {tag: 'div', handle:'handle'});
|
|
||||||
|
|
||||||
statusMessage('Added new field','good');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function reportError(request){
|
|
||||||
// More complex error for developers
|
|
||||||
statusMessage(request.responseText,'bad');
|
|
||||||
|
|
||||||
}
|
|
@ -1,5 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Javascript required to power the user defined forms.
|
||||||
|
*
|
||||||
|
* Rewritten and refactored from the prototype version FieldEditor.
|
||||||
|
*
|
||||||
|
* @todo Upgrade to jQuery 1.3 so we can use live rather
|
||||||
|
* then livequery
|
||||||
|
*/
|
||||||
(function($) {
|
(function($) {
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
/*--------------------- SUBMISSIONS ------------------------ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a given Submission from the form, or all submissions
|
||||||
|
* we let the href of the delete link to do all the work for us
|
||||||
|
*/
|
||||||
|
|
||||||
$("#FormSubmissions .deleteSubmission").click(function() {
|
$("#FormSubmissions .deleteSubmission").click(function() {
|
||||||
var deletedSubmission = $(this);
|
var deletedSubmission = $(this);
|
||||||
$.post($(this).attr('href'), function(data) {
|
$.post($(this).attr('href'), function(data) {
|
||||||
@ -7,5 +23,126 @@
|
|||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*-------------------- 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 ul.Menu li a").livequery('click',function() {
|
||||||
|
|
||||||
|
// if this form is readonly...
|
||||||
|
if($("#Fields").hasClass('readonly')) return false;
|
||||||
|
|
||||||
|
// Give the user some feedback
|
||||||
|
statusMessage(ss.i18n._t('UserForms.ADDINGNEWFIELD', 'Adding New Field'));
|
||||||
|
|
||||||
|
// variables
|
||||||
|
var action = $("#Form_EditForm").attr("action") + '/field/Fields/addfield';
|
||||||
|
var length = $(".FieldInfo").length + 1;
|
||||||
|
var securityID = ($("#SecurityID")) ? '&SecurityID='+$("#SecurityID").attr("value") : '';
|
||||||
|
var type = $(this).attr("ID");
|
||||||
|
|
||||||
|
//send ajax request to the page
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: action,
|
||||||
|
data: 'NewID='+ length +"&Type="+ type + securityID,
|
||||||
|
|
||||||
|
// create a new field
|
||||||
|
success: function(msg){
|
||||||
|
$('#Fields_fields').append(msg);
|
||||||
|
statusMessage(ss.i18n._t('UserForms.ADDEDNEWFIELD', 'Added New Field'));
|
||||||
|
},
|
||||||
|
|
||||||
|
// error creating new field
|
||||||
|
error: function(request, text, error) {
|
||||||
|
statusMessage(ss.i18n._t('UserForms.ERRORCREATINGFIELD', 'Error Creating Field'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the more options popdown. Or hide it if we
|
||||||
|
* currently have it open
|
||||||
|
*/
|
||||||
|
$(".EditableFormField .moreOptions").livequery('click',function() {
|
||||||
|
var parentID = $(this).parents(".EditableFormField");
|
||||||
|
if(parentID) {
|
||||||
|
var extraOptions = parentID.children(".extraOptions");
|
||||||
|
if(extraOptions) {
|
||||||
|
if(extraOptions.hasClass('hidden')) {
|
||||||
|
extraOptions.removeClass('hidden').show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
extraOptions.addClass('hidden').hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a field from the user defined form
|
||||||
|
*/
|
||||||
|
$(".EditableFormField .delete").livequery('click', function() {
|
||||||
|
$(this).parents(".EditableFormField").remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a suboption to a radio field or to a dropdown box
|
||||||
|
* for example
|
||||||
|
*/
|
||||||
|
$(".EditableFormField .addableOption").livequery('click', function() {
|
||||||
|
|
||||||
|
// Give the user some feedback
|
||||||
|
statusMessage(ss.i18n._t('UserForms.ADDINGNEWFIELD', 'Adding New Option'));
|
||||||
|
|
||||||
|
// variables
|
||||||
|
var options = $(this).parent("li");
|
||||||
|
var action = $("#Form_EditForm").attr("action") + '/field/Fields/addoptionfield';
|
||||||
|
var parent = $(this).attr("rel");
|
||||||
|
var text = $(this).parents("li").children(".text").val();
|
||||||
|
|
||||||
|
// clear input
|
||||||
|
$(this).parents("li").children(".text").val("");
|
||||||
|
|
||||||
|
//send ajax request to the page
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: action,
|
||||||
|
data: 'Parent='+ parent +"&Text="+ text,
|
||||||
|
|
||||||
|
// create a new field
|
||||||
|
success: function(msg){
|
||||||
|
options.before(msg);
|
||||||
|
statusMessage(ss.i18n._t('UserForms.ADDEDNEWFIELD', 'Added New Field'));
|
||||||
|
},
|
||||||
|
|
||||||
|
// error creating new field
|
||||||
|
error: function(request, text, error) {
|
||||||
|
statusMessage(ss.i18n._t('UserForms.ERRORCREATINGFIELD', 'Error Creating Field'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a suboption such as an dropdown option or a
|
||||||
|
* checkbox field
|
||||||
|
*/
|
||||||
|
$(".EditableFormField .deleteOption").livequery('click', function() {
|
||||||
|
// pass the deleted status onto the element
|
||||||
|
$(this).parents("li").children("[type=text]").attr("value", "field-node-deleted");
|
||||||
|
$(this).parents("li").hide();
|
||||||
|
|
||||||
|
// Give the user some feedback
|
||||||
|
statusMessage(ss.i18n._t('UserForms.REMOVINGOPTION', 'Removed Option'));
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
})
|
})
|
||||||
})(jQuery);
|
(jQuery);
|
@ -1,26 +0,0 @@
|
|||||||
<div class="EditableCheckbox EditableFormField" id="$Name.Attr">
|
|
||||||
<div class="FieldInfo">
|
|
||||||
<% if isReadonly %>
|
|
||||||
<img class="handle" src="sapphire/images/drag-readonly.gif" alt="<% _t('LOCKED', 'This field cannot be modified') %>" />
|
|
||||||
<% else %>
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
<img class="icon" src="userforms/images/fe_icons/checkbox.png" alt="<% _t('CHECKBOX', 'Checkbox field') %>" />
|
|
||||||
$TitleField
|
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
<a class="delete" href="#" title="<% _t('DELETE', 'Delete this field') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete this field') %>" /></a>
|
|
||||||
</div>
|
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
|
||||||
<div class="FieldDefault">
|
|
||||||
<label>
|
|
||||||
$CheckboxField
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<% control ExtraOptions %>
|
|
||||||
$FieldHolder
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="EditableCheckbox" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
|
||||||
</div>
|
|
@ -1,51 +0,0 @@
|
|||||||
<div class="EditableCheckboxGroupField EditableMultiOptionFormField EditableFormField" id="$Name.Attr">
|
|
||||||
<div class="FieldInfo">
|
|
||||||
<% if isReadonly %>
|
|
||||||
<img class="handle" src="sapphire/images/drag_readonly.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% else %>
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
<img class="icon" src="userforms/images/fe_icons/checkboxes.png" alt="<% _t('CHECKBOXGROUP', 'Checkbox group') %>" title="<% _t('CHECKBOXGROUP', 'Checkbox group') %>" />
|
|
||||||
$TitleField
|
|
||||||
<input type="hidden" name="hiddenDefaultOption" value="$DefaultOption" />
|
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
<% if isReadonly %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% else %>
|
|
||||||
<% if CanDelete %>
|
|
||||||
<a class="delete" href="#" title="<% _t('DELETE', 'Delete this field') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete this field') %>" /></a>
|
|
||||||
<% else %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('REQUIRED', 'This field is required for this form and cannot be deleted') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
<% end_if %>
|
|
||||||
</div>
|
|
||||||
<div class="hidden">
|
|
||||||
$TemplateOption
|
|
||||||
</div>
|
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
|
||||||
<div class="EditableDropdownBox FieldDefault">
|
|
||||||
<ul class="EditableDropdownOptions" id="$Name.Attr-list">
|
|
||||||
<% if isReadonly %>
|
|
||||||
<% control Options %>
|
|
||||||
$ReadonlyOption
|
|
||||||
<% end_control %>
|
|
||||||
<% else %>
|
|
||||||
<% control Options %>
|
|
||||||
$Option
|
|
||||||
<% end_control %>
|
|
||||||
<li class="AddDropdownOption">
|
|
||||||
<input class="text" type="text" name="$Name.Attr[NewOption]" value="" />
|
|
||||||
<a href="#" title="<% _t('ADD', 'Add option to field') %>"><img src="cms/images/add.gif" alt="<% _t('ADD', 'Add new option') %>" /></a>
|
|
||||||
</li>
|
|
||||||
<% end_if %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<% control ExtraOptions %>
|
|
||||||
$FieldHolder
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="$Name.Attr[Deleted]" value="" />
|
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="EditableCheckboxGroupField" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
|
||||||
</div>
|
|
@ -1,10 +0,0 @@
|
|||||||
<li>
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of options') %>" />
|
|
||||||
<input type="radio" name="$Name.Attr[Default]" value="$ID" />
|
|
||||||
<input type="text" name="$Name.Attr[Title]" value="$Title.Attr" />
|
|
||||||
<% if isReadonly %>
|
|
||||||
<a href="#"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Remove this option') %>" /></a>
|
|
||||||
<% else %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
</li>
|
|
@ -1,20 +0,0 @@
|
|||||||
<div id="$Name.Attr" class="EditableDateField EditableFormField">
|
|
||||||
<div class="FieldInfo">
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
<img class="icon" src="userforms/images/fe_icons/date-time.png" alt="<% _t('DATE', 'Date Field') %>" />
|
|
||||||
$TitleField
|
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
<a class="delete" href="#" title="<% _t('DELETE', 'Delete this field') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete this field') %>" /></a>
|
|
||||||
</div>
|
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
|
||||||
<div class="FieldDefault">
|
|
||||||
$DefaultField
|
|
||||||
</div>
|
|
||||||
<% control ExtraOptions %>
|
|
||||||
$FieldHolder
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="EditableDateField" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
|
||||||
</div>
|
|
@ -1,50 +0,0 @@
|
|||||||
<div class="EditableDropdown EditableMultiOptionFormField EditableFormField" id="$Name.Attr">
|
|
||||||
<div class="FieldInfo">
|
|
||||||
<% if isReadonly %>
|
|
||||||
<img class="handle" src="sapphire/images/drag_readonly.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% else %>
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
<img class="icon" src="userforms/images/fe_icons/dropdown.png" alt="<% _t('DROPDOWN', 'Dropdown box') %>" title="<% _t('DROPDOWN', 'Dropdown box') %>"/>
|
|
||||||
$TitleField
|
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
<% if isReadonly %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% else %>
|
|
||||||
<% if CanDelete %>
|
|
||||||
<a class="delete" href="#" title="<% _t('DELETE', 'Delete this field') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete this field') %>" /></a>
|
|
||||||
<% else %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('REQUIRED', 'This field is required for this form and cannot be deleted') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
<% end_if %>
|
|
||||||
</div>
|
|
||||||
<div class="hidden">
|
|
||||||
$TemplateOption
|
|
||||||
</div>
|
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
|
||||||
<div class="EditableDropdownBox FieldDefault">
|
|
||||||
<ul class="EditableDropdownOptions" id="$Name.Attr-list">
|
|
||||||
<% if isReadonly %>
|
|
||||||
<% control Options %>
|
|
||||||
$ReadonlyOption
|
|
||||||
<% end_control %>
|
|
||||||
<% else %>
|
|
||||||
<% control Options %>
|
|
||||||
$Option
|
|
||||||
<% end_control %>
|
|
||||||
<li class="AddDropdownOption">
|
|
||||||
<input class="text" type="text" name="$Name.Attr[NewOption]" value="" />
|
|
||||||
<a href="#" title="<% _t('ADD', 'Add option to field') %>"><img src="cms/images/add.gif" alt="<% _t('ADD', 'Add new option') %>" /></a>
|
|
||||||
</li>
|
|
||||||
<% end_if %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<% control ExtraOptions %>
|
|
||||||
$FieldHolder
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="$Name.Attr[Deleted]" value="" />
|
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="EditableDropdown" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
|
||||||
</div>
|
|
@ -1,10 +0,0 @@
|
|||||||
<li>
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of options') %>" />
|
|
||||||
<input type="text" name="$Name.Attr[Title]" value="$Title.Attr" />
|
|
||||||
<input type="radio" name="$Name.Attr[Default]" value="$ID" />
|
|
||||||
<% if isReadonly %>
|
|
||||||
<a href="#"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Remove this option') %>" /></a>
|
|
||||||
<% else %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
</li>
|
|
@ -1,25 +0,0 @@
|
|||||||
<div class="EditableEmailField EditableFormField" id="$Name.Attr">
|
|
||||||
<div class="FieldInfo">
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
<img class="icon" src="userforms/images/fe_icons/text-email.png" alt="<% _t('EMAIL', 'Email address field') %>" />
|
|
||||||
$TitleField
|
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
<% if CanDelete %>
|
|
||||||
<a class="delete" href="#" title="<% _t('DELETE', 'Delete this field') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete this field') %>" /></a>
|
|
||||||
<% else %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('REQUIRED', 'This field is required for this form and cannot be deleted') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
</div>
|
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
|
||||||
<div class="FieldDefault">
|
|
||||||
$DefaultField
|
|
||||||
</div>
|
|
||||||
<% control ExtraOptions %>
|
|
||||||
$FieldHolder
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="$Name.Attr[CanDelete]" value="$CanDelete" />
|
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="EditableEmailField" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
|
||||||
</div>
|
|
@ -1,20 +0,0 @@
|
|||||||
<div id="$Name.Attr" class="EditableFormField EditableFileField">
|
|
||||||
<div class="FieldInfo">
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
<img class="icon" src="userforms/images/fe_icons/file-upload.png" alt="<% _t('FILE', 'File upload field') %>" />
|
|
||||||
$TitleField
|
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
<a class="delete" href="#" title="<% _t('DELETE', 'Delete this field') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete this field') %>" /></a>
|
|
||||||
</div>
|
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
|
||||||
<div class="FieldDefault">
|
|
||||||
$DefaultField
|
|
||||||
</div>
|
|
||||||
<% control ExtraOptions %>
|
|
||||||
$FieldHolder
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="EditableFileField" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
|
||||||
</div>
|
|
@ -5,9 +5,17 @@
|
|||||||
<% else %>
|
<% else %>
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
||||||
<% end_if %>
|
<% end_if %>
|
||||||
|
|
||||||
<img class="icon" src="userforms/images/fe_icons/{$ClassName.LowerCase}.png" alt="$ClassName" title="$singular_name" />
|
<img class="icon" src="userforms/images/fe_icons/{$ClassName.LowerCase}.png" alt="$ClassName" title="$singular_name" />
|
||||||
|
|
||||||
$TitleField
|
$TitleField
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
|
<% if showExtraOptions %>
|
||||||
|
<a class="moreOptions" href="#" title="<% _t('MORE', 'More options') %>">
|
||||||
|
<img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" />
|
||||||
|
</a>
|
||||||
|
<% end_if %>
|
||||||
|
|
||||||
<% if isReadonly %>
|
<% if isReadonly %>
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
<img src="cms/images/locked.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
||||||
<% else %>
|
<% else %>
|
||||||
@ -18,25 +26,34 @@
|
|||||||
<% end_if %>
|
<% end_if %>
|
||||||
<% end_if %>
|
<% end_if %>
|
||||||
</div>
|
</div>
|
||||||
<% if Options %>
|
|
||||||
<div class="hidden">
|
<% if showExtraOptions %>
|
||||||
<% control Options %>
|
<div class="extraOptions hidden" id="$Name.Attr-extraOptions">
|
||||||
|
<ul class="editableOptions" id="$Name.Attr-list">
|
||||||
|
|
||||||
<% if isReadonly %>
|
<% if isReadonly %>
|
||||||
|
<% control Options %>
|
||||||
$ReadonlyOption
|
$ReadonlyOption
|
||||||
<% else %>
|
|
||||||
$Option
|
|
||||||
<% end_if %>
|
|
||||||
<% end_control %>
|
<% end_control %>
|
||||||
</div>
|
<% else %>
|
||||||
|
<% control Options %>
|
||||||
|
$EditSegment
|
||||||
|
<% end_control %>
|
||||||
|
<% if hasAddableOptions %>
|
||||||
|
<li class="{$ClassName}Option">
|
||||||
|
<input class="text" type="text" name="$Name.Attr[NewOption]" value="" />
|
||||||
|
<a href="#" rel="$ID" class="addableOption" title="<% _t('ADD', 'Add option to field') %>"><img src="cms/images/add.gif" alt="<% _t('ADD', 'Add new option') %>" /></a>
|
||||||
|
</li>
|
||||||
<% end_if %>
|
<% end_if %>
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
<% end_if %>
|
||||||
<div class="FieldDefault">
|
</ul>
|
||||||
$DefaultField
|
|
||||||
</div>
|
|
||||||
<% control ExtraOptions %>
|
<% control ExtraOptions %>
|
||||||
$FieldHolder
|
$FieldHolder
|
||||||
<% end_control %>
|
<% end_control %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end_if %>
|
||||||
|
|
||||||
<input type="hidden" name="$Name.Attr[CanDelete]" value="$CanDelete" />
|
<input type="hidden" name="$Name.Attr[CanDelete]" value="$CanDelete" />
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="$ClassName" />
|
<input type="hidden" name="$Name.Attr[Type]" value="$ClassName" />
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
<li class="EditableFormFieldOption" id="$ID">
|
|
||||||
<% if isReadonly %>
|
|
||||||
<img class="handle" src="sapphire/images/drag_readonly.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
$DefaultSelect
|
|
||||||
<input class="text" type="text" name="$Name.Attr[Title]" value="$Title.Att" disabled="disabled" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="$ID" />
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% else %>
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
$DefaultSelect
|
|
||||||
<input class="text" type="text" name="$Name.Attr[Title]" value="$Title.Att" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="$ID" />
|
|
||||||
<a href="#"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Remove this option') %>" /></a>
|
|
||||||
<% end_if %>
|
|
||||||
</li>
|
|
@ -1,17 +0,0 @@
|
|||||||
<div class="EditableFormHeading EditableFormField" id="$Name.Attr">
|
|
||||||
<div class="FieldInfo">
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
<img class="icon" src="userforms/images/fe_icons/heading.png" alt="<% _t('HEADING', 'Heading field') %>" />
|
|
||||||
$TitleField
|
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
<a class="delete" href="#" title="<% _t('DELETE', 'Delete this field') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete this field') %>" /></a>
|
|
||||||
</div>
|
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
|
||||||
<% control ExtraOptions %>
|
|
||||||
$FieldHolder
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="EditableFormHeading" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
|
||||||
</div>
|
|
@ -1,20 +0,0 @@
|
|||||||
<div class="EditableLiteralField EditableFormField" id="$Name.Attr">
|
|
||||||
<div class="FieldInfo">
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
<img class="icon" src="userforms/images/fe_icons/literal.png" alt="<% _t('LITERALFIELD', 'Literal Field') %>" />
|
|
||||||
$TitleField
|
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
<a class="delete" href="#" title="<% _t('DELETE', 'Delete this field') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete this field') %>" /></a>
|
|
||||||
</div>
|
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
|
||||||
<div class="FieldDefault" id="$Name.Attr-fieldDefault">
|
|
||||||
$DefaultField
|
|
||||||
</div>
|
|
||||||
<% control ExtraOptions %>
|
|
||||||
$FieldHolder
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="EditableLiteralField" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
|
||||||
</div>
|
|
11
templates/EditableOption.ss
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<li>
|
||||||
|
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of options') %>" />
|
||||||
|
$DefaultSelect
|
||||||
|
<input type="text" name="$Name.Attr[Title]" value="$Title" />
|
||||||
|
|
||||||
|
<% if isReadonly %>
|
||||||
|
<img src="cms/images/locked.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
||||||
|
<% else %>
|
||||||
|
<a href="$ID" class="deleteOption"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Remove this option') %>" /></a>
|
||||||
|
<% end_if %>
|
||||||
|
</li>
|
@ -1,51 +0,0 @@
|
|||||||
<div class="EditableRadioField EditableMultiOptionFormField EditableFormField" id="$Name.Attr">
|
|
||||||
<div class="FieldInfo">
|
|
||||||
<% if isReadonly %>
|
|
||||||
<img class="handle" src="sapphire/images/drag_readonly.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% else %>
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
<img class="handle" src="userforms/images/fe_icons/radio.png" alt="<% _t('SET', 'Radio button set') %>" title="<% _t('SET', 'Radio button set') %>" />
|
|
||||||
$TitleField
|
|
||||||
<input type="hidden" name="hiddenDefaultOption" value="$DefaultOption" />
|
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
<% if isReadonly %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% else %>
|
|
||||||
<% if CanDelete %>
|
|
||||||
<a class="delete" href="#" title="<% _t('DELETE', 'Delete this field') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete this field') %>" /></a>
|
|
||||||
<% else %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('REQUIRED', 'This field is required for this form and cannot be deleted') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
<% end_if %>
|
|
||||||
</div>
|
|
||||||
<div class="hidden">
|
|
||||||
$TemplateOption
|
|
||||||
</div>
|
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
|
||||||
<div class="EditableDropdownBox FieldDefault">
|
|
||||||
<ul class="EditableDropdownOptions" id="$Name.Attr-list">
|
|
||||||
<% if isReadonly %>
|
|
||||||
<% control Options %>
|
|
||||||
$ReadonlyOption
|
|
||||||
<% end_control %>
|
|
||||||
<% else %>
|
|
||||||
<% control Options %>
|
|
||||||
$Option
|
|
||||||
<% end_control %>
|
|
||||||
<li class="AddDropdownOption">
|
|
||||||
<input class="text" type="text" name="$Name.Attr[NewOption]" value="" />
|
|
||||||
<a href="#" title="<% _t('ADD', 'Add option to field') %>"><img src="cms/images/add.gif" alt="<% _t('ADD', 'Add new option') %>" /></a>
|
|
||||||
</li>
|
|
||||||
<% end_if %>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<% control ExtraOptions %>
|
|
||||||
$FieldHolder
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="$Name.Attr[Deleted]" value="" />
|
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="EditableRadioField" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
|
||||||
</div>
|
|
@ -1,10 +0,0 @@
|
|||||||
<li>
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of options') %>" />
|
|
||||||
<input type="radio" name="$Name.Attr[Default]" value="$ID" />
|
|
||||||
<input type="text" name="$Name.Attr[Title]" value="$Title.Attr" />
|
|
||||||
<% if isReadonly %>
|
|
||||||
<a href="#"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Remove this option') %>" /></a>
|
|
||||||
<% else %>
|
|
||||||
<img src="cms/images/locked.gif" alt="<% _t('LOCKED', 'These fields cannot be modified') %>" />
|
|
||||||
<% end_if %>
|
|
||||||
</li>
|
|
@ -1,20 +0,0 @@
|
|||||||
<div class="EditableTextField EditableFormField" id="$Name.Attr">
|
|
||||||
<div class="FieldInfo">
|
|
||||||
<img class="handle" src="sapphire/images/drag.gif" alt="<% _t('DRAG', 'Drag to rearrange order of fields') %>" />
|
|
||||||
<img class="icon" src="userforms/images/fe_icons/text.png" alt="<% _t('TEXTFIELD', 'Text Field') %>" />
|
|
||||||
$TitleField
|
|
||||||
<a class="toggler" href="#" title="<% _t('MORE', 'More options') %>"><img src="cms/images/edit.gif" alt="<% _t('MORE', 'More options') %>" /></a>
|
|
||||||
<a class="delete" href="#" title="<% _t('DELETE', 'Delete this field') %>"><img src="cms/images/delete.gif" alt="<% _t('DELETE', 'Delete this field') %>" /></a>
|
|
||||||
</div>
|
|
||||||
<div class="ExtraOptions" id="$Name.Attr-extraOptions">
|
|
||||||
<div class="FieldDefault" id="$Name.Attr-fieldDefault">
|
|
||||||
$DefaultField
|
|
||||||
</div>
|
|
||||||
<% control ExtraOptions %>
|
|
||||||
$FieldHolder
|
|
||||||
<% end_control %>
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="$Name.Attr[CustomParameter]" value="$CustomParameter" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Type]" value="EditableTextField" />
|
|
||||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
|
||||||
</div>
|
|
28
tests/UserDefinedFormTest.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various tests for the user defined forms.
|
||||||
|
* Does not test the user interface in the admin.
|
||||||
|
*
|
||||||
|
* @todo Add more comprehensive tests
|
||||||
|
* @package userforms
|
||||||
|
*/
|
||||||
|
|
||||||
|
class UserDefinedFormTest extends SapphireTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic Test creating all the editable form fields
|
||||||
|
*/
|
||||||
|
function testCreatingAllFields() {
|
||||||
|
$fields = ClassInfo::subclassesFor('EditableFormField');
|
||||||
|
foreach($fields as $field) {
|
||||||
|
$object = new $field();
|
||||||
|
$object->Name = "$field";
|
||||||
|
$object->Title = "$field";
|
||||||
|
$object->write();
|
||||||
|
|
||||||
|
$this->assertEquals($field, $object->Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|