mirror of
https://github.com/silverstripe/silverstripe-userforms.git
synced 2024-10-22 17:05:42 +02:00
ENHANCEMENT Moved UserDefinedForm and related code, templates, CSS and javascript out of cms and sapphire classes into userforms/trunk
This commit is contained in:
parent
645787823a
commit
1ea06b4028
6
_config.php
Normal file
6
_config.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
LeftAndMain::require_javascript('userforms/javascript/FieldEditor.js');
|
||||
LeftAndMain::require_css('userforms/css/FieldEditor.css');
|
||||
|
||||
?>
|
341
code/UserDefinedForm.php
Executable file
341
code/UserDefinedForm.php
Executable file
@ -0,0 +1,341 @@
|
||||
<?php
|
||||
/**
|
||||
* Page type that lets users build a contact form.
|
||||
* @package cms
|
||||
* @subpackage pagetypes
|
||||
*/
|
||||
class UserDefinedForm extends Page {
|
||||
static $add_action = "a contact form";
|
||||
|
||||
static $icon = "cms/images/treeicons/task";
|
||||
|
||||
// a list of groups that are permitted to create pages of this type.
|
||||
/*static $can_create = array(
|
||||
'Administrators'
|
||||
);*/
|
||||
|
||||
static $need_permission = 'ADMIN';
|
||||
|
||||
static $db = array(
|
||||
"EmailTo" => "Varchar",
|
||||
"EmailOnSubmit" => "Boolean",
|
||||
"SubmitButtonText" => "Varchar",
|
||||
"OnCompleteMessage" => "HTMLText"
|
||||
);
|
||||
|
||||
static $defaults = array(
|
||||
"OnCompleteMessage" => "<p>Thanks, we've received your submission.</p>",
|
||||
);
|
||||
|
||||
static $has_many = array(
|
||||
"Fields" => "EditableFormField",
|
||||
"Submissions" => "SubmittedForm"
|
||||
);
|
||||
|
||||
protected $fields;
|
||||
|
||||
function getCMSFields($cms) {
|
||||
$fields = parent::getCMSFields($cms);
|
||||
|
||||
$fields->addFieldToTab("Root."._t('UserDefinedForm.FORM', 'Form'), new FieldEditor("Fields", 'Fields', "", $this ));
|
||||
$fields->addFieldToTab("Root."._t('UserDefinedForm.SUBMISSIONS','Submissions'), new SubmittedFormReportField( "Reports", _t('UserDefinedForm.RECEIVED', 'Received Submissions'), "", $this ) );
|
||||
$fields->addFieldToTab("Root.Content."._t('UserDefinedForm.ONCOMPLETE','On complete'), new HtmlEditorField( "OnCompleteMessage", _t('UserDefinedForm.ONCOMPLETELABEL', 'Show on completion'),3,"",_t('UserDefinedForm.ONCOMPLETEMESSAGE', $this->OnCompleteMessage), $this ) );
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
function FilterForm() {
|
||||
// Build fields
|
||||
$fields = new FieldSet();
|
||||
$required = array();
|
||||
|
||||
foreach( $this->Fields() as $field ) {
|
||||
$fields->push( $field->getFilterField() );
|
||||
}
|
||||
|
||||
// Build actions
|
||||
$actions = new FieldSet(
|
||||
new FormAction( "filter", _t('UserDefinedForm.SUBMIT', 'Submit') )
|
||||
);
|
||||
|
||||
// set the name of the form
|
||||
return new Form( $this, "Form", $fields, $actions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the submissions by the given criteria
|
||||
*/
|
||||
function filter( $data, $form ) {
|
||||
|
||||
$filterClause = array( "`SubmittedForm`.`ParentID` = '{$this->ID}'" );
|
||||
|
||||
$keywords = preg_split( '/\s+/', $data['FilterKeyword'] );
|
||||
|
||||
$keywordClauses = array();
|
||||
|
||||
// combine all keywords into one clause
|
||||
foreach( $keywords as $keyword ) {
|
||||
|
||||
// escape %, \ and _ in the keyword. These have special meanings in a LIKE string
|
||||
$keyword = preg_replace( '/([%_])/', '\\\\1', addslashes( $keyword ) );
|
||||
|
||||
$keywordClauses[] = "`Value` LIKE '%$keyword%'";
|
||||
}
|
||||
|
||||
if( count( $keywordClauses ) > 0 ) {
|
||||
$filterClause[] = "( " . implode( ' OR ', $keywordClauses ) . ")";
|
||||
$searchQuery = 'keywords \'' . implode( "', '", $keywords ) . '\' ';
|
||||
}
|
||||
|
||||
$fromDate = addslashes( $data['FilterFromDate'] );
|
||||
$toDate = addslashes( $data['FilterToDate'] );
|
||||
|
||||
// use date objects to convert date to value expected by database
|
||||
if( ereg('^([0-9]+)/([0-9]+)/([0-9]+)$', $fromDate, $parts) )
|
||||
$fromDate = $parts[3] . '-' . $parts[2] . '-' . $parts[1];
|
||||
|
||||
if( ereg('^([0-9]+)/([0-9]+)/([0-9]+)$', $toDate, $parts) )
|
||||
$toDate = $parts[3] . '-' . $parts[2] . '-' . $parts[1];
|
||||
|
||||
if( $fromDate ) {
|
||||
$filterClause[] = "`SubmittedForm`.`Created` >= '$fromDate'";
|
||||
$searchQuery .= 'from ' . $fromDate . ' ';
|
||||
}
|
||||
|
||||
if( $toDate ) {
|
||||
$filterClause[] = "`SubmittedForm`.`Created` <= '$toDate'";
|
||||
$searchQuery .= 'to ' . $toDate;
|
||||
}
|
||||
|
||||
$submittedValues = DataObject::get( 'SubmittedFormField', implode( ' AND ', $filterClause ), "", "INNER JOIN `SubmittedForm` ON `SubmittedFormField`.`ParentID`=`SubmittedForm`.`ID`" );
|
||||
|
||||
if( !$submittedValues || $submittedValues->Count() == 0 )
|
||||
return _t('UserDefinedForm.NORESULTS', 'No matching results found');
|
||||
|
||||
$submissions = $submittedValues->groupWithParents( 'ParentID', 'SubmittedForm' );
|
||||
|
||||
if( !$submissions || $submissions->Count() == 0 )
|
||||
return _t('UserDefinedForm.NORESULTS', 'No matching results found');
|
||||
|
||||
return $submissions->customise(
|
||||
array( 'Submissions' => $submissions )
|
||||
)->renderWith( 'SubmittedFormReportField_Reports' );
|
||||
}
|
||||
|
||||
function ReportFilterForm() {
|
||||
return new SubmittedFormReportField_FilterForm( $this, 'ReportFilterForm' );
|
||||
}
|
||||
|
||||
function delete() {
|
||||
// remove all the fields associated with this page
|
||||
foreach( $this->Fields() as $field )
|
||||
$field->delete();
|
||||
|
||||
parent::delete();
|
||||
}
|
||||
|
||||
public function customFormActions( $isReadonly = false ) {
|
||||
return new FieldSet( new TextField( "SubmitButtonText", _t('UserDefinedForm.TEXTONSUBMIT', 'Text on submit button:'), $this->SubmitButtonText ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate this UserDefinedForm page, and its form fields.
|
||||
* Submissions, on the other hand, won't be duplicated.
|
||||
*/
|
||||
public function duplicate() {
|
||||
$page = parent::duplicate();
|
||||
foreach($this->Fields() as $field) {
|
||||
$newField = $field->duplicate();
|
||||
$newField->ParentID = $page->ID;
|
||||
$newField->write();
|
||||
}
|
||||
return $page;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller for the {@link UserDefinedForm} page type.
|
||||
* @package cms
|
||||
* @subpackage pagetypes
|
||||
*/
|
||||
class UserDefinedForm_Controller extends Page_Controller {
|
||||
|
||||
function init() {
|
||||
Requirements::javascript(THIRDPARTY_DIR . 'jsparty/prototype-safe.js');
|
||||
Requirements::javascript(THIRDPARTY_DIR . 'jsparty/behaviour.js');
|
||||
|
||||
parent::init();
|
||||
}
|
||||
|
||||
function Form() {
|
||||
// Build fields
|
||||
$fields = new FieldSet();
|
||||
$required = array();
|
||||
|
||||
if( !$this->SubmitButtonText )
|
||||
$this->SubmitButtonText = 'Submit';
|
||||
|
||||
foreach( $this->Fields() as $field ) {
|
||||
$fields->push( $field->getFormField() );
|
||||
if( $field->Required )
|
||||
$required[] = $field->Name;
|
||||
}
|
||||
|
||||
if(!isset($_SERVER['HTTP_REFERER'])) {
|
||||
$_SERVER['HTTP_REFERER'] = "";
|
||||
}
|
||||
|
||||
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
|
||||
$fields->push( new HiddenField( "Referrer", "", $referer ) );
|
||||
|
||||
// Build actions
|
||||
$actions = new FieldSet(
|
||||
new FormAction( "process", $this->SubmitButtonText )
|
||||
);
|
||||
|
||||
// set the name of the form
|
||||
$form = new Form( $this, "Form", $fields, $actions, new RequiredFields( $required ) );
|
||||
$form->loadDataFrom($this->failover);
|
||||
return $form;
|
||||
}
|
||||
|
||||
function ReportFilterForm() {
|
||||
return new SubmittedFormReportField_FilterForm( $this, 'ReportFilterForm' );
|
||||
}
|
||||
|
||||
function process( $data, $form ) {
|
||||
$submittedForm = new SubmittedForm();
|
||||
$submittedForm->SubmittedBy = Member::currentUser();
|
||||
$submittedForm->ParentID = $this->ID;
|
||||
$submittedForm->Recipient = $this->EmailTo;
|
||||
$submittedForm->write();
|
||||
|
||||
$values = array();
|
||||
$recipientAddresses = array();
|
||||
$sendCopy = false;
|
||||
|
||||
$attachments = array();
|
||||
|
||||
$submittedFields = new DataObjectSet();
|
||||
foreach( $this->Fields() as $field ) {
|
||||
$submittedField = new SubmittedFormField();
|
||||
$submittedField->ParentID = $submittedForm->ID;
|
||||
$submittedField->Name = $field->Name;
|
||||
$submittedField->Title = $field->Title;
|
||||
|
||||
if( $field->hasMethod( 'getValueFromData' ) )
|
||||
$submittedField->Value = $field->getValueFromData( $data );
|
||||
else
|
||||
if(isset($data[$field->Name])) $submittedField->Value = $data[$field->Name];
|
||||
|
||||
$submittedField->write();
|
||||
$submittedFields->push($submittedField);
|
||||
|
||||
if(!empty( $data[$field->Name])){
|
||||
// execute the appropriate functionality based on the form field.
|
||||
switch($field->ClassName){
|
||||
|
||||
case "EditableEmailField" :
|
||||
|
||||
if($field->SendCopy){
|
||||
$recipientAddresses[] = $data[$field->Name];
|
||||
$sendCopy = true;
|
||||
$values[$field->Title] = '<a style="white-space: nowrap" href="mailto:'.$data[$field->Name].'">'.$data[$field->Name].'</a>';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "EditableFileField" :
|
||||
|
||||
// Returns a file type which we attach to the email.
|
||||
$submittedfile = $field->createSubmittedField($data[$field->Name], $submittedForm);
|
||||
$file = $submittedfile->UploadedFile();
|
||||
|
||||
$filename = $file->getFilename();
|
||||
|
||||
// Attach the file if its less than 1MB, provide a link if its over.
|
||||
if($file->getAbsoluteSize() < 1024*1024*1){
|
||||
$attachments[] = $file;
|
||||
}
|
||||
|
||||
// Always provide the link if present.
|
||||
if($file->ID) {
|
||||
$submittedField->Value = $values[$field->Title] = "<a href=\"". $filename ."\" title=\"". Director::absoluteBaseURL(). $filename. "\">Uploaded to: ". Director::absoluteBaseURL(). $filename . "</a>";
|
||||
} else {
|
||||
$submittedField->Value = $values[$field->Title] = "";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}elseif( $field->hasMethod( 'getValueFromData' ) ) {
|
||||
$values[$field->Title] = Convert::linkIfMatch($field->getValueFromData( $data ));
|
||||
|
||||
} else {
|
||||
if(isset($data[$field->Name])) $values[$field->Title] = Convert::linkIfMatch($data[$field->Name]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( $this->EmailOnSubmit || $sendCopy ) {
|
||||
$emailData = array(
|
||||
"Recipient" => $this->EmailTo,
|
||||
"Sender" => Member::currentUser(),
|
||||
"Fields" => $submittedFields,
|
||||
);
|
||||
|
||||
$email = new UserDefinedForm_SubmittedFormEmail($submittedFields);
|
||||
$email->populateTemplate($emailData);
|
||||
$email->setTo( $this->EmailTo );
|
||||
$email->setSubject( $this->Title );
|
||||
|
||||
// add attachments to email (<1MB)
|
||||
if($attachments){
|
||||
foreach($attachments as $file){
|
||||
$email->attachFile($filename,$filename);
|
||||
}
|
||||
}
|
||||
|
||||
$email->send();
|
||||
|
||||
// send to each of email fields
|
||||
foreach( $recipientAddresses as $addr ) {
|
||||
$email->setTo( $addr );
|
||||
$email->send();
|
||||
}
|
||||
}
|
||||
|
||||
$custom = $this->customise(array(
|
||||
"Content" => $this->customise( array( 'Link' => $data['Referrer'] ) )->renderWith('ReceivedFormSubmission'),
|
||||
"Form" => " ",
|
||||
));
|
||||
|
||||
return $custom->renderWith('Page');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Email that gets sent when a submission is made.
|
||||
* @package cms
|
||||
* @subpackage pagetypes
|
||||
*/
|
||||
class UserDefinedForm_SubmittedFormEmail extends Email {
|
||||
protected $ss_template = "SubmittedFormEmail";
|
||||
protected $from = '$Sender.Email';
|
||||
protected $to = '$Recipient.Email';
|
||||
protected $subject = 'Submission of form';
|
||||
protected $data;
|
||||
|
||||
function __construct($values) {
|
||||
$this->subject = _t('UserDefinedForm_SubmittedFormEmail.EMAILSUBJECT', 'Submission of form');
|
||||
parent::__construct();
|
||||
|
||||
$this->data = $values;
|
||||
}
|
||||
|
||||
function Data() {
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
14
code/editor/EditableButton.php
Executable file
14
code/editor/EditableButton.php
Executable file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* EditableButton
|
||||
* Allows a user to modify the text on the button
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableButton extends FormField {
|
||||
|
||||
function Field() {
|
||||
return '<span class="EditableButton"><img src="cms/images/button-left.gif" /><input name="'.$this->name.'" value="'.$this->attrValue().'" /><img src="cms/images/button-right.gif" /></span>';
|
||||
}
|
||||
}
|
||||
?>
|
45
code/editor/EditableCheckbox.php
Executable file
45
code/editor/EditableCheckbox.php
Executable file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* EditableCheckbox
|
||||
* A user modifiable checkbox on a UserDefinedForm
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableCheckbox extends EditableFormField {
|
||||
|
||||
// Could remove this and just use value
|
||||
static $db = array(
|
||||
"Checked" => "Boolean"
|
||||
);
|
||||
|
||||
static $singular_name = 'Checkbox';
|
||||
static $plural_name = 'Checkboxes';
|
||||
|
||||
function CheckboxField() {
|
||||
$checkbox = new CheckboxField("Fields[".$this->ID."][Default]", "Checked by default", $this->getField('Default'));
|
||||
|
||||
if( $this->readonly )
|
||||
$checkbox = $checkbox->performReadonlyTransformation();
|
||||
|
||||
return $checkbox->FieldHolder();
|
||||
}
|
||||
|
||||
function populateFromPostData( $data ) {
|
||||
$this->setField('Checked', isset($data['Checked']) ? $data['Checked'] : null);
|
||||
parent::populateFromPostData( $data );
|
||||
}
|
||||
|
||||
function getFormField() {
|
||||
return new CheckboxField( $this->Name, $this->Title, $this->getField('Default') );
|
||||
}
|
||||
|
||||
function getFilterField() {
|
||||
return new OptionsetField( $this->Name,
|
||||
$this->Title,
|
||||
array( '-1' => '('._t('EditableCheckbox.ANY', 'Any').')',
|
||||
'on' => _t('EditableCheckbox.SELECTED', 'Selected'),
|
||||
'0' => _t('EditableCheckbox.NOTSELECTED', 'Not selected') )
|
||||
);
|
||||
}
|
||||
}
|
||||
?>
|
156
code/editor/EditableCheckboxGroupField.php
Executable file
156
code/editor/EditableCheckboxGroupField.php
Executable file
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
/**
|
||||
* EditableDropdown
|
||||
* Represents a set of selectable radio buttons
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableCheckboxGroupField extends EditableFormField {
|
||||
|
||||
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 $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'] );
|
||||
|
||||
|
||||
// store default, etc
|
||||
foreach( $fieldSet as $option ) {
|
||||
if( $deletedOptions && array_search( $option->ID, $deletedOptions ) !== false ) {
|
||||
$option->delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
if( $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;
|
||||
|
||||
foreach( $this->Options() as $option ) {
|
||||
if( $option->getField('Default') )
|
||||
return $defaultOption;
|
||||
else
|
||||
$defaultOption++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
function getFormField() {
|
||||
return $this->createField();
|
||||
}
|
||||
|
||||
function getFilterField() {
|
||||
return $this->createField( true );
|
||||
}
|
||||
|
||||
function createField( $asFilter = false ) {
|
||||
$optionSet = $this->Options();
|
||||
$options = array();
|
||||
|
||||
if( $asFilter )
|
||||
$options['-1'] = '(Any)';
|
||||
|
||||
$defaultOption = '-1';
|
||||
|
||||
/*foreach( $optionSet as $option ) {
|
||||
$options[$option->Title] = $option->Title;
|
||||
}*/
|
||||
|
||||
// return radiofields
|
||||
$checkboxSet = new CheckboxSetField( $this->Name, $this->Title, $optionSet, $optionSet );
|
||||
|
||||
return $checkboxSet;
|
||||
}
|
||||
|
||||
function getValueFromData($data) {
|
||||
if(empty($data[$this->Name])) {
|
||||
return "";
|
||||
}
|
||||
|
||||
$entries = $data[$this->Name];
|
||||
|
||||
if(!is_array($data[$this->Name])) {
|
||||
$entries = array($data[$this->Name]);
|
||||
}
|
||||
|
||||
$selectedOptions = DataObject::get('EditableCheckboxOption', "ParentID={$this->ID} AND ID IN (" . implode(',', $entries) . ")");
|
||||
foreach($selectedOptions as $selected) {
|
||||
if(!$result) {
|
||||
$result = $selected->Title;
|
||||
} else {
|
||||
$result .= "," . $selected->Title;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function TemplateOption() {
|
||||
$option = new EditableCheckboxOption();
|
||||
return $option->EditSegment();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
76
code/editor/EditableCheckboxOption.php
Executable file
76
code/editor/EditableCheckboxOption.php
Executable file
@ -0,0 +1,76 @@
|
||||
<?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'];
|
||||
$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\"";
|
||||
|
||||
if( $this->getField('Default') )
|
||||
$default = " checked=\"checked\"";
|
||||
|
||||
return "<input class=\"checkbox\" type=\"checkbox\" name=\"Fields[{$this->ParentID}][{$this->ID}][Default]\" value=\"1\"".$disabled.$default." />";
|
||||
}
|
||||
}
|
||||
?>
|
49
code/editor/EditableDateField.php
Executable file
49
code/editor/EditableDateField.php
Executable file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* EditableDateField
|
||||
* Allows a user to add a date field to the Field Editor
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableDateField extends EditableFormField {
|
||||
static $singular_name = 'Date field';
|
||||
static $plural_name = 'Date fields';
|
||||
|
||||
function DefaultField() {
|
||||
$dmyField = new CalendarDateField( "Fields[{$this->ID}][Default]", "", $this->getField('Default') );
|
||||
|
||||
if( $this->readonly )
|
||||
$dmyField = $dmyField->performReadonlyTransformation();
|
||||
|
||||
return $dmyField;
|
||||
}
|
||||
|
||||
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-';
|
||||
|
||||
if( empty( $data['Default'] ) && !empty( $data[$fieldPrefix.'Year'] ) && !empty( $data[$fieldPrefix.'Month'] ) && !empty( $data[$fieldPrefix.'Day'] ) )
|
||||
$data['Default'] = $data['Year'] . '-' . $data['Month'] . '-' . $data['Day'];
|
||||
|
||||
// Debug::show( $data );
|
||||
|
||||
parent::populateFromPostData( $data );
|
||||
}
|
||||
|
||||
function getFormField() {
|
||||
return new CalendarDateField( $this->Name, $this->Title, $this->getField('Default') );
|
||||
}
|
||||
}
|
||||
?>
|
127
code/editor/EditableDropdown.php
Executable file
127
code/editor/EditableDropdown.php
Executable file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
* EditableDropdown
|
||||
* Represents a modifiable dropdown box on a form
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableDropdown extends EditableFormField {
|
||||
|
||||
static $has_many = array(
|
||||
"Options" => "EditableDropdownOption"
|
||||
);
|
||||
|
||||
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($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 ) {
|
||||
$optionSet = $this->Options();
|
||||
$options = array();
|
||||
|
||||
if( $asFilter )
|
||||
$options['-1'] = "(Any)";
|
||||
|
||||
$defaultOption = '-1';
|
||||
|
||||
foreach( $optionSet as $option ) {
|
||||
$options[$option->Title] = $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;
|
||||
}
|
||||
}
|
||||
?>
|
77
code/editor/EditableDropdownOption.php
Executable file
77
code/editor/EditableDropdownOption.php
Executable file
@ -0,0 +1,77 @@
|
||||
<?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." />";
|
||||
}
|
||||
}
|
||||
?>
|
53
code/editor/EditableEmailField.php
Executable file
53
code/editor/EditableEmailField.php
Executable file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* EditableEmailField
|
||||
* Allow users to define a validating editable email field for a UserDefinedForm
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableEmailField extends EditableFormField {
|
||||
|
||||
static $db = array(
|
||||
"SendCopy" => "Boolean"
|
||||
);
|
||||
|
||||
static $singular_name = 'Email field';
|
||||
static $plural_name = 'Email fields';
|
||||
|
||||
function populateFromPostData( $data ) {
|
||||
$this->SendCopy = !empty( $data['SendCopy'] ) ? "1" : "0";
|
||||
|
||||
parent::populateFromPostData( $data );
|
||||
}
|
||||
|
||||
function ExtraOptions() {
|
||||
$baseName = "Fields[$this->ID]";
|
||||
|
||||
$extraFields = new FieldSet(
|
||||
new CheckboxField( $baseName . "[SendCopy]", _t('EditableEmailField.SENDCOPY', 'Send copy of submission to this address'), $this->SendCopy )
|
||||
);
|
||||
|
||||
foreach( parent::ExtraOptions() as $extraField )
|
||||
$extraFields->push( $extraField );
|
||||
|
||||
if( $this->readonly )
|
||||
$extraFields = $extraFields->makeReadonly();
|
||||
|
||||
return $extraFields;
|
||||
}
|
||||
|
||||
function getFormField() {
|
||||
return new EmailField( $this->Name, $this->Title, $this->getField('Default') );
|
||||
}
|
||||
|
||||
function getFilterField() {
|
||||
return $this->createField( true );
|
||||
}
|
||||
|
||||
function DefaultField() {
|
||||
$disabled = ($this->readonly) ? " disabled=\"disabled\"" : '';
|
||||
|
||||
return '<input class="defaultText" name="Fields['.Convert::raw2att( $this->ID ).'][Default]" type="text" value="'.Convert::raw2att( $this->getField('Default') ).'"'.$disabled.' />';
|
||||
}
|
||||
}
|
||||
?>
|
65
code/editor/EditableFileField.php
Executable file
65
code/editor/EditableFileField.php
Executable file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* Allows a user to add a field that can be used to upload a file
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableFileField extends EditableFormField {
|
||||
|
||||
// this needs to be moved.
|
||||
static $has_one = array(
|
||||
"UploadedFile" => "File"
|
||||
);
|
||||
|
||||
/**
|
||||
* @see {Upload->allowedMaxFileSize}
|
||||
* @var int
|
||||
*/
|
||||
public static $allowed_max_file_size;
|
||||
|
||||
/**
|
||||
* @see {Upload->allowedExtensions}
|
||||
* @var array
|
||||
*/
|
||||
public static $allowed_extensions = array();
|
||||
|
||||
static $singular_name = 'File field';
|
||||
static $plural_names = 'File fields';
|
||||
|
||||
function getFormField() {
|
||||
if($field = parent::getFormField())
|
||||
return $field;
|
||||
return new FileField($this->Name, $this->Title, $this->getField('Default'));
|
||||
// TODO We can't use the preview feature because FileIFrameField also shows the "From the file store" functionality
|
||||
//return new FileIFrameField( $this->Name, $this->Title, $this->getField('Default') );
|
||||
}
|
||||
|
||||
function getSimpleFormField(){
|
||||
return new FileField($this->Name, $this->Title, $this->getField('Default'));
|
||||
}
|
||||
|
||||
function createSubmittedField($data, $submittedForm, $fieldClass = "SubmittedFileField") {
|
||||
if(!$_FILES[$this->Name])
|
||||
return null;
|
||||
|
||||
$submittedField = new $fieldClass();
|
||||
$submittedField->Title = $this->Title;
|
||||
$submittedField->Name = $this->Name;
|
||||
$submittedField->ParentID = $submittedForm->ID;
|
||||
|
||||
// create the file from post data
|
||||
$upload = new Upload();
|
||||
$upload->setAllowedExtensions(self::$allowed_extensions);
|
||||
$upload->setAllowedMaxFileSize(self::$allowed_max_file_size);
|
||||
|
||||
// upload file
|
||||
$upload->load($_FILES[$this->Name]);
|
||||
|
||||
$uploadedFile = $upload->getFile();
|
||||
$submittedField->UploadedFileID = $uploadedFile->ID;
|
||||
$submittedField->write();
|
||||
|
||||
return $submittedField;
|
||||
}
|
||||
}
|
||||
?>
|
213
code/editor/EditableFormField.php
Executable file
213
code/editor/EditableFormField.php
Executable file
@ -0,0 +1,213 @@
|
||||
<?php
|
||||
/**
|
||||
* Represents an editable form field
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableFormField extends DataObject {
|
||||
|
||||
static $default_sort = "Sort";
|
||||
|
||||
static $db = array(
|
||||
"Name" => "Varchar",
|
||||
"Title" => "Varchar(255)",
|
||||
"Default" => "Varchar",
|
||||
"Sort" => "Int",
|
||||
"Required" => "Boolean",
|
||||
"CanDelete" => "Boolean",
|
||||
"CustomParameter" => "Varchar"
|
||||
);
|
||||
|
||||
static $defaults = array(
|
||||
"CanDelete" => "1"
|
||||
);
|
||||
|
||||
static $has_one = array(
|
||||
"Parent" => "SiteTree",
|
||||
);
|
||||
|
||||
protected $readonly;
|
||||
|
||||
protected $editor;
|
||||
|
||||
function setEditor( $editor ) {
|
||||
$this->editor = $editor;
|
||||
}
|
||||
|
||||
function __construct( $record = null, $isSingleton = false ) {
|
||||
$this->setField('Default', -1);
|
||||
parent::__construct( $record, $isSingleton );
|
||||
}
|
||||
|
||||
function EditSegment() {
|
||||
return $this->renderWith('EditableFormField');
|
||||
}
|
||||
|
||||
function isReadonly() {
|
||||
return $this->readonly;
|
||||
}
|
||||
|
||||
function ClassName() {
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
function makeReadonly() {
|
||||
$this->readonly = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
function ReadonlyEditSegment() {
|
||||
$this->readonly = true;
|
||||
return $this->EditSegment();
|
||||
}
|
||||
|
||||
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 = '';
|
||||
}
|
||||
|
||||
return "<input type=\"text\" class=\"text\" title=\"("._t('EditableFormField.ENTERQUESTION', 'Enter Question').")\" value=\"$titleAttr\" name=\"Fields[{$this->ID}][Title]\"$readOnlyAttr />";
|
||||
}
|
||||
|
||||
function Name() {
|
||||
return "Fields[".$this->ID."]";
|
||||
}
|
||||
|
||||
/*function getName() {
|
||||
return "field" . $this->ID;
|
||||
}*/
|
||||
|
||||
function populateFromPostData( $data ) {
|
||||
|
||||
$this->Title = $data['Title'];
|
||||
if(isset($data['Default'])) {
|
||||
$this->setField('Default', $data['Default']);
|
||||
}
|
||||
$this->Sort = isset($data['Sort']) ? $data['Sort'] : null;
|
||||
$this->CustomParameter = $data['CustomParameter'];
|
||||
$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();
|
||||
}
|
||||
|
||||
function ExtraOptions() {
|
||||
|
||||
$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( 'getExtraOptionsForField' ) ) {
|
||||
$extraFields = $this->Parent()->getExtraOptionsForField( $this );
|
||||
|
||||
foreach( $extraFields as $extraField )
|
||||
$extraOptions->push( $extraField );
|
||||
}
|
||||
|
||||
if( $this->readonly )
|
||||
$extraOptions = $extraOptions->makeReadonly();
|
||||
|
||||
return $extraOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a FormField to appear on the front end
|
||||
*/
|
||||
function getFormField() {
|
||||
}
|
||||
|
||||
function getFilterField() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an evaluation appropriate for a filter clause
|
||||
* @todo: escape the string
|
||||
*/
|
||||
function filterClause( $value ) {
|
||||
// Not filtering on this field
|
||||
|
||||
if( $value == '-1' )
|
||||
return "";
|
||||
else
|
||||
return "`{$this->name}` = '$value'";
|
||||
}
|
||||
|
||||
function showInReports() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function prepopulate( $value ) {
|
||||
$this->prepopulateFromMap( $this->parsePrepopulateValue( $value ) );
|
||||
}
|
||||
|
||||
protected function parsePrepopulateValue( $value ) {
|
||||
$paramList = explode( ',', $value );
|
||||
|
||||
$paramMap = array();
|
||||
|
||||
foreach( $paramList as $param ) {
|
||||
|
||||
if( preg_match( '/([^=]+)=(.+)/', $param, $match ) ) {
|
||||
if( isset( $paramMap[$match[1]] ) && is_array( $paramMap[$match[1]] ) ) {
|
||||
$paramMap[$match[1]][] = $match[2];
|
||||
} 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 ) ) {
|
||||
$this->$field = $fieldValue;
|
||||
// Debug::message( 'Set ' . $field . ':'. $fieldValue );
|
||||
}
|
||||
}
|
||||
|
||||
// exit();
|
||||
}
|
||||
|
||||
function Type() {
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
function CustomParameter() {
|
||||
return $this->CustomParameter;
|
||||
}
|
||||
/*
|
||||
function saveInto( DataObject $record ) {
|
||||
if(
|
||||
}
|
||||
*/
|
||||
}
|
||||
?>
|
21
code/editor/EditableFormHeading.php
Executable file
21
code/editor/EditableFormHeading.php
Executable file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* Allows an editor to insert a generic heading into a field
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableFormHeading extends EditableFormField {
|
||||
static $singular_name = 'Form heading';
|
||||
static $plural_name = 'Form headings';
|
||||
|
||||
function getFormField() {
|
||||
// TODO customise this
|
||||
return new LabelField( $this->Title, 'FormHeading' );
|
||||
// return '<h3>' . $this->Title . '</h3>';
|
||||
}
|
||||
|
||||
function showInReports() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
?>
|
44
code/editor/EditableMemberListField.php
Normal file
44
code/editor/EditableMemberListField.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* Creates an editable field that displays members in a given group
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableMemberListField extends EditableFormField {
|
||||
|
||||
static $has_one = array(
|
||||
'Group' => 'Group'
|
||||
);
|
||||
|
||||
static $singular_name = 'Member list field';
|
||||
static $plural_name = 'Member list fields';
|
||||
|
||||
public function DefaultField() {
|
||||
// return new TreeDropdownField( "Fields[{$this->ID}][GroupID]", 'Group' );
|
||||
|
||||
$groups = DataObject::get('Group');
|
||||
|
||||
foreach( $groups as $group )
|
||||
$groupArray[$group->ID] = $group->Title;
|
||||
|
||||
return new DropdownField( "Fields[{$this->ID}][GroupID]", 'Group', $groupArray, $this->GroupID );
|
||||
}
|
||||
|
||||
public function populateFromPostData( $data ) {
|
||||
$this->GroupID = $data['GroupID'];
|
||||
|
||||
parent::populateFromPostData( $data );
|
||||
}
|
||||
|
||||
function getFormField() {
|
||||
return new DropdownField( $this->Name, $this->Title, Member::mapInGroups( $this->GroupID ) );
|
||||
}
|
||||
|
||||
function getValueFromData( $data ) {
|
||||
$value = $data[$this->Name];
|
||||
|
||||
$member = DataObject::get_one('Member', "Member.ID = {$value}");
|
||||
return $member->getName();
|
||||
}
|
||||
}
|
||||
?>
|
187
code/editor/EditableRadioField.php
Executable file
187
code/editor/EditableRadioField.php
Executable file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
/**
|
||||
* EditableDropdown
|
||||
* Represents a set of selectable radio buttons
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableRadioField extends EditableFormField {
|
||||
|
||||
static $has_many = array(
|
||||
"Options" => "EditableRadioOption"
|
||||
);
|
||||
|
||||
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;
|
||||
|
||||
foreach( $this->Options() as $option ) {
|
||||
if( $option->getField('Default') )
|
||||
return $defaultOption;
|
||||
else
|
||||
$defaultOption++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
function getFormField() {
|
||||
return $this->createField();
|
||||
}
|
||||
|
||||
function getFilterField() {
|
||||
return $this->createField( true );
|
||||
}
|
||||
|
||||
function createField( $asFilter = false ) {
|
||||
$optionSet = $this->Options();
|
||||
$options = array();
|
||||
$defaultOption = '';
|
||||
|
||||
if( $asFilter )
|
||||
$options['-1'] = '(Any)';
|
||||
|
||||
// $defaultOption = '-1';
|
||||
|
||||
foreach( $optionSet as $option ) {
|
||||
$options[$option->Title] = $option->Title;
|
||||
if( $option->getField('Default') && !$asFilter ) $defaultOption = $option->Title;
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
?>
|
84
code/editor/EditableRadioOption.php
Executable file
84
code/editor/EditableRadioOption.php
Executable file
@ -0,0 +1,84 @@
|
||||
<?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." />";
|
||||
}
|
||||
}
|
||||
?>
|
92
code/editor/EditableTextField.php
Executable file
92
code/editor/EditableTextField.php
Executable file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* EditableTextField
|
||||
* This control represents a user-defined field in a user defined form
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class EditableTextField extends EditableFormField {
|
||||
|
||||
static $db = array(
|
||||
"Size" => "Int",
|
||||
"MinLength" => "Int",
|
||||
"MaxLength" => "Int",
|
||||
"Rows" => "Int"
|
||||
);
|
||||
|
||||
static $singular_name = 'Text field';
|
||||
static $plural_name = 'Text fields';
|
||||
|
||||
function __construct( $record = null, $isSingleton = false ) {
|
||||
$this->Size = 32;
|
||||
$this->MinLength = 1;
|
||||
$this->MaxLength = 32;
|
||||
$this->Rows = 1;
|
||||
parent::__construct( $record, $isSingleton );
|
||||
}
|
||||
|
||||
function ExtraOptions() {
|
||||
|
||||
// eventually replace hard-coded "Fields"?
|
||||
$baseName = "Fields[$this->ID]";
|
||||
|
||||
$extraFields = new FieldSet(
|
||||
new TextField($baseName . "[Size]", _t('EditableTextField.TEXTBOXLENGTH', 'Length of text box'), (string)$this->Size),
|
||||
new FieldGroup(_t('EditableTextField.TEXTLENGTH', 'Text length'),
|
||||
new TextField($baseName . "[MinLength]", "", (string)$this->MinLength),
|
||||
new TextField($baseName . "[MaxLength]", " - ", (string)$this->MaxLength)
|
||||
),
|
||||
new TextField($baseName . "[Rows]", _t('EditableTextField.NUMBERROWS', 'Number of rows'), (string)$this->Rows)
|
||||
);
|
||||
|
||||
foreach( parent::ExtraOptions() as $extraField )
|
||||
$extraFields->push( $extraField );
|
||||
|
||||
if( $this->readonly )
|
||||
$extraFields = $extraFields->makeReadonly();
|
||||
|
||||
return $extraFields;
|
||||
}
|
||||
|
||||
function populateFromPostData( $data ) {
|
||||
|
||||
$this->Size = !empty( $data['Size'] ) ? $data['Size'] : 32;
|
||||
$this->MinLength = !empty( $data['MinLength'] ) ? $data['MinLength'] : 1;
|
||||
$this->MaxLength = !empty( $data['MaxLength'] ) ? $data['MaxLength'] : 32;
|
||||
$this->Rows = !empty( $data['Rows'] ) ? $data['Rows'] : 1;
|
||||
parent::populateFromPostData( $data );
|
||||
}
|
||||
|
||||
function getFormField() {
|
||||
return $this->createField();
|
||||
}
|
||||
|
||||
function getFilterField() {
|
||||
return $this->createField( true );
|
||||
}
|
||||
|
||||
function createField( $asFilter = false ) {
|
||||
if( $this->Rows == 1 )
|
||||
return new TextField( $this->Name, $this->Title, ( $asFilter ) ? "" : $this->getField('Default'), ( $this->Size && $this->Size > 0 ) ? $this->Size : null );
|
||||
else
|
||||
return new TextareaField( $this->Name, $this->Title, $this->Rows, $this->Size, ( $asFilter ) ? "" : $this->getField('Default') );
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the default fields.
|
||||
*/
|
||||
function DefaultField() {
|
||||
$disabled = '';
|
||||
if( $this->readonly ){
|
||||
$disabled = " disabled=\"disabled\"";
|
||||
} else {
|
||||
$disabled = '';
|
||||
}
|
||||
if( $this->Rows == 1 ){
|
||||
return '<div class="field text"><label class="left">'._t('EditableTextField.DEFAULTTEXT', 'Default Text').' </label> <input class="defaultText" name="Fields['.Convert::raw2att( $this->ID ).'][Default]" type="text" value="'.Convert::raw2att( $this->getField('Default') ).'"'.$disabled.' /></div>';
|
||||
}else{
|
||||
return '<div class="field text"><label class="left">'._t('EditableTextField.DEFAULTTEXT', 'Default Text').' </label> <textarea class="defaultText" name="Fields['.Convert::raw2att( $this->ID ).'][Default]"'.$disabled.'>'.Convert::raw2att( $this->getField('Default') ).'</textarea></div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
199
code/editor/FieldEditor.php
Executable file
199
code/editor/FieldEditor.php
Executable file
@ -0,0 +1,199 @@
|
||||
<?php
|
||||
/**
|
||||
* Allows CMS user to create forms dynamically.
|
||||
* @package forms
|
||||
* @subpackage fieldeditor
|
||||
*/
|
||||
class FieldEditor extends FormField {
|
||||
|
||||
protected $readonly = false;
|
||||
|
||||
function isReadonly() {
|
||||
return $this->readonly;
|
||||
}
|
||||
|
||||
function performReadonlyTransformation() {
|
||||
$this->readonly = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
function makeReadonly() {
|
||||
return $this->performReadonlyTransformation();
|
||||
}
|
||||
|
||||
function FieldHolder() {
|
||||
return $this->renderWith("FieldEditor");
|
||||
}
|
||||
|
||||
function Fields() {
|
||||
Requirements::css(SAPPHIRE_DIR . "/css/FieldEditor.css");
|
||||
Requirements::javascript(SAPPHIRE_DIR . "/javascript/FieldEditor.js");
|
||||
|
||||
$relationName = $this->name;
|
||||
|
||||
$fields = $this->form->getRecord()->$relationName();
|
||||
|
||||
if( $this->readonly ) {
|
||||
$readonlyFields = new DataObjectSet();
|
||||
|
||||
foreach( $fields as $field ) {
|
||||
$field->setEditor( $this );
|
||||
$readonlyFields->push( $field->makeReadonly() );
|
||||
}
|
||||
|
||||
$fields = $readonlyFields;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
function saveInto(DataObject $record) {
|
||||
|
||||
$name = $this->name;
|
||||
$fieldSet = $record->$name();
|
||||
|
||||
$record->EmailTo = $_REQUEST[$name]['EmailTo'];
|
||||
$record->EmailOnSubmit = isset( $_REQUEST[$name]['EmailOnSubmit'] ) ? "1" : "0";
|
||||
$record->SubmitButtonText = $_REQUEST[$name]['SubmitButtonText'];
|
||||
|
||||
// store the field IDs and delete the missing fields
|
||||
// alternatively, we could delete all the fields and re add them
|
||||
$missingFields = array();
|
||||
|
||||
foreach( $fieldSet as $existingField ){
|
||||
$missingFields[$existingField->ID] = $existingField;
|
||||
}
|
||||
|
||||
// write the new fields to the database
|
||||
if($_REQUEST[$name]){
|
||||
foreach( array_keys( $_REQUEST[$name] ) as $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'" );
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 addNewField( $newField ) {
|
||||
$newField->ParentID = $this->ID;
|
||||
$newField->write();
|
||||
return $this->renderWith("FieldEditor");
|
||||
}*/
|
||||
|
||||
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*/
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
function adddropdownfield() {
|
||||
return $this->addNewField( new EditableDropdown() );
|
||||
}
|
||||
|
||||
function addcheckboxfield() {
|
||||
return $this->addNewField( new EditableCheckbox() );
|
||||
}
|
||||
|
||||
protected $haveFormOptions = true;
|
||||
|
||||
function setHaveFormOptions($bool){
|
||||
$this->haveFormOptions = $bool;
|
||||
}
|
||||
|
||||
function getHaveFormOptions(){
|
||||
return $this->haveFormOptions;
|
||||
}
|
||||
|
||||
function FormOptions() {
|
||||
if($this->haveFormOptions){
|
||||
$fields = new FieldSet(
|
||||
new EmailField( "{$this->name}[EmailTo]", _t('FieldEditor.EMAILSUBMISSION', 'Email submission to:'), $this->form->getRecord()->EmailTo ),
|
||||
new CheckboxField( "{$this->name}[EmailOnSubmit]", _t('FieldEditor.EMAILONSUBMIT', 'Email form on submit:'), $this->form->getRecord()->EmailOnSubmit )
|
||||
);
|
||||
|
||||
if( $this->form->getRecord()->hasMethod( 'customFormActions' ) ) {
|
||||
$newFields = $this->form->getRecord()->customFormActions( $this->readonly );
|
||||
|
||||
foreach( $newFields as $newField ) {
|
||||
$newField->setName( "{$this->name}[{$newField->Name()}]" );
|
||||
$fields->push( $newField );
|
||||
}
|
||||
}
|
||||
if( $this->readonly )
|
||||
$fields = $fields->makeReadonly();
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
?>
|
13
code/editor/SubmittedFileField.php
Executable file
13
code/editor/SubmittedFileField.php
Executable file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* A file uploaded on a UserDefinedForm field
|
||||
* @package cms
|
||||
*/
|
||||
class SubmittedFileField extends SubmittedFormField {
|
||||
|
||||
static $has_one = array(
|
||||
"UploadedFile" => "File"
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
24
code/editor/SubmittedForm.php
Executable file
24
code/editor/SubmittedForm.php
Executable file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* Contents of an UserDefinedForm submission
|
||||
* @package cms
|
||||
*/
|
||||
class SubmittedForm extends DataObject {
|
||||
static $has_one = array(
|
||||
"SubmittedBy" => "Member",
|
||||
"Parent" => "UserDefinedForm",
|
||||
);
|
||||
|
||||
static $db = array(
|
||||
"Recipient" => "Varchar"
|
||||
);
|
||||
|
||||
static $has_many = array(
|
||||
"FieldValues" => "SubmittedFormField"
|
||||
);
|
||||
|
||||
function SubmitTime() {
|
||||
return $this->Created;
|
||||
}
|
||||
}
|
||||
?>
|
18
code/editor/SubmittedFormField.php
Executable file
18
code/editor/SubmittedFormField.php
Executable file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* Data received from a UserDefinedForm submission
|
||||
* @package cms
|
||||
*/
|
||||
class SubmittedFormField extends DataObject {
|
||||
|
||||
static $db = array(
|
||||
"Name" => "Varchar",
|
||||
"Value" => "Text",
|
||||
"Title" => "Varchar"
|
||||
);
|
||||
|
||||
static $has_one = array(
|
||||
"Parent" => "SubmittedForm"
|
||||
);
|
||||
}
|
||||
?>
|
26
code/editor/SubmittedFormReportField.php
Executable file
26
code/editor/SubmittedFormReportField.php
Executable file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* Displays a summary of instances of a form submitted to the website
|
||||
* @package cms
|
||||
*/
|
||||
class SubmittedFormReportField extends FormField {
|
||||
|
||||
/**
|
||||
* Displays the form (without defaults) submitted as it appears on the front of the site
|
||||
* Users will use this instance of the form to filter results
|
||||
*/
|
||||
function Form() {
|
||||
/*return $this->form->Form();*/
|
||||
}
|
||||
|
||||
function Field() {
|
||||
Requirements::css(SAPPHIRE_DIR . "/css/SubmittedFormReportField.css");
|
||||
|
||||
return $this->renderWith("SubmittedFormReportField");
|
||||
}
|
||||
|
||||
function Submissions() {
|
||||
return $this->form->getRecord()->Submissions();
|
||||
}
|
||||
}
|
||||
?>
|
202
css/FieldEditor.css
Executable file
202
css/FieldEditor.css
Executable file
@ -0,0 +1,202 @@
|
||||
* {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
div.FieldEditor {
|
||||
border: 1px solid #CCCCCC;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
div.FieldEditor ul.Menu {
|
||||
margin: 0;
|
||||
padding: 3px;
|
||||
background-color: #eee;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div.FieldEditor div.FormOptions div.CompositeField {
|
||||
margin-left: 4em;
|
||||
}
|
||||
|
||||
div.FieldEditor div.FormOptions label.left {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div.FieldEditor div.FormOptions label.right,
|
||||
div.FieldEditor div.FormOptions label.CustomActionLabel {
|
||||
margin-left: 0em;
|
||||
float: none;
|
||||
line-height: auto;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.FieldEditor input.checkbox {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
div.FieldEditor ul.Menu li {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
div.FieldEditor div.FieldList {
|
||||
background-color: white;
|
||||
border-bottom: 1px solid #CCCCCC;
|
||||
border-top: 1px solid #CCCCCC;
|
||||
height: 75%;
|
||||
/*overflow-y: scroll;*/
|
||||
}
|
||||
|
||||
div.FieldEditor div.FormOptions {
|
||||
background-color: #EEEEEE;
|
||||
position: relative;
|
||||
float: left;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
div.FieldEditor div.FormOptions div.field {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div.FieldEditor div.FormOptions div.optionset li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.FieldEditor div.FormOptions div.optionset li label {
|
||||
float: none !important;
|
||||
}
|
||||
|
||||
.DragEditable {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div.FieldEditor ul li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.FieldEditor ul a {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
div.FieldEditor ul a:hover {
|
||||
background-color: #CCCCCC;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* EditableFormField - Default class for all editable form fields
|
||||
********************************************************************/
|
||||
|
||||
div.EditableFormField {
|
||||
padding: 3px;
|
||||
border-top: 1px dashed #CCCCCC;
|
||||
}
|
||||
|
||||
div.EditableFormField.mouseOver {
|
||||
background-color: #f3ef9d;
|
||||
}
|
||||
|
||||
div.EditableFormField div.hidden {
|
||||
display: none;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
div.EditableFormField div.FieldInfo {
|
||||
margin: 0px;
|
||||
padding-right: -3px;
|
||||
}
|
||||
|
||||
div.EditableFormField div.FieldInfo * {
|
||||
display: inline;
|
||||
margin-right: 3px;
|
||||
margin-left: 0px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.EditableFormField div.FieldInfo input,
|
||||
div.EditableFormField div.FieldDefault input {
|
||||
width: 250px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
div.EditableFormField div.ExtraOptions {
|
||||
display: none;
|
||||
margin: 3px 0px 3px 57px;
|
||||
background-color: #EEEEEE;
|
||||
/* IE has background issues without this */
|
||||
/*position: relative;*/
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* EditableDateField
|
||||
********************************************************************/
|
||||
|
||||
div.EditableDateField div.FieldDefault input {
|
||||
width: 2em;
|
||||
}
|
||||
|
||||
div.EditableDateField div.FieldDefault input.year {
|
||||
width: 4em;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* EditableEmailField
|
||||
********************************************************************/
|
||||
|
||||
/*********************************************************************
|
||||
* EditableDropdown
|
||||
********************************************************************/
|
||||
|
||||
#right #Form_EditForm div.EditableMultiOptionFormField div.FieldDefault ul.EditableDropdownOptions {
|
||||
border: solid 1px #7F9DB9;
|
||||
/* IE */
|
||||
margin: 0px;
|
||||
/* display: none; */
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#right #Form_EditForm div.EditableDropdown select {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#right #Form_EditForm div.EditableDropdown select,
|
||||
#right #Form_EditForm div.EditableMultiOptionFormField ul.EditableDropdownOptions {
|
||||
width: 250px;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
#right #Form_EditForm li.EditableFormFieldOption {
|
||||
display: block;
|
||||
padding: 2px 0px;
|
||||
}
|
||||
|
||||
#right #Form_EditForm li.EditableFormFieldOption * {
|
||||
vertical-align: middle;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#right #Form_EditForm li.EditableFormFieldOption a {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#right #Form_EditForm li.EditableFormFieldOption input.text {
|
||||
width: 170px !important;
|
||||
}
|
||||
|
||||
#right #Form_EditForm li.EditableFormFieldOption input.radio,
|
||||
#right #Form_EditForm li.EditableFormFieldOption input.checkbox {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
#right #Form_EditForm li.AddDropdownOption {
|
||||
border-top: dashed 1px #7F9DB9;
|
||||
padding-left: 37px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Need first rule in order to overwrite */
|
||||
#right #Form_EditForm li.AddDropdownOption input.text {
|
||||
width: 170px !important;
|
||||
margin-left: 0px;
|
||||
}
|
555
javascript/FieldEditor.js
Executable file
555
javascript/FieldEditor.js
Executable file
@ -0,0 +1,555 @@
|
||||
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++ ) {
|
||||
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 ) {
|
||||
this.getElementsByTagName('div')[0].removeChild( optionToRemove );
|
||||
}
|
||||
}
|
||||
|
||||
FieldEditorField = Class.create();
|
||||
|
||||
FieldEditorField.prototype = {
|
||||
initialize: function() {
|
||||
var fieldInfoDiv = this.findDescendant( 'div', 'FieldInfo' );
|
||||
|
||||
this.titleField = this.findDescendant( 'input', 'text', element );
|
||||
|
||||
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.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');
|
||||
|
||||
}
|
3
lang/en_US.php
Normal file
3
lang/en_US.php
Normal file
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
?>
|
26
templates/EditableCheckbox.ss
Executable file
26
templates/EditableCheckbox.ss
Executable file
@ -0,0 +1,26 @@
|
||||
<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="sapphire/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>
|
51
templates/EditableCheckboxGroupField.ss
Executable file
51
templates/EditableCheckboxGroupField.ss
Executable file
@ -0,0 +1,51 @@
|
||||
<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="sapphire/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>
|
10
templates/EditableCheckboxOption.ss
Executable file
10
templates/EditableCheckboxOption.ss
Executable file
@ -0,0 +1,10 @@
|
||||
<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>
|
20
templates/EditableDateField.ss
Executable file
20
templates/EditableDateField.ss
Executable file
@ -0,0 +1,20 @@
|
||||
<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="sapphire/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>
|
50
templates/EditableDropdown.ss
Executable file
50
templates/EditableDropdown.ss
Executable file
@ -0,0 +1,50 @@
|
||||
<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="sapphire/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>
|
10
templates/EditableDropdownOption.ss
Executable file
10
templates/EditableDropdownOption.ss
Executable file
@ -0,0 +1,10 @@
|
||||
<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>
|
25
templates/EditableEmailField.ss
Executable file
25
templates/EditableEmailField.ss
Executable file
@ -0,0 +1,25 @@
|
||||
<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="sapphire/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>
|
20
templates/EditableFileField.ss
Executable file
20
templates/EditableFileField.ss
Executable file
@ -0,0 +1,20 @@
|
||||
<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="sapphire/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>
|
44
templates/EditableFormField.ss
Executable file
44
templates/EditableFormField.ss
Executable file
@ -0,0 +1,44 @@
|
||||
<div class="$ClassName 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="sapphire/images/fe_icons/{$ClassName.LowerCase}.png" alt="$ClassName" title="$singular_name" />
|
||||
$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>
|
||||
<% if Options %>
|
||||
<div class="hidden">
|
||||
<% control Options %>
|
||||
<% if isReadonly %>
|
||||
$ReadonlyOption
|
||||
<% else %>
|
||||
$Option
|
||||
<% end_if %>
|
||||
<% end_control %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
<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="$ClassName" />
|
||||
<input type="hidden" name="$Name.Attr[Sort]" value="-1" />
|
||||
</div>
|
15
templates/EditableFormFieldOption.ss
Executable file
15
templates/EditableFormFieldOption.ss
Executable file
@ -0,0 +1,15 @@
|
||||
<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>
|
17
templates/EditableFormHeading.ss
Executable file
17
templates/EditableFormHeading.ss
Executable file
@ -0,0 +1,17 @@
|
||||
<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="sapphire/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>
|
51
templates/EditableRadioField.ss
Executable file
51
templates/EditableRadioField.ss
Executable file
@ -0,0 +1,51 @@
|
||||
<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="sapphire/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>
|
10
templates/EditableRadioOption.ss
Executable file
10
templates/EditableRadioOption.ss
Executable file
@ -0,0 +1,10 @@
|
||||
<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>
|
20
templates/EditableTextField.ss
Executable file
20
templates/EditableTextField.ss
Executable file
@ -0,0 +1,20 @@
|
||||
<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="sapphire/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>
|
81
templates/FieldEditor.ss
Executable file
81
templates/FieldEditor.ss
Executable file
@ -0,0 +1,81 @@
|
||||
<div class="FieldEditor <% if isReadonly %>readonly<% end_if %>" id="Fields" name="$Name.Attr">
|
||||
<ul class="TopMenu Menu">
|
||||
<li><% _t('ADD', 'Add') %>:</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('TEXTTITLE', 'Add text field') %>" id="TextField"><% _t('TEXT', 'Text') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('CHECKBOXTITLE', 'Add checkbox') %>" id="Checkbox"><% _t('CHECKBOX', 'Checkbox') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('DROPDOWNTITLE', 'Add dropdown') %>" id="Dropdown"><% _t('DROPDOWN', 'Dropdown') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('RADIOSETTITLE', 'Add radio button set') %>" id="RadioField"><% _t('RADIOSET', 'Radio') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('EMAILTITLE', 'Add email field') %>" id="EmailField"><% _t('EMAIL', 'Email') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('FORMHEADINGTITLE', 'Add form heading') %>" id="FormHeading"><% _t('FORMHEADING', 'Heading') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('DATETITLE', 'Add date heading') %>" id="DateField"><% _t('DATE', 'Date') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('FILETITLE', 'Add file upload field') %>" id="FileField"><% _t('FILE', 'File') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('CHECKBOXGROUPTITLE', 'Add checkbox group field') %>" id="CheckboxGroupField"><% _t('CHECKBOXGROUP', 'Checkboxes') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('MEMBERTITLE', 'Add member list field') %>" id="MemberListField"><% _t('MEMBER', 'Member List') %></a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="FieldList" id="Fields_fields">
|
||||
<% control Fields %>
|
||||
<% if isReadonly %>
|
||||
$ReadonlyEditSegment
|
||||
<% else %>
|
||||
$EditSegment
|
||||
<% end_if %>
|
||||
<% end_control %>
|
||||
</div>
|
||||
<ul class="BottomMenu Menu">
|
||||
<li><% _t('ADD', 'Add') %>:</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('TEXTTITLE', 'Add text field') %>" id="TextField"><% _t('TEXT', 'Text') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('CHECKBOXTITLE', 'Add checkbox') %>" id="Checkbox"><% _t('CHECKBOX', 'Checkbox') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('DROPDOWNTITLE', 'Add dropdown') %>" id="Dropdown"><% _t('DROPDOWN', 'Dropdown') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('RADIOSETTITLE', 'Add radio button set') %>" id="RadioField"><% _t('RADIOSET', 'Radio') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('EMAILTITLE', 'Add email field') %>" id="EmailField"><% _t('EMAIL', 'Email') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('FORMHEADINGTITLE', 'Add form heading') %>" id="FormHeading"><% _t('FORMHEADING', 'Heading') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('DATETITLE', 'Add date heading') %>" id="DateField"><% _t('DATE', 'Date') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('FILETITLE', 'Add file upload field') %>" id="FileField"><% _t('FILE', 'File') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('CHECKBOXGROUPTITLE', 'Add checkbox group field') %>" id="CheckboxGroupField"><% _t('CHECKBOXGROUP', 'Checkboxes') %></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" title="<% _t('MEMBERTITLE', 'Add member list field') %>" id="MemberListField"><% _t('MEMBER', 'Member List') %></a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="FormOptions">
|
||||
<% control FormOptions %>
|
||||
$FieldHolder
|
||||
<% end_control %>
|
||||
</div></div>
|
18
templates/SubmittedFormReportField.ss
Normal file
18
templates/SubmittedFormReportField.ss
Normal file
@ -0,0 +1,18 @@
|
||||
<div class="reportfilter">
|
||||
$FilterForm
|
||||
</div>
|
||||
<div class="reports" id="FormSubmissions">
|
||||
<% control Submissions %>
|
||||
<div class="report">
|
||||
<span class="submitted"><% _t('SUBMITTED', 'Submitted at') %> $Created.Nice <% if Recipient %>to $Recipient<% end_if %></span>
|
||||
<table>
|
||||
<% control FieldValues %>
|
||||
<tr>
|
||||
<td class="field">$Title</td>
|
||||
<td class="value">$Value</td>
|
||||
</tr>
|
||||
<% end_control %>
|
||||
</table>
|
||||
</div>
|
||||
<% end_control %>
|
||||
</div>
|
21
templates/email/SubmittedFormEmail.ss
Executable file
21
templates/email/SubmittedFormEmail.ss
Executable file
@ -0,0 +1,21 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<h1>$Subject</h1>
|
||||
<p>
|
||||
<% _t('SUBMITTED','The following data was submitted to your website:') %>
|
||||
|
||||
</p>
|
||||
$Body
|
||||
|
||||
<table>
|
||||
<% control Fields %>
|
||||
<tr>
|
||||
<td><b>$Title</b></td>
|
||||
<td>$Value</td>
|
||||
</tr>
|
||||
<% end_control %>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user