(merged from branches/roa. use "svn log -c <changeset> -g <module-svn-path>" for detailed commit message)

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@60204 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2008-08-09 02:16:46 +00:00
parent 05ad3c8e1c
commit 83fff5f1c1
3 changed files with 166 additions and 38 deletions

View File

@ -42,6 +42,17 @@ abstract class ModelAdmin extends LeftAndMain {
'delete' 'delete'
); );
/**
* Model object currently in manipulation queue. Used for updating Link to point
* to the correct generic data object in generated URLs.
*
* @var string
*/
private $currentModel = false;
/**
* Initialize the model admin interface. Sets up embedded jquery libraries and requisite plugins
*/
public function init() { public function init() {
parent::init(); parent::init();
@ -50,13 +61,34 @@ abstract class ModelAdmin extends LeftAndMain {
user_error('ModelAdmin::init(): Invalid Model class', E_USER_ERROR); user_error('ModelAdmin::init(): Invalid Model class', E_USER_ERROR);
} }
Requirements::css('cms/css/ModelAdmin.css'); Requirements::css('cms/css/ModelAdmin.css'); // standard layout formatting for management UI
Requirements::css('cms/css/silverstripe.tabs.css'); // follows the jQuery UI theme conventions
Requirements::javascript('jsparty/jquery/jquery.js');
Requirements::javascript('jsparty/jquery/livequery/jquery.livequery.js');
Requirements::javascript('jsparty/jquery/ui/ui/ui.base.js');
Requirements::javascript('jsparty/jquery/ui/ui/ui.tabs.js');
Requirements::javascript('jsparty/jquery/ui/plugins/form/jquery.form.js');
Requirements::javascript('cms/javascript/ModelAdmin.js');
} }
/**
* Add mappings for generic form constructors to automatically delegate to a scaffolded form object.
*/
function defineMethods() {
parent::defineMethods();
foreach($this->getManagedModels() as $class) {
$this->addWrapperMethod('SearchForm_' . $class, 'getSearchFormForModel');
$this->addWrapperMethod('AddForm_' . $class, 'getAddFormForModel');
$this->addWrapperMethod('EditForm_' . $class, 'getEditFormForModel');
}
}
/** /**
* Return default link to this controller * Return default link to this controller
* *
* @todo We've specified this in Director::addRules(), why repeat? * @todo extract full URL binding from Director::addRules so that it's not tied to 'admin/crm'
* @todo is there a way of removing the dependency on this method from the Form?
* *
* @return string * @return string
*/ */
@ -91,13 +123,11 @@ abstract class ModelAdmin extends LeftAndMain {
} }
/** /**
* @todo documentation
* *
* @param array $data * @param array $data
* @param Form $form
*/ */
public function save($data, $form) { public function save($data, $form) {
// @todo implementation Debug::dump($data);
} }
/** /**
@ -112,7 +142,7 @@ abstract class ModelAdmin extends LeftAndMain {
$form = new Form( $form = new Form(
$this, $this,
'AddForm_add', "AddForm",
new FieldSet( new FieldSet(
new DropdownField('ClassName', 'Type', $modelMap) new DropdownField('ClassName', 'Type', $modelMap)
), ),
@ -120,6 +150,7 @@ abstract class ModelAdmin extends LeftAndMain {
new FormAction('add', _t('GenericDataAdmin.CREATE')) new FormAction('add', _t('GenericDataAdmin.CREATE'))
) )
); );
$form->setFormMethod('get');
return $form; return $form;
} }
@ -156,21 +187,14 @@ abstract class ModelAdmin extends LeftAndMain {
*/ */
protected function getEditForm($modelClass) { protected function getEditForm($modelClass) {
$modelObj = singleton($modelClass); $modelObj = singleton($modelClass);
$formName = "EditForm_$modelClass";
$fields = $this->getFieldsForModel($modelObj); $fields = $this->getFieldsForModel($modelObj);
$this->getComponentFieldsForModel($modelObj, $fields);
$actions = $this->getActionsForModel($modelObj); $actions = $this->getActionsForModel($modelObj);
$validator = $this->getValidatorForModel($modelObj); $validator = $this->getValidatorForModel($modelObj);
// necessary because of overriding the form action - NEED TO VERIFY THIS
$form = new Form( $fields->push(new HiddenField("executeForm", $formName));
$this, $form = new Form($this, $formName, $fields, $actions, $validator);
'ModelEditForm',
$fields,
$actions,
$validator
);
return $form; return $form;
} }
@ -197,7 +221,28 @@ abstract class ModelAdmin extends LeftAndMain {
* @return FieldSet * @return FieldSet
*/ */
protected function getFieldsForModel($modelObj) { protected function getFieldsForModel($modelObj) {
return $modelObj->getCMSFields(); $fields = $modelObj->getCMSFields();
if (!$fields->dataFieldByName('ID')) {
$fields->push(new HiddenField('ID'));
}
return $fields;
}
/**
* Update: complex table field generation moved into controller - could be
* in the DataObject scaffolding?
*
* @param unknown_type $modelObj
* @return FieldSet of ComplexTableFields
*/
protected function getComponentFieldsForModel($modelObj, $fieldSet) {
foreach($modelObj->has_many() as $relationship => $component) {
$relationshipFields = array_keys(singleton($component)->searchableFields());
$fieldSet->push(new ComplexTableField($this, $relationship, $component, $relationshipFields));
}
return $fieldSet;
} }
/** /**
@ -214,7 +259,6 @@ abstract class ModelAdmin extends LeftAndMain {
new FormAction('save', _t('GenericDataAdmin.SAVE')), new FormAction('save', _t('GenericDataAdmin.SAVE')),
new FormAction('delete', _t('GenericDataAdmin.DELETE')) new FormAction('delete', _t('GenericDataAdmin.DELETE'))
); );
return $actions; return $actions;
} }
@ -230,7 +274,7 @@ abstract class ModelAdmin extends LeftAndMain {
protected function getValidatorForModel($modelObj) { protected function getValidatorForModel($modelObj) {
return false; return false;
} }
/** /**
* Get a search form for a single {@link DataObject} subclass. * Get a search form for a single {@link DataObject} subclass.
* *
@ -238,18 +282,19 @@ abstract class ModelAdmin extends LeftAndMain {
* @return FieldSet * @return FieldSet
*/ */
protected function getSearchFormForModel($modelClass) { protected function getSearchFormForModel($modelClass) {
if(substr($modelClass,0,11) == 'SearchForm_') $modelClass = substr($modelClass, 11);
$context = singleton($modelClass)->getDefaultSearchContext(); $context = singleton($modelClass)->getDefaultSearchContext();
$form = new Form( $form = new Form(
$this, $this,
"SearchForm_search_{$modelClass}", "SearchForm_$modelClass",
$context->getSearchFields(), $context->getSearchFields(),
new FieldSet( new FieldSet(
new FormAction('search', _t('MemberTableField.SEARCH')) new FormAction('search', _t('MemberTableField.SEARCH'))
) )
); );
//can't set generic search form as GET because of weirdness with FormObjectLink $form->setFormMethod('get');
//$form->setFormMethod('get');
return $form; return $form;
} }
@ -257,25 +302,19 @@ abstract class ModelAdmin extends LeftAndMain {
* Overwrite the default form action with the path to the DataObject filter * Overwrite the default form action with the path to the DataObject filter
* (relies on the search form having the specifically named id as 'SearchForm_DataObject') * (relies on the search form having the specifically named id as 'SearchForm_DataObject')
* *
* @todo extract hard-coded prefix and generate from Director settings * @todo override default linking to add DataObject based URI paths
*/ */
function FormObjectLink($formName) { function FormObjectLink($formName) {
$segments = explode('_', $formName); return $this->Link();
if (count($segments) == 3) {
return Director::absoluteBaseURL()."admin/crm/{$segments[1]}/{$segments[2]}";
} elseif (count($segments) == 2) {
return Director::absoluteBaseURL()."admin/crm/{$segments[1]}";
} else {
return "?executeForm=$formName";
}
} }
/** /**
* Action to render a data object collection, using the model context to provide filters * Action to render a data object collection, using the model context to provide filters
* and paging. * and paging.
*/ */
function search() { function search($data, $form) {
$className = $this->urlParams['ClassName']; $className = $this->urlParams['ClassName'];
Debug::dump($className);
if (in_array($className, $this->getManagedModels())) { if (in_array($className, $this->getManagedModels())) {
$model = singleton($className); $model = singleton($className);
// @todo need to filter post vars // @todo need to filter post vars
@ -306,7 +345,7 @@ abstract class ModelAdmin extends LeftAndMain {
* View a generic model using a form object to render a partial HTML * View a generic model using a form object to render a partial HTML
* fragment to be embedded via Ajax calls. * fragment to be embedded via Ajax calls.
*/ */
function view() { function show() {
$className = $this->urlParams['ClassName']; $className = $this->urlParams['ClassName'];
$ID = $this->urlParams['ID']; $ID = $this->urlParams['ID'];
@ -314,14 +353,15 @@ abstract class ModelAdmin extends LeftAndMain {
$model = DataObject::get_by_id($className, $ID); $model = DataObject::get_by_id($className, $ID);
$fields = $model->getCMSFields(); /*$fields = $model->getCMSFields();
$actions = new FieldSet( $actions = new FieldSet(
new FormAction('save', 'Save') new FormAction('save', 'Save')
); );
$form = new Form($this, $className, $fields, $actions); $form = new Form($this, $className, $fields, $actions);
$form->makeReadonly(); $form->makeReadonly();*/
$form = $this->getEditForm($className);
$form->loadNonBlankDataFrom($model); $form->loadNonBlankDataFrom($model);
return $form->forTemplate(); return $form->forTemplate();
} }

31
css/silverstripe.tabs.css Normal file
View File

@ -0,0 +1,31 @@
/**
* SilverStripe specific styles that map to elements from the jQuery UI theme.
*
* This is not a fully functional tab module, but the file naming convention reflects
* the jQuery theme format
*
* @todo move generic tab styles into this file
* @todo add to silverstripe specific branch of /jsparty/jquery/ui/themes
*/
/* Caution! Ensure accessibility in print and other media types... */
@media projection, screen { /* Use class for showing/hiding tab content, so that visibility can be better controlled in different media types... */
.ui-tabs-hide {
display: none;
}
}
/* Hide useless elements in print layouts... */
@media print {
.ui-tabs-nav {
display: none;
}
}
/**
* stuff for search forms
*/
.loading {
cursor:hourglass;
}

View File

@ -0,0 +1,57 @@
jQuery(document).ready(function() {
function showRecord(uri) {
jQuery.get(uri, function(result){
jQuery('#right').html(result);
Behaviour.apply();
});
}
function saveRecord(uri, data) {
//jQuery.post(uri, data, function(result) {)
}
jQuery('#AddForm_holder form').submit(function(){
className = jQuery('select option:selected', this).val();
// @todo remove dependency on hardcoded URL path
requestPath = jQuery(this).attr('action') + '/add/' + className;
showRecord(requestPath);
return false;
});
// attach generic action handler to all forms displayed in the #right panel
jQuery('#right .action').click(function(){
alert('do something here');
return false;
});
jQuery('#SearchForm_holder').tabs();
jQuery('.tab form').submit(function(){
form = jQuery(this);
var data = {};
jQuery('*[name]', form).each(function(){
var t = jQuery(this);
var val = (t.attr('type') == 'checkbox') ? (t.attr('checked') == true) ? 1 : 0 : t.val();
data[t.attr('name')] = val;
});
jQuery.get(form.attr('action'), data, function(result){
jQuery('#ResultTable_holder').html(result);
jQuery('#ResultTable_holder td').click(function(){
td = jQuery(this);
showRecord(td.parent().attr('id'));
td.parent().parent().find('td').removeClass('active');
td.addClass('active').siblings().addClass('active');
}).hover(function(){
jQuery(this).addClass('over').siblings().addClass('over')
}, function(){
jQuery(this).removeClass('over').siblings().removeClass('over')
});
});
return false;
});
});