diff --git a/code/editor/EditableButton.php b/code/editor/EditableButton.php
index b03d97d..ae796f7 100755
--- a/code/editor/EditableButton.php
+++ b/code/editor/EditableButton.php
@@ -1,9 +1,9 @@
readonly = true;
- return $this->Option();
- }
-
- function isReadonly() {
- return $this->readonly;
- }
-
- static $has_many = array(
- "Options" => "EditableCheckboxOption"
- );
-
static $singular_name = "Checkbox group";
+
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() {
$defaultOption = 0;
@@ -98,14 +25,6 @@ class EditableCheckboxGroupField extends EditableFormField {
return -1;
}
- function getFormField() {
- return $this->createField();
- }
-
- function getFilterField() {
- return $this->createField( true );
- }
-
function createField($asFilter = false) {
$optionSet = $this->Options();
$options = array();
@@ -127,7 +46,7 @@ class EditableCheckboxGroupField extends EditableFormField {
$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) {
if(!$result) {
$result = $selected->Title;
@@ -138,11 +57,6 @@ class EditableCheckboxGroupField extends EditableFormField {
return $result;
}
-
- function TemplateOption() {
- $option = new EditableCheckboxOption();
- return $option->EditSegment();
- }
}
?>
\ No newline at end of file
diff --git a/code/editor/EditableCheckboxOption.php b/code/editor/EditableCheckboxOption.php
deleted file mode 100755
index 24a4f3f..0000000
--- a/code/editor/EditableCheckboxOption.php
+++ /dev/null
@@ -1,82 +0,0 @@
- "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 ' ';*/
-
- 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 " ParentID}][{$this->ID}][Default]\" value=\"1\"".$disabled.$default." />";
- }
-}
-?>
\ No newline at end of file
diff --git a/code/editor/EditableDateField.php b/code/editor/EditableDateField.php
index ae21e3a..b982fe1 100755
--- a/code/editor/EditableDateField.php
+++ b/code/editor/EditableDateField.php
@@ -1,9 +1,10 @@
"EditableDropdownOption"
- );
+class EditableDropdown extends EditableMultipleOptionField {
static $singular_name = 'Dropdown';
+
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();
$options = array();
- if( $asFilter )
+ if($asFilter) {
$options['-1'] = "(Any)";
-
+ }
$defaultOption = '-1';
foreach( $optionSet as $option ) {
$options[$option->Title] = $option->Title;
- if( $option->getField('Default') && !$asFilter ) $defaultOption = $option->Title;
+ if($option->getField('Default') && !$asFilter) $defaultOption = $option->Title;
}
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;
- }
+
}
?>
diff --git a/code/editor/EditableDropdownOption.php b/code/editor/EditableDropdownOption.php
deleted file mode 100755
index 7d1bfd0..0000000
--- a/code/editor/EditableDropdownOption.php
+++ /dev/null
@@ -1,77 +0,0 @@
-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 ' ';*/
-
- return $this->EditSegment();
- }
-
- function DefaultSelect() {
- $disabled = ($this->readonly) ? " disabled=\"disabled\"" : '';
-
- $default = ($this->Parent()->getField('Default') == $this->ID) ? " checked=\"checked\"" : "";
-
- return " ParentID}][Default]\" value=\"{$this->ID}\"".$disabled.$default." />";
- }
-}
-?>
diff --git a/code/editor/EditableEmailField.php b/code/editor/EditableEmailField.php
index 7c247de..cf96398 100755
--- a/code/editor/EditableEmailField.php
+++ b/code/editor/EditableEmailField.php
@@ -1,9 +1,10 @@
"Int",
"Required" => "Boolean",
"CanDelete" => "Boolean",
- "CustomParameter" => "Varchar"
+ "CustomParameter" => "Varchar",
+ "OptionallyDisplay" => "Boolean"
);
static $defaults = array(
@@ -26,19 +28,36 @@ class EditableFormField extends DataObject {
"Parent" => "SiteTree",
);
+ /**
+ * @var bool Is this field readonly to the user
+ */
protected $readonly;
+ /**
+ * @var FieldEditor The current editor
+ */
protected $editor;
-
- function setEditor( $editor ) {
- $this->editor = $editor;
- }
-
- function __construct( $record = null, $isSingleton = false ) {
+
+ /**
+ * Construct a new EditableFormField Object.
+ *
+ * @param array|null $record This will be null for a new database record.
+ * @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);
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() {
return $this->renderWith('EditableFormField');
}
@@ -51,6 +70,26 @@ class EditableFormField extends DataObject {
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() {
$this->readonly = true;
return $this;
@@ -62,15 +101,8 @@ class EditableFormField extends DataObject {
}
function TitleField() {
- // return new TextField( "Fields[".$this->ID."][Title]", null, $this->Title );
$titleAttr = Convert::raw2att($this->Title);
- $readOnlyAttr = '';
-
- if( $this->readonly ) {
- $readOnlyAttr = ' disabled="disabled"';
- } else {
- $readOnlyAttr = '';
- }
+ $readOnlyAttr = ($this->readonly) ? ' disabled="disabled"' : '';
return " ID}][Title]\"$readOnlyAttr />";
}
@@ -79,25 +111,23 @@ class EditableFormField extends DataObject {
return "Fields[".$this->ID."]";
}
- /*function getName() {
- return "field" . $this->ID;
- }*/
-
- function populateFromPostData( $data ) {
-
- $this->Title = isset($data['Title']) ? $data['Title']: "";
-
- if(isset($data['Default'])) {
- $this->setField('Default', $data['Default']);
- }
-
+ /**
+ * How to save the data submitted in this field into
+ * the database object which this field represents.
+ *
+ * Any class's which call this should also call
+ * {@link parent::populateFromPostData()} to ensure
+ * that this method is called
+ *
+ * @access public
+ */
+ 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->CustomParameter = isset($data['CustomParameter']) ? $data['CustomParameter'] : null;
$this->Required = !empty($data['Required']) ? 1 : 0;
$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->write();
}
@@ -107,22 +137,28 @@ class EditableFormField extends DataObject {
$baseName = "Fields[$this->ID]";
$extraOptions = new FieldSet();
- if( !$this->Parent()->hasMethod( 'hideExtraOption' ) ){
- $extraOptions->push( new CheckboxField($baseName . "[Required]", _t('EditableFormField.REQUIRED', 'Required?'), $this->Required) );
- }elseif( !$this->Parent()->hideExtraOption( 'Required' ) ){
- $extraOptions->push( new CheckboxField($baseName . "[Required]", _t('EditableFormField.REQUIRED', 'Required?'), $this->Required) );
+ if(!$this->Parent()->hasMethod('hideExtraOption')){
+ $extraOptions->push(new CheckboxField($baseName . "[Required]", _t('EditableFormField.REQUIRED', 'Required?'), $this->Required));
+ }
+ elseif(!$this->Parent()->hideExtraOption('Required')){
+ $extraOptions->push(new CheckboxField($baseName . "[Required]", _t('EditableFormField.REQUIRED', 'Required?'), $this->Required));
}
- if( $this->Parent()->hasMethod( 'getExtraOptionsForField' ) ) {
- $extraFields = $this->Parent()->getExtraOptionsForField( $this );
+ if($this->Parent()->hasMethod('getExtraOptionsForField')) {
+ $extraFields = $this->Parent()->getExtraOptionsForField($this);
- foreach( $extraFields as $extraField )
- $extraOptions->push( $extraField );
+ foreach($extraFields as $extraField) {
+ $extraOptions->push($extraField);
+ }
}
- if( $this->readonly )
+ if($this->readonly) {
$extraOptions = $extraOptions->makeReadonly();
-
+ }
+
+ // support for optionally display field
+ // $extraOptions->push(new CheckboxField($baseName ."[OptionallyDisplay]", _t('EditableFormField.OPTIONALLYDISPLAY', 'Optionally Display Field'), $this->OptionallyDisplay));
+
return $extraOptions;
}
@@ -159,7 +195,6 @@ class EditableFormField extends DataObject {
protected function parsePrepopulateValue( $value ) {
$paramList = explode( ',', $value );
-
$paramMap = array();
foreach( $paramList as $param ) {
@@ -170,33 +205,20 @@ class EditableFormField extends DataObject {
} else if( isset( $paramMap[$match[1]] ) ) {
$paramMap[$match[1]] = array( $paramMap[$match[1]] );
$paramMap[$match[1]][] = $match[2];
- //Debug::message( $match[1] . '[]=' . $match[2] );
} else {
$paramMap[$match[1]] = $match[2];
- //Debug::message( $match[1] . '=' . $match[2] );
}
- } else {
- //Debug::message('Invalid: ' . $param );
}
}
-
- //Debug::show( $paramMap );
-
return $paramMap;
}
protected function prepopulateFromMap( $paramMap ) {
- //Debug::show( $paramMap );
- //Debug::show( $this->stat('db') );
-
- foreach( $paramMap as $field => $fieldValue ) {
- if( /*$this->hasField( $field ) &&*/ !is_array( $fieldValue ) ) {
+ foreach($paramMap as $field => $fieldValue) {
+ if(!is_array($fieldValue)) {
$this->$field = $fieldValue;
- // Debug::message( 'Set ' . $field . ':'. $fieldValue );
}
}
-
- // exit();
}
function Type() {
diff --git a/code/editor/EditableFormHeading.php b/code/editor/EditableFormHeading.php
index 7f61a53..8055d2e 100755
--- a/code/editor/EditableFormHeading.php
+++ b/code/editor/EditableFormHeading.php
@@ -1,15 +1,16 @@
Title);
$labelField->addExtraClass('FormHeading');
return $labelField;
@@ -18,5 +19,9 @@ class EditableFormHeading extends EditableFormField {
function showInReports() {
return false;
}
+
+ function showExtraOptions() {
+ return false;
+ }
}
?>
\ No newline at end of file
diff --git a/code/editor/EditableLiteralField.php b/code/editor/EditableLiteralField.php
index 001f4ef..ed503ae 100644
--- a/code/editor/EditableLiteralField.php
+++ b/code/editor/EditableLiteralField.php
@@ -1,10 +1,10 @@
ID]";
@@ -33,32 +28,13 @@ class EditableLiteralField extends EditableFormField {
}
function populateFromPostData($data) {
-
$this->Content = $data['Content'];
parent::populateFromPostData($data);
}
- function getFormField() {
- return $this->createField();
- }
-
- function getFilterField() {
- return $this->createField(true);
- }
-
function createField() {
return new LiteralField("LiteralField[$this->ID]",
"
$this->Title ". $this->Content."
");
}
- /**
- * Populates the default fields.
- */
- function DefaultField() {
- return "";
- }
-
- function EditSegment() {
- return $this->renderWith( $this->class );
- }
}
?>
\ No newline at end of file
diff --git a/code/editor/EditableMemberListField.php b/code/editor/EditableMemberListField.php
index eeb6f95..653bec7 100644
--- a/code/editor/EditableMemberListField.php
+++ b/code/editor/EditableMemberListField.php
@@ -1,8 +1,8 @@
"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 " ParentID}][Default]\" value=\"{$this->ID}\"".$disabled.$default." />";
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/editor/EditableOption.php b/code/editor/EditableOption.php
new file mode 100644
index 0000000..97c227c
--- /dev/null
+++ b/code/editor/EditableOption.php
@@ -0,0 +1,71 @@
+ "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();
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/code/editor/EditableRadioField.php b/code/editor/EditableRadioField.php
index 820464c..bc26925 100755
--- a/code/editor/EditableRadioField.php
+++ b/code/editor/EditableRadioField.php
@@ -1,101 +1,16 @@
"EditableRadioOption"
- );
+class EditableRadioField extends EditableMultipleOptionField {
static $singular_name = 'Radio field';
+
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() {
$defaultOption = 0;
@@ -110,14 +25,6 @@ class EditableRadioField extends EditableFormField {
return -1;
}
- function getFormField() {
- return $this->createField();
- }
-
- function getFilterField() {
- return $this->createField( true );
- }
-
function createField( $asFilter = false ) {
$optionSet = $this->Options();
$options = array();
@@ -136,52 +43,5 @@ class EditableRadioField extends EditableFormField {
// return radiofields
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();
- }
- }
+}
?>
diff --git a/code/editor/EditableRadioOption.php b/code/editor/EditableRadioOption.php
deleted file mode 100755
index 2c40464..0000000
--- a/code/editor/EditableRadioOption.php
+++ /dev/null
@@ -1,84 +0,0 @@
-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 ' ';*/
-
- return $this->EditSegment();
- }
-
- function DefaultSelect() {
- $disabled = ($this->readonly) ? " disabled=\"disabled\"" : '';
-
- if($this->Parent()->getField('Default') == $this->ID) {
- $default = " checked=\"checked\"";
- } else {
- $default = '';
- }
-
- return " ParentID}][Default]\" value=\"{$this->ID}\"".$disabled.$default." />";
- }
-}
-?>
\ No newline at end of file
diff --git a/code/editor/EditableTextField.php b/code/editor/EditableTextField.php
index c3f6ff2..40bcfa6 100755
--- a/code/editor/EditableTextField.php
+++ b/code/editor/EditableTextField.php
@@ -1,9 +1,10 @@
name;
@@ -75,10 +75,16 @@ class FieldEditor extends FormField {
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) {
$name = $this->name;
+
$fieldSet = $record->$name();
// @todo shouldn't we deal with customFormActions on that object?
@@ -90,104 +96,109 @@ class FieldEditor extends FormField {
// store the field IDs and delete the missing fields
// alternatively, we could delete all the fields and re add them
$missingFields = array();
-
- foreach( $fieldSet as $existingField ){
+
+ foreach($fieldSet as $existingField){
$missingFields[$existingField->ID] = $existingField;
}
-
- // write the new fields to the database
+
if($_REQUEST[$name]){
foreach( array_keys( $_REQUEST[$name] ) as $newEditableID ) {
$newEditableData = $_REQUEST[$name][$newEditableID];
+
+ $editable = DataObject::get_one('EditableFormField', "(`ParentID`='{$record->ID}' OR `ParentID`=0) AND `EditableFormField`.`ID`='$newEditableID'" );
+
+ // check if we are updating an existing field. One odd thing is a 'deleted' field
+ // 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]);
+ }
+ }
- // `ParentID`=0 is for the new page
- $editable = DataObject::get_one( 'EditableFormField', "(`ParentID`='{$record->ID}' OR `ParentID`=0) AND `EditableFormField`.`ID`='$newEditableID'" );
-
- // check if we are updating an existing field
- if( $editable && isset($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;
- }
- }
-
- if($editable) {
- if($editable->ParentID == 0) {
- $editable->ParentID = $record->ID;
- }
- $editable->populateFromPostData($newEditableData);
- //$editable->write();
- }
+ if($editable) {
+ if($editable->ParentID == 0) {
+ $editable->ParentID = $record->ID;
+ }
+ $editable->populateFromPostData($newEditableData);
+ }
}
}
-
+
// remove the fields not saved
foreach($missingFields as $removedField) {
if(is_numeric($removedField->ID)) $removedField->delete();
}
-
+
if($record->hasMethod('customFormSave')) {
$record->customFormSave( $_REQUEST[$name], $record );
}
- //$record->writeWithoutVersion();
if($record->hasMethod( '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
$parentID = $this->form->getRecord()->ID;
- $lastField = DataObject::get('EditableFormField', "`ParentID`='$parentID'", "`Sort` DESC", null, 1 );
- $nextSort = 1;
-
- // the new sort value is the value of the last sort + 1 if a field exists
- if( $lastField )
- $nextSort += $lastField->Sort;
-
- $className = "Editable" . ucfirst($_REQUEST['Type']);
- $name = $this->name;
- if(is_subclass_of($className, "EditableFormField")) {
- $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*/
+ if($parentID) {
+ $parentID = Convert::raw2sql($parentID); // who knows what could happen
+ $highestSort = DB::query("SELECT MAX(Sort) FROM EditableFormField WHERE ParentID = '$parentID'");
+ $sort = $highestSort->value() + 1;
+
+ $className = "Editable" . ucfirst($_REQUEST['Type']);
+ $name = $this->name;
+ if(is_subclass_of($className, "EditableFormField")) {
+ $e = new $className();
+ $e->write();
$e->ParentID = $this->form->getRecord()->ID;
-
- //Debug::show($e);
- $e->write();
- //$e->ID = "new-" . ( $_REQUEST['NewID'] + 1 );
- $e->Name = $e->class . $e->ID;
- $e->write();
-
- return $e->EditSegment();
- } else {
- user_error("FieldEditor::addfield: Tried to create a field of class '$className'", E_USER_ERROR);
+ $e->Name = $e->class . $e->ID;
+ $e->write();
+ return $e->EditSegment();
+ }
}
+ 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'] : "";
+
+ // work out the sort by getting the sort of the last field in the form +1
+ 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;
}
-
- function addcheckboxfield() {
- return $this->addNewField( new EditableCheckbox() );
- }
-
+
protected $haveFormOptions = true;
function setHaveFormOptions($bool){
diff --git a/css/FieldEditor.css b/css/FieldEditor.css
index 131f980..bf1a363 100755
--- a/css/FieldEditor.css
+++ b/css/FieldEditor.css
@@ -73,7 +73,7 @@ div.FieldEditor div.MenuHolder {
border: 0;
}
-div.FieldEditor ul li {
+div.FieldEditor .MenuHolder ul li {
display: inline;
}
@@ -121,12 +121,10 @@ div.EditableFormField.mouseOver {
margin-left: 0px;
}
- div.EditableFormField div.ExtraOptions {
+ div.EditableFormField div.extraOptions {
display: none;
margin: 3px 0px 3px 57px;
background-color: #EEEEEE;
- /* IE has background issues without this */
- /*position: relative;*/
padding: 3px;
}
@@ -151,10 +149,7 @@ div.EditableDateField div.FieldDefault input {
********************************************************************/
#right #Form_EditForm div.EditableMultiOptionFormField div.FieldDefault ul.EditableDropdownOptions {
- border: solid 1px #7F9DB9;
- /* IE */
margin: 0px;
- /* display: none; */
display: block;
position: relative;
}
diff --git a/images/fe_icons/editablecheckbox.png b/images/editablecheckbox.png
similarity index 100%
rename from images/fe_icons/editablecheckbox.png
rename to images/editablecheckbox.png
diff --git a/images/fe_icons/checkboxes.png b/images/editablecheckboxgroupfield.png
similarity index 100%
rename from images/fe_icons/checkboxes.png
rename to images/editablecheckboxgroupfield.png
diff --git a/images/fe_icons/editabledatefield.png b/images/editabledatefield.png
similarity index 100%
rename from images/fe_icons/editabledatefield.png
rename to images/editabledatefield.png
diff --git a/images/fe_icons/dropdown.png b/images/editabledropdown.png
similarity index 100%
rename from images/fe_icons/dropdown.png
rename to images/editabledropdown.png
diff --git a/images/fe_icons/editableemailfield.png b/images/editableemailfield.png
similarity index 100%
rename from images/fe_icons/editableemailfield.png
rename to images/editableemailfield.png
diff --git a/images/fe_icons/editablefilefield.png b/images/editablefilefield.png
similarity index 100%
rename from images/fe_icons/editablefilefield.png
rename to images/editablefilefield.png
diff --git a/images/fe_icons/editableformheading.png b/images/editableformheading.png
similarity index 100%
rename from images/fe_icons/editableformheading.png
rename to images/editableformheading.png
diff --git a/images/editableliteralfield.png b/images/editableliteralfield.png
new file mode 100644
index 0000000..9c30878
Binary files /dev/null and b/images/editableliteralfield.png differ
diff --git a/images/fe_icons/checkbox.png b/images/fe_icons/checkbox.png
deleted file mode 100755
index 8250899..0000000
Binary files a/images/fe_icons/checkbox.png and /dev/null differ
diff --git a/images/fe_icons/date-time.png b/images/fe_icons/date-time.png
deleted file mode 100755
index d3ddaa4..0000000
Binary files a/images/fe_icons/date-time.png and /dev/null differ
diff --git a/images/fe_icons/radio.png b/images/fe_icons/editableradiofield.png
similarity index 100%
rename from images/fe_icons/radio.png
rename to images/fe_icons/editableradiofield.png
diff --git a/images/fe_icons/file-upload.png b/images/fe_icons/file-upload.png
deleted file mode 100755
index 4f16b13..0000000
Binary files a/images/fe_icons/file-upload.png and /dev/null differ
diff --git a/images/fe_icons/heading.png b/images/fe_icons/heading.png
deleted file mode 100755
index 3d95723..0000000
Binary files a/images/fe_icons/heading.png and /dev/null differ
diff --git a/images/fe_icons/text-email.png b/images/fe_icons/text-email.png
deleted file mode 100755
index 7697d66..0000000
Binary files a/images/fe_icons/text-email.png and /dev/null differ
diff --git a/images/fe_icons/text-numbers.png b/images/fe_icons/text-numbers.png
deleted file mode 100755
index 0ed65d4..0000000
Binary files a/images/fe_icons/text-numbers.png and /dev/null differ
diff --git a/images/fe_icons/text-password.png b/images/fe_icons/text-password.png
deleted file mode 100755
index 36d69f2..0000000
Binary files a/images/fe_icons/text-password.png and /dev/null differ
diff --git a/images/fe_icons/text.png b/images/fe_icons/text.png
deleted file mode 100755
index cb7951b..0000000
Binary files a/images/fe_icons/text.png and /dev/null differ
diff --git a/javascript/FieldEditor.js b/javascript/FieldEditor.js
index 3dbf571..e69de29 100755
--- a/javascript/FieldEditor.js
+++ b/javascript/FieldEditor.js
@@ -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');
-
-}
diff --git a/javascript/UserForm.js b/javascript/UserForm.js
index 0569fcd..c0afbea 100644
--- a/javascript/UserForm.js
+++ b/javascript/UserForm.js
@@ -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($) {
$(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() {
var deletedSubmission = $(this);
$.post($(this).attr('href'), function(data) {
@@ -7,5 +23,126 @@
});
return false;
});
- })
-})(jQuery);
\ No newline at end of file
+
+ /*-------------------- 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);
\ No newline at end of file
diff --git a/templates/EditableCheckbox.ss b/templates/EditableCheckbox.ss
deleted file mode 100755
index 5ce547f..0000000
--- a/templates/EditableCheckbox.ss
+++ /dev/null
@@ -1,26 +0,0 @@
-
\ No newline at end of file
diff --git a/templates/EditableCheckboxGroupField.ss b/templates/EditableCheckboxGroupField.ss
deleted file mode 100755
index 3553ad3..0000000
--- a/templates/EditableCheckboxGroupField.ss
+++ /dev/null
@@ -1,51 +0,0 @@
-
diff --git a/templates/EditableCheckboxOption.ss b/templates/EditableCheckboxOption.ss
deleted file mode 100755
index 70865a9..0000000
--- a/templates/EditableCheckboxOption.ss
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- <% if isReadonly %>
-
- <% else %>
-
- <% end_if %>
-
\ No newline at end of file
diff --git a/templates/EditableDateField.ss b/templates/EditableDateField.ss
deleted file mode 100755
index 6343bb5..0000000
--- a/templates/EditableDateField.ss
+++ /dev/null
@@ -1,20 +0,0 @@
-
diff --git a/templates/EditableDropdown.ss b/templates/EditableDropdown.ss
deleted file mode 100755
index c02bd6d..0000000
--- a/templates/EditableDropdown.ss
+++ /dev/null
@@ -1,50 +0,0 @@
-
diff --git a/templates/EditableDropdownOption.ss b/templates/EditableDropdownOption.ss
deleted file mode 100755
index 2bdf47a..0000000
--- a/templates/EditableDropdownOption.ss
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- <% if isReadonly %>
-
- <% else %>
-
- <% end_if %>
-
\ No newline at end of file
diff --git a/templates/EditableEmailField.ss b/templates/EditableEmailField.ss
deleted file mode 100755
index 7b7aadd..0000000
--- a/templates/EditableEmailField.ss
+++ /dev/null
@@ -1,25 +0,0 @@
-
\ No newline at end of file
diff --git a/templates/EditableFileField.ss b/templates/EditableFileField.ss
deleted file mode 100755
index f8f6b31..0000000
--- a/templates/EditableFileField.ss
+++ /dev/null
@@ -1,20 +0,0 @@
-
diff --git a/templates/EditableFormField.ss b/templates/EditableFormField.ss
index 3d2a8bc..06194a6 100755
--- a/templates/EditableFormField.ss
+++ b/templates/EditableFormField.ss
@@ -1,44 +1,61 @@
\ No newline at end of file
diff --git a/templates/EditableFormFieldOption.ss b/templates/EditableFormFieldOption.ss
deleted file mode 100755
index 4ec8971..0000000
--- a/templates/EditableFormFieldOption.ss
+++ /dev/null
@@ -1,15 +0,0 @@
-
- <% if isReadonly %>
-
- $DefaultSelect
-
-
-
- <% else %>
-
- $DefaultSelect
-
-
-
- <% end_if %>
-
\ No newline at end of file
diff --git a/templates/EditableFormHeading.ss b/templates/EditableFormHeading.ss
deleted file mode 100755
index 9324c39..0000000
--- a/templates/EditableFormHeading.ss
+++ /dev/null
@@ -1,17 +0,0 @@
-
diff --git a/templates/EditableLiteralField.ss b/templates/EditableLiteralField.ss
deleted file mode 100644
index d10f909..0000000
--- a/templates/EditableLiteralField.ss
+++ /dev/null
@@ -1,20 +0,0 @@
-
\ No newline at end of file
diff --git a/templates/EditableOption.ss b/templates/EditableOption.ss
new file mode 100644
index 0000000..1cb543d
--- /dev/null
+++ b/templates/EditableOption.ss
@@ -0,0 +1,11 @@
+
+
+ $DefaultSelect
+
+
+ <% if isReadonly %>
+
+ <% else %>
+
+ <% end_if %>
+
\ No newline at end of file
diff --git a/templates/EditableRadioField.ss b/templates/EditableRadioField.ss
deleted file mode 100755
index 452905a..0000000
--- a/templates/EditableRadioField.ss
+++ /dev/null
@@ -1,51 +0,0 @@
-
\ No newline at end of file
diff --git a/templates/EditableRadioOption.ss b/templates/EditableRadioOption.ss
deleted file mode 100755
index 70865a9..0000000
--- a/templates/EditableRadioOption.ss
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- <% if isReadonly %>
-
- <% else %>
-
- <% end_if %>
-
\ No newline at end of file
diff --git a/templates/EditableTextField.ss b/templates/EditableTextField.ss
deleted file mode 100755
index b9f59bd..0000000
--- a/templates/EditableTextField.ss
+++ /dev/null
@@ -1,20 +0,0 @@
-
\ No newline at end of file
diff --git a/tests/UserDefinedFormTest.php b/tests/UserDefinedFormTest.php
new file mode 100644
index 0000000..ae92f4a
--- /dev/null
+++ b/tests/UserDefinedFormTest.php
@@ -0,0 +1,28 @@
+Name = "$field";
+ $object->Title = "$field";
+ $object->write();
+
+ $this->assertEquals($field, $object->Name);
+ }
+ }
+}
+?>
\ No newline at end of file