diff --git a/README.md b/README.md index afd29cc..5d3db52 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ SilverStripe Grid Field Extensions Module This module provides a number of useful grid field components: * `GridFieldAddExistingSearchButton` - a more advanced search form for adding items. +* `GridFieldAddNewMultiClass` - lets the user select from a list of classes to create a new record from. * `GridFieldOrderableRows` - drag and drop re-ordering of rows. Maintainer Contacts diff --git a/code/GridFieldAddNewMultiClass.php b/code/GridFieldAddNewMultiClass.php new file mode 100644 index 0000000..fa1d30f --- /dev/null +++ b/code/GridFieldAddNewMultiClass.php @@ -0,0 +1,162 @@ +setFragment($fragment); + $this->setTitle(_t('GridFieldExtensions.ADD', 'Add')); + } + + /** + * Gets the fragment name this button is rendered into. + * + * @return string + */ + public function getFragment() { + return $this->fragment; + } + + /** + * Sets the fragment name this button is rendered into. + * + * @param string $fragment + */ + public function setFragment($fragment) { + $this->fragment = $fragment; + } + + /** + * Gets the button title text. + * + * @return string + */ + public function getTitle() { + return $this->title; + } + + /** + * Sets the button title text. + * + * @param string $title + */ + public function setTitle($title) { + $this->title = $title; + } + + /** + * Gets the classes that can be created using this button, defaulting to the model class and + * its subclasses. + * + * @param GridField $grid + * @return array a map of class name to title + */ + protected function getClasses($grid) { + $result = array(); + + if(is_null($this->classes)) { + $classes = array_values(ClassInfo::subclassesFor($grid->getModelClass())); + } else { + $classes = $this->classes; + } + + foreach($classes as $class => $title) { + if(!is_string($class)) { + $class = $title; + $title = singleton($class)->i18n_singular_name(); + } + + if(!singleton($class)->canCreate()) { + continue; + } + + $result[$class] = $title; + } + + return $result; + } + + /** + * Sets the classes that can be created using this button. + * + * @param array $classes a set of class names, optionally mapped to titles + */ + public function setClasses(array $classes) { + $this->classes = $classes; + } + + /** + * Handles adding a new instance of a selected class. + * + * @param GridField $grid + * @param SS_HTTPRequest $request + */ + public function handleAdd($grid, $request) { + $class = $request->param('ClassName'); + $classes = $this->getClasses($grid); + $component = $grid->getConfig()->getComponentByType('GridFieldDetailForm'); + + if(!$component) { + throw new Exception('The add new multi class component requires the detail form component.'); + } + + if(!$class || !array_key_exists($class, $classes)) { + throw new SS_HTTPResponse_Exception(400); + } + + $handler = new GridFieldAddNewMultiClassHandler( + $grid, $component, new $class(), $grid->getForm()->getController(), 'add-multi-class' + ); + $handler->setTemplate($component->getTemplate()); + + return $handler; + } + + /** + * {@inheritDoc} + */ + public function getHTMLFragments($grid) { + $classes = $this->getClasses($grid); + + if(!count($classes)) { + return array(); + } + + $field = new DropdownField(sprintf('%s[ClassName]', __CLASS__), '', $classes); + $field->setEmptyString(_t('GridFieldExtensions.SELECTTYPETOCREATE', '(Select type to create)')); + $field->addExtraClass('no-change-track'); + + $data = new ArrayData(array( + 'Title' => $this->getTitle(), + 'Link' => Controller::join_links($grid->Link(), 'add-multi-class'), + 'ClassField' => $field + )); + + return array( + $this->getFragment() => $data->renderWith(__CLASS__) + ); + } + + /** + * {@inheritDoc} + */ + public function getURLHandlers($grid) { + return array( + 'add-multi-class/$ClassName!' => 'handleAdd' + ); + } + +} diff --git a/code/GridFieldAddNewMultiClassHandler.php b/code/GridFieldAddNewMultiClassHandler.php new file mode 100644 index 0000000..cf99b5b --- /dev/null +++ b/code/GridFieldAddNewMultiClassHandler.php @@ -0,0 +1,17 @@ +record->ID) { + return parent::Link($action); + } else { + return Controller::join_links( + $this->gridField->Link(), 'add-multi-class', get_class($this->record) + ); + } + } + +} diff --git a/css/GridFieldExtensions.css b/css/GridFieldExtensions.css index b55a5a9..df0e733 100644 --- a/css/GridFieldExtensions.css +++ b/css/GridFieldExtensions.css @@ -55,6 +55,21 @@ padding: 6px; } +/** + * GridFieldAddNewMultiClass + */ + +.ss-gridfield-add-new-multi-class { + margin-bottom: 8px !important; +} + +.ss-gridfield-add-new-multi-class .field { + border: none; + box-shadow: none; + float: left; + margin: 0 4px 0 0; +} + /** * GridFieldOrderableRows */ diff --git a/javascript/GridFieldExtensions.js b/javascript/GridFieldExtensions.js index 8a14691..7642311 100644 --- a/javascript/GridFieldExtensions.js +++ b/javascript/GridFieldExtensions.js @@ -72,6 +72,41 @@ } }); + /** + * GridFieldAddNewMultiClass + */ + + $(".ss-gridfield-add-new-multi-class .ss-ui-button").entwine({ + onclick: function() { + var link = this.prop("href"); + var cls = this.parents(".ss-gridfield-add-new-multi-class").find("select").val(); + + if(cls && cls.length) { + this.getGridField().showDetailView(link + "/" + cls); + } + + return false; + } + }); + + $(".ss-gridfield-add-new-multi-class select").entwine({ + onadd: function() { + this.update(); + }, + onchange: function() { + this.update(); + }, + update: function() { + var btn = this.parents(".ss-gridfield-add-new-multi-class").find(".ss-ui-button"); + + if(this.val() && this.val().length) { + btn.button("enable"); + } else { + btn.button("disable"); + } + } + }); + /** * GridFieldOrderableRows */ diff --git a/templates/GridFieldAddNewMultiClass.ss b/templates/GridFieldAddNewMultiClass.ss new file mode 100644 index 0000000..b6165c4 --- /dev/null +++ b/templates/GridFieldAddNewMultiClass.ss @@ -0,0 +1,7 @@ +
+ $ClassField.FieldHolder + + + $Title + +