From 692453bf9b421903ca69cde1caa942f89e175e8d Mon Sep 17 00:00:00 2001 From: ajshort Date: Sat, 9 Feb 2013 02:19:30 +1100 Subject: [PATCH] Implement inline creation of records. * Builds on the editable cols component with GridFieldAddNewInlineButton. * Closes #2. --- README.md | 1 + code/GridFieldAddNewInlineButton.php | 142 +++++++++++++++++++++++ code/GridFieldEditableColumns.php | 4 +- css/GridFieldExtensions.css | 8 ++ javascript/GridFieldExtensions.js | 33 ++++++ templates/GridFieldAddNewInlineButton.ss | 3 + templates/GridFieldAddNewInlineRow.ss | 13 +++ 7 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 code/GridFieldAddNewInlineButton.php create mode 100644 templates/GridFieldAddNewInlineButton.ss create mode 100644 templates/GridFieldAddNewInlineRow.ss diff --git a/README.md b/README.md index c3b4543d..ed33f1a7 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. +* `GridFieldAddNewInlineButton` - builds on `GridFieldEditableColumns` to allow inline creation of records. * `GridFieldAddNewMultiClass` - lets the user select from a list of classes to create a new record from. * `GridFieldEditableColumns` - allows inline editing of records. * `GridFieldOrderableRows` - drag and drop re-ordering of rows. diff --git a/code/GridFieldAddNewInlineButton.php b/code/GridFieldAddNewInlineButton.php new file mode 100644 index 00000000..0780dd7b --- /dev/null +++ b/code/GridFieldAddNewInlineButton.php @@ -0,0 +1,142 @@ +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; + } + + public function getHTMLFragments($grid) { + $class = $grid->getModelClass(); + $fragment = $this->getFragment(); + + if(!$editable = $grid->getConfig()->getComponentByType('GridFieldEditableColumns')) { + throw new Exception('Inline adding requires the editable columns component'); + } + + if(!singleton($class)->canCreate()) { + return false; + } + + Requirements::javascript(THIRDPARTY_DIR . '/javascript-templates/tmpl.js'); + GridFieldExtensions::include_requirements(); + + $data = new ArrayData(array( + 'Title' => $this->getTitle(), + )); + + return array( + $fragment => $data->renderWith(__CLASS__), + 'after' => $this->getRowTemplate($grid, $editable) + ); + } + + private function getRowTemplate(GridField $grid, GridFieldEditableColumns $editable) { + $class = $grid->getModelClass(); + + $columns = new ArrayList(); + $handled = array_keys($editable->getDisplayFields($grid)); + + $record = new $class(); + $fields = $editable->getFields($grid, $record); + + foreach($grid->getColumns() as $column) { + if(in_array($column, $handled)) { + $field = $fields->dataFieldByName($column); + $field->setName(sprintf( + '%s[%s][{%%=o.num%%}][%s]', $grid->getName(), __CLASS__, $field->getName() + )); + + $content = $field->Field(); + } else { + $content = null; + } + + $attrs = ''; + + foreach($grid->getColumnAttributes($record, $column) as $attr => $val) { + $attrs .= sprintf(' %s="%s"', $attr, Convert::raw2att($val)); + } + + $columns->push(new ArrayData(array( + 'Content' => $content, + 'Attributes' => $attrs, + 'IsActions' => $column == 'Actions' + ))); + } + + return $columns->renderWith('GridFieldAddNewInlineRow'); + } + + public function handleSave(GridField $grid, DataObjectInterface $record) { + $value = $grid->Value(); + + if(!isset($value[__CLASS__]) || !is_array($value[__CLASS__])) { + return; + } + + $class = $grid->getModelClass(); + $editable = $grid->getConfig()->getComponentByType('GridFieldEditableColumns'); + $form = $editable->getForm($grid, $record); + + if(!singleton($class)->canCreate()) { + return; + } + + foreach($value[__CLASS__] as $fields) { + $item = new $class(); + + $form->loadDataFrom($fields, Form::MERGE_CLEAR_MISSING); + $form->saveInto($item); + + $grid->getList()->add($item); + } + } + +} diff --git a/code/GridFieldEditableColumns.php b/code/GridFieldEditableColumns.php index dd0cef71..76cbcf8b 100644 --- a/code/GridFieldEditableColumns.php +++ b/code/GridFieldEditableColumns.php @@ -110,7 +110,7 @@ public function getURLHandlers($grid) { * @param DataObjectInterface $record * @return FieldList */ - protected function getFields(GridField $grid, DataObjectInterface $record) { + public function getFields(GridField $grid, DataObjectInterface $record) { $cols = $this->getDisplayFields($grid); $fields = new FieldList(); $class = $grid->getList()->dataClass(); @@ -162,7 +162,7 @@ protected function getFields(GridField $grid, DataObjectInterface $record) { * @param DataObjectInterface $record * @return Form */ - protected function getForm(GridField $grid, DataObjectInterface $record) { + public function getForm(GridField $grid, DataObjectInterface $record) { $fields = $this->getFields($grid, $record); $form = new Form($this, null, $fields, new FieldList()); diff --git a/css/GridFieldExtensions.css b/css/GridFieldExtensions.css index 140158ef..16f8a923 100644 --- a/css/GridFieldExtensions.css +++ b/css/GridFieldExtensions.css @@ -86,6 +86,14 @@ max-width: none !important; } +.ss-gridfield-add-new-inline span.readonly { + color: #FFF !important; +} + +.ss-gridfield-add-new-inline .col-buttons { + text-align: right; +} + /** * GridFieldOrderableRows */ diff --git a/javascript/GridFieldExtensions.js b/javascript/GridFieldExtensions.js index 746f62d0..313ab6db 100644 --- a/javascript/GridFieldExtensions.js +++ b/javascript/GridFieldExtensions.js @@ -72,6 +72,39 @@ } }); + /** + * GridFieldAddNewInlineButton + */ + + $(".ss-gridfield-add-new-inline").entwine({ + onclick: function() { + var tmpl = window.tmpl; + var grid = this.getGridField(); + var row = grid.find(".ss-gridfield-add-inline-template"); + var num = grid.data("add-inline-num") || 1; + + tmpl.cache["ss-gridfield-add-inline-template"] = tmpl(row.html()); + + grid.find("tbody").append(tmpl("ss-gridfield-add-inline-template", { num: num })); + grid.find(".ss-gridfield-no-items").hide(); + grid.data("add-inline-num", num + 1); + + return false; + } + }); + + $(".ss-gridfield-delete-inline").entwine({ + onclick: function() { + var msg = ss.i18n._t("GridFieldExtensions.CONFIRMDEL", "Are you sure you want to delete this?"); + + if(confirm(msg)) { + this.parents("tr").remove(); + } + + return false; + } + }); + /** * GridFieldAddNewMultiClass */ diff --git a/templates/GridFieldAddNewInlineButton.ss b/templates/GridFieldAddNewInlineButton.ss new file mode 100644 index 00000000..d5d48878 --- /dev/null +++ b/templates/GridFieldAddNewInlineButton.ss @@ -0,0 +1,3 @@ + diff --git a/templates/GridFieldAddNewInlineRow.ss b/templates/GridFieldAddNewInlineRow.ss new file mode 100644 index 00000000..90a4dc01 --- /dev/null +++ b/templates/GridFieldAddNewInlineRow.ss @@ -0,0 +1,13 @@ +