<% if Message %>
$Message
<% else %>
diff --git a/control/Controller.php b/control/Controller.php
index ac1af911b..e53aaa7bd 100644
--- a/control/Controller.php
+++ b/control/Controller.php
@@ -298,6 +298,23 @@ class Controller extends RequestHandler {
public function hasAction($action) {
return parent::hasAction($action) || $this->hasActionTemplate($action);
}
+
+ /**
+ * Removes all the "action" part of the current URL and returns the result.
+ * If no action parameter is present, returns the full URL
+ * @static
+ * @return String
+ */
+ public function removeAction($fullURL, $action = null) {
+ if (!$action) $action = $this->getAction(); //default to current action
+ $returnURL = $fullURL;
+
+ if (($pos = strpos($fullURL, $action)) !== false) {
+ $returnURL = substr($fullURL,0,$pos);
+ }
+
+ return $returnURL;
+ }
/**
* Returns TRUE if this controller has a template that is specifically designed to handle a specific action.
diff --git a/css/GridField.css b/css/GridField.css
index 52b7d26ba..1f92e5941 100644
--- a/css/GridField.css
+++ b/css/GridField.css
@@ -9,20 +9,22 @@
.cms table.ss-gridfield-table tbody td button { border: none; background: none; margin: 0 0 0 2px; padding: 0; width: auto; text-shadow: none; }
.cms table.ss-gridfield-table tfoot { color: #1d2224; }
.cms table.ss-gridfield-table tfoot tr td { background: #95a5ab; padding: .7em; border-bottom: 1px solid rgba(0, 0, 0, 0.1); }
-.cms table.ss-gridfield-table tr.sortable-header th { background: #7f9198; }
+.cms table.ss-gridfield-table tr.title { -moz-border-radius-topleft: 7px; -webkit-border-top-left-radius: 7px; -o-border-top-left-radius: 7px; -ms-border-top-left-radius: 7px; -khtml-border-top-left-radius: 7px; border-top-left-radius: 7px; -moz-border-radius-topright: 7px; -webkit-border-top-right-radius: 7px; -o-border-top-right-radius: 7px; -ms-border-top-right-radius: 7px; -khtml-border-top-right-radius: 7px; border-top-right-radius: 7px; }
+.cms table.ss-gridfield-table tr.title th { position: relative; background: #7f9198; border-top: 1px solid rgba(0, 0, 0, 0.1); padding: 5px; min-height: 40px; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b1c0c5), color-stop(100%, #7f9198)); background-image: -webkit-linear-gradient(#b1c0c5, #7f9198); background-image: -moz-linear-gradient(#b1c0c5, #7f9198); background-image: -o-linear-gradient(#b1c0c5, #7f9198); background-image: -ms-linear-gradient(#b1c0c5, #7f9198); background-image: linear-gradient(#b1c0c5, #7f9198); -moz-border-radius-topleft: 7px; -webkit-border-top-left-radius: 7px; -o-border-top-left-radius: 7px; -ms-border-top-left-radius: 7px; -khtml-border-top-left-radius: 7px; border-top-left-radius: 7px; -moz-border-radius-topright: 7px; -webkit-border-top-right-radius: 7px; -o-border-top-right-radius: 7px; -ms-border-top-right-radius: 7px; -khtml-border-top-right-radius: 7px; border-top-right-radius: 7px; text-shadow: rgba(0, 0, 0, 0.3) 0px -1px 0; }
+.cms table.ss-gridfield-table tr.title th h2 { padding: 0px; font-size: 16px; color: #fff; margin: 0; display: inline; }
+.cms table.ss-gridfield-table tr.title th .new { font-size: 14px; border-color: rgba(0, 0, 0, 0.1); float: right; }
+.cms table.ss-gridfield-table tr.sortable-header { background: #bac8ce; }
.cms table.ss-gridfield-table tr:hover { background: #FFFAD6 !important; }
.cms table.ss-gridfield-table tr:first-child { background: transparent; }
.cms table.ss-gridfield-table tr.ss-gridfield-even { background: #f0f4f7; }
.cms table.ss-gridfield-table tr.ss-gridfield-even.ss-gridfield-last { border-bottom: none; }
.cms table.ss-gridfield-table tr.even { background: #f0f4f7; }
.cms table.ss-gridfield-table tr th { font-weight: bold; font-size: 12px; color: #FFF; padding: 5px; border-right: 1px solid rgba(0, 0, 0, 0.1); }
-.cms table.ss-gridfield-table tr th.main:first-child { -moz-border-radius-topleft: 7px; -webkit-border-top-left-radius: 7px; -o-border-top-left-radius: 7px; -ms-border-top-left-radius: 7px; -khtml-border-top-left-radius: 7px; border-top-left-radius: 7px; }
-.cms table.ss-gridfield-table tr th.main:last-child { -moz-border-radius-topright: 7px; -webkit-border-top-right-radius: 7px; -o-border-top-right-radius: 7px; -ms-border-top-right-radius: 7px; -khtml-border-top-right-radius: 7px; border-top-right-radius: 7px; }
.cms table.ss-gridfield-table tr th div.fieldgroup, .cms table.ss-gridfield-table tr th div.fieldgroup-field { width: auto; }
.cms table.ss-gridfield-table tr th div.fieldgroup { min-width: 200px; padding-right: 0; }
-.cms table.ss-gridfield-table tr th.extra, .cms table.ss-gridfield-table tr th.action { background: #7f9198; padding: 0; cursor: default; }
+.cms table.ss-gridfield-table tr th.extra, .cms table.ss-gridfield-table tr th.action { padding: 0; cursor: default; }
.cms table.ss-gridfield-table tr th.extra button.ss-ui-button, .cms table.ss-gridfield-table tr th.extra button:hover.ss-ui-button, .cms table.ss-gridfield-table tr th.action button.ss-ui-button, .cms table.ss-gridfield-table tr th.action button:hover.ss-ui-button { margin-left: .9em; color: #222; }
-.cms table.ss-gridfield-table tr th.main { border-top: 1px solid rgba(0, 0, 0, 0.1); color: #fff; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b1c0c5), color-stop(100%, #7f9198)); background-image: -webkit-linear-gradient(#b1c0c5, #7f9198); background-image: -moz-linear-gradient(#b1c0c5, #7f9198); background-image: -o-linear-gradient(#b1c0c5, #7f9198); background-image: -ms-linear-gradient(#b1c0c5, #7f9198); background-image: linear-gradient(#b1c0c5, #7f9198); }
+.cms table.ss-gridfield-table tr th.main { border-top: 1px solid rgba(0, 0, 0, 0.1); color: #fff; background: #9cb0b9; border-bottom: 1px solid rgba(0, 0, 0, 0.1); }
.cms table.ss-gridfield-table tr th.main span { text-shadow: rgba(0, 0, 0, 0.3) 0px -1px 0; }
.cms table.ss-gridfield-table tr th.extra { background: #bac8ce; padding: 5px; border-top: rgba(0, 0, 0, 0.3); }
.cms table.ss-gridfield-table tr th.extra span { width: auto; display: inline; position: static; }
diff --git a/filesystem/File.php b/filesystem/File.php
index f7a8b4ef7..53473b44a 100644
--- a/filesystem/File.php
+++ b/filesystem/File.php
@@ -119,6 +119,8 @@ class File extends DataObject {
'cab','arj','tar','zip','zipx','sit','sitx','gz','tgz','bz2','ace','arc','pkg','dmg','hqx','jar',
'xml','pdf',
);
+
+ protected static $labelSeparator = ':';
/**
* @var If this is true, then restrictions set in {@link $allowed_max_file_size} and
@@ -255,23 +257,58 @@ class File extends DataObject {
return $this->canEdit($member);
}
+ /*
+ * Generate and return the preview image / file upload / replace field for this File
+ * @return FormField
+ */
+ protected function getFilePreview() {
+ //file upload
+ $uploadField = new UploadField('UploadField','Upload Field');
+ $uploadField->setConfig('previewMaxWidth', 40);
+ $uploadField->setConfig('previewMaxHeight', 30);
+ //$uploadField->setTemplate('FileEditUploadField');
+ if ($this->ParentID) {
+ $parent = $this->Parent();
+ if ($parent) { //set the parent that the Upload field should use for uploads
+ $uploadField->setFolderName($parent->getFilename());
+ $uploadField->setRecord($parent);
+ //TODO: make the uploadField replace the existing file
+ }
+ }
+
+ return $uploadField;
+ }
+
+ /**
+ * Returns the fields to power the edit screen of files in the CMS
+ * @return FieldList
+ */
function getCMSFields() {
$urlLink = "
";
+ //create the file attributes in a FieldGroup
+ $filePreview = new FieldGroup(
+ $this->getFilePreview(),
+ new ReadonlyField("FileType", _t('AssetTableField.TYPE','File type').self::$labelSeparator),
+ new ReadonlyField("Filename", _t('AssetTableField.FILENAME','File name').self::$labelSeparator),
+ new ReadonlyField("Size", _t('AssetTableField.SIZE','File size').self::$labelSeparator, $this->getSize()),
+ new DateField_Disabled("Created", _t('AssetTableField.CREATED','First uploaded').self::$labelSeparator),
+ new DateField_Disabled("LastEdited", _t('AssetTableField.LASTEDIT','Last changed').self::$labelSeparator)
+ );
+ $filePreview->setTitle("File preview");
+ $filePreview->setName("FilePreview");
+
return new FieldList(
new TabSet('Root',
- new Tab('Main',
+ new Tab('Main',
+ $filePreview,
new TextField("Title", _t('AssetTableField.TITLE','Title')),
new TextField("Name", _t('AssetTableField.FILENAME','Filename')),
- new LiteralField("AbsoluteURL", $urlLink),
- new ReadonlyField("FileType", _t('AssetTableField.TYPE','Type')),
- new ReadonlyField("Size", _t('AssetTableField.SIZE','Size'), $this->getSize()),
- new DropdownField("OwnerID", _t('AssetTableField.OWNER','Owner'), Member::mapInCMSGroups()),
- new DateField_Disabled("Created", _t('AssetTableField.CREATED','First uploaded')),
- new DateField_Disabled("LastEdited", _t('AssetTableField.LASTEDIT','Last changed'))
+ new LiteralField("AbsoluteURL", $urlLink), //TODO: replace this is a proper preview
+ new DropdownField("OwnerID", _t('AssetTableField.OWNER','Owner'), Member::mapInCMSGroups())
)
)
);
diff --git a/forms/FieldGroup.php b/forms/FieldGroup.php
index a0c7181a4..ec4ec989a 100644
--- a/forms/FieldGroup.php
+++ b/forms/FieldGroup.php
@@ -97,14 +97,21 @@ class FieldGroup extends CompositeField {
$spaceZebra = isset($this->zebra) ? " fieldgroup-$this->zebra" : '';
$idAtt = isset($this->id) ? " id=\"{$this->id}\"" : '';
$content = "
";
-
+
+ $count = 1;
foreach($fs as $subfield) {
$childZebra = (!isset($childZebra) || $childZebra == "odd") ? "even" : "odd";
if($subfield->hasMethod('setZebra')) {
$subfield->setZebra($childZebra);
}
-
- $content .= "
" . $subfield->{$this->subfieldParam}() . "
";
+
+ //label the first and last fields of each surrounding div
+ if ($count == 1) $firstLast = "first";
+ elseif ($count == count($fs)) $firstLast = "last";
+ else $firstLast = '';
+
+ $content .= "
" . $subfield->{$this->subfieldParam}() . "
";
+ $count++;
}
$content .= "
";
diff --git a/forms/Form.php b/forms/Form.php
index 5f251537c..5e7c21183 100644
--- a/forms/Form.php
+++ b/forms/Form.php
@@ -379,10 +379,9 @@ class Form extends RequestHandler {
if($field = $this->checkFieldsForAction($field->FieldList(), $funcName)) {
return $field;
}
- } elseif (!$field->hasMethod($funcName)) {
- continue;
+ } elseif ($field->hasMethod($funcName)) {
+ return $field;
}
- return $field;
}
}
diff --git a/forms/gridfield/GridField.php b/forms/gridfield/GridField.php
index 22625f501..b2f574727 100755
--- a/forms/gridfield/GridField.php
+++ b/forms/gridfield/GridField.php
@@ -80,8 +80,6 @@ class GridField extends FormField {
*/
public function __construct($name, $title = null, SS_List $dataList = null, GridFieldConfig $config = null) {
parent::__construct($name, $title, null);
-
- FormField::__construct($name);
if($dataList) {
$this->setList($dataList);
@@ -386,6 +384,7 @@ class GridField extends FormField {
$item->augmentColumns($this, $columns);
}
}
+
return $columns;
}
@@ -404,8 +403,11 @@ class GridField extends FormField {
}
if(!empty($this->columnDispatch[$column])) {
- $handler = $this->columnDispatch[$column];
- return $handler->getColumnContent($this, $record, $column);
+ $content = "";
+ foreach($this->columnDispatch[$column] as $handler) {
+ $content .= $handler->getColumnContent($this, $record, $column);
+ }
+ return $content;
} else {
throw new InvalidArgumentException("Bad column '$column'");
}
@@ -427,15 +429,18 @@ class GridField extends FormField {
}
if(!empty($this->columnDispatch[$column])) {
- $handler = $this->columnDispatch[$column];
- $attrs = $handler->getColumnAttributes($this, $record, $column);
- if(is_array($attrs)) {
- return $attrs;
- } elseif($attrs) {
- throw new LogicException("Non-array response from " . get_class($handler) . "::getColumnAttributes()");
- } else {
- return array();
+ $attrs = array();
+
+ foreach($this->columnDispatch[$column] as $handler) {
+ $column_attrs = $handler->getColumnAttributes($this, $record, $column);
+
+ if(is_array($column_attrs))
+ $attrs = array_merge($attrs, $column_attrs);
+ elseif($column_attrs)
+ throw new LogicException("Non-array response from " . get_class($handler) . "::getColumnAttributes()");
}
+
+ return $attrs;
} else {
throw new InvalidArgumentException("Bad column '$column'");
}
@@ -456,13 +461,19 @@ class GridField extends FormField {
}
if(!empty($this->columnDispatch[$column])) {
- $handler = $this->columnDispatch[$column];
- $metadata = $handler->getColumnMetadata($this, $column);
- if(is_array($metadata)) {
- return $metadata;
- } elseif($metadata) {
- throw new LogicException("Non-array response from " . get_class($handler) . "::getColumnMetadata()");
+ $metadata = array();
+
+ foreach($this->columnDispatch[$column] as $handler) {
+ $column_metadata = $handler->getColumnMetadata($this, $column);
+
+ if(is_array($column_metadata))
+ $metadata = array_merge($metadata, $column_metadata);
+ else
+ throw new LogicException("Non-array response from " . get_class($handler) . "::getColumnMetadata()");
+
}
+
+ return $metadata;
}
throw new InvalidArgumentException("Bad column '$column'");
}
@@ -489,10 +500,10 @@ class GridField extends FormField {
if($item instanceof GridField_ColumnProvider) {
$columns = $item->getColumnsHandled($this);
foreach($columns as $column) {
- $this->columnDispatch[$column] = $item;
+ $this->columnDispatch[$column][] = $item;
}
}
- }
+ }
}
/**
@@ -729,23 +740,18 @@ class GridField_Action extends FormAction {
$actionData['StateID'] = $id;
// And generate field
- $attributes = array(
- 'class' => ($this->extraClass() ? $this->extraClass() : '') . ' action-' . $this->actionName,
- 'id' => $this->id(),
- 'type' => 'submit',
+ $data = new ArrayData(array(
+ 'Class' => ($this->extraClass() ? $this->extraClass() : '') . ($this->isReadonly() ? ' disabled' : ''),
+ 'ID' => $this->id(),
// Note: This field needs to be less than 65 chars, otherwise Suhosin security patch
// will strip it from the requests
- 'name' => 'action_gridFieldAlterAction'. '?' . http_build_query($actionData),
- 'tabindex' => $this->getTabIndex(),
- 'data-url' => $this->gridField->Link(),
- );
+ 'Name' => 'action_gridFieldAlterAction'. '?' . http_build_query($actionData),
+ 'Disabled' => $this->isReadonly(),
+ 'Label' => $this->buttonLabel,
+ 'DataURL' => $this->gridField->Link(),
+ ));
- if($this->isReadonly()) {
- $attributes['disabled'] = 'disabled';
- $attributes['class'] = $attributes['class'] . ' disabled';
- }
-
- return $this->createTag('button', $attributes, $this->buttonLabel);
+ return $data->renderWith('GridField_Action');
}
/**
diff --git a/forms/gridfield/GridFieldAction.php b/forms/gridfield/GridFieldAction.php
index 3ae3f040f..6cfe77039 100644
--- a/forms/gridfield/GridFieldAction.php
+++ b/forms/gridfield/GridFieldAction.php
@@ -1,7 +1,10 @@
'');
}
}
@@ -47,7 +51,7 @@ class GridFieldAction_Edit implements GridField_ColumnProvider {
* @return type
*/
public function getColumnsHandled($gridField) {
- return array('EditAction');
+ return array('Actions');
}
/**
@@ -57,7 +61,7 @@ class GridFieldAction_Edit implements GridField_ColumnProvider {
* @return array
*/
public function getActions($gridField) {
- return array('deleterecord');
+ return array();
}
/**
@@ -68,7 +72,11 @@ class GridFieldAction_Edit implements GridField_ColumnProvider {
* @return string - the HTML for the column
*/
public function getColumnContent($gridField, $record, $columnName) {
- return sprintf('
%s', Controller::join_links($gridField->Link('item'), $record->ID, 'edit'), _t('GridAction.Edit', 'edit'));
+ $data = new ArrayData(array(
+ 'Link' => Controller::join_links($gridField->Link('item'), $record->ID, 'edit')
+ ));
+
+ return $data->renderWith('GridFieldAction_Edit');
}
/**
@@ -98,7 +106,8 @@ class GridFieldAction_Delete implements GridField_ColumnProvider, GridField_Acti
* @param array $columns
*/
public function augmentColumns($gridField, &$columns) {
- $columns[] = 'DeleteAction';
+ if(!in_array('Actions', $columns))
+ $columns[] = 'Actions';
}
/**
@@ -121,7 +130,7 @@ class GridFieldAction_Delete implements GridField_ColumnProvider, GridField_Acti
* @return array
*/
public function getColumnMetadata($gridField, $columnName) {
- if($columnName == 'DeleteAction') {
+ if($columnName == 'Actions') {
return array('title' => '');
}
}
@@ -133,7 +142,7 @@ class GridFieldAction_Delete implements GridField_ColumnProvider, GridField_Acti
* @return type
*/
public function getColumnsHandled($gridField) {
- return array('DeleteAction');
+ return array('Actions');
}
/**
@@ -175,12 +184,11 @@ class GridFieldAction_Delete implements GridField_ColumnProvider, GridField_Acti
* @return void
*/
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
- $id = $arguments['RecordID'];
- $item = $gridField->getList()->byID($id);
- if(!$item) return;
-
if($actionName == 'deleterecord') {
- $item->delete();
+ $id = $arguments['RecordID'];
+ $item = $gridField->getList()->byID($id);
+ if(!$item) return;
+ $item->delete();
}
}
}
\ No newline at end of file
diff --git a/forms/gridfield/GridFieldConfig.php b/forms/gridfield/GridFieldConfig.php
index b45cde614..eae9ae5f2 100755
--- a/forms/gridfield/GridFieldConfig.php
+++ b/forms/gridfield/GridFieldConfig.php
@@ -87,15 +87,16 @@ class GridFieldConfig_Base extends GridFieldConfig {
* @param int $itemsPerPage - How many items per page should show up per page
* @return GridFieldConfig_Base
*/
- public static function create($itemsPerPage=25){
- return new GridFieldConfig_Base($itemsPerPage=25);
+ public static function create($itemsPerPage=15){
+ return new GridFieldConfig_Base($itemsPerPage=15);
}
/**
*
* @param int $itemsPerPage - How many items per page should show up
*/
- public function __construct($itemsPerPage=25) {
+ public function __construct($itemsPerPage=15) {
+ $this->addComponent(new GridFieldTitle());
$this->addComponent(new GridFieldSortableHeader());
$this->addComponent(new GridFieldFilter());
$this->addComponent(new GridFieldDefaultColumns());
@@ -142,5 +143,6 @@ class GridFieldConfig_ManyManyEditor extends GridFieldConfig {
$this->addComponent(new GridFieldAction_Edit());
$this->addComponent(new GridFieldRelationDelete());
$this->addComponent(new GridFieldPaginator($itemsPerPage));
+ $this->addComponent(new GridFieldPopupForms());
}
}
diff --git a/forms/gridfield/GridFieldPaginator.php b/forms/gridfield/GridFieldPaginator.php
index 7b468413d..ff7b944d4 100755
--- a/forms/gridfield/GridFieldPaginator.php
+++ b/forms/gridfield/GridFieldPaginator.php
@@ -18,7 +18,7 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
*
* @var int
*/
- protected $itemsPerPage = 25;
+ protected $itemsPerPage = 15;
/**
* Which template to use for rendering
@@ -31,7 +31,7 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
*
* @param int $itemsPerPage - How many items should be displayed per page
*/
- public function __construct($itemsPerPage=25) {
+ public function __construct($itemsPerPage=15) {
$this->itemsPerPage = $itemsPerPage;
}
diff --git a/forms/gridfield/GridFieldPopupForms.php b/forms/gridfield/GridFieldPopupForms.php
index 70399584b..168cc97f2 100755
--- a/forms/gridfield/GridFieldPopupForms.php
+++ b/forms/gridfield/GridFieldPopupForms.php
@@ -1,7 +1,10 @@
/field/
/item/
@@ -9,22 +12,18 @@
*/
class GridFieldPopupForms implements GridField_URLHandler {
+
+
/**
* @var String
*/
- protected $template = 'GridFieldItemEditView';
+ protected $template = 'GridFieldPopupForms';
- /**
- *
- * @var Controller
- */
- protected $popupController;
-
/**
*
* @var string
*/
- protected $popupFormName;
+ protected $name;
function getURLHandlers($gridField) {
return array(
@@ -41,12 +40,10 @@ class GridFieldPopupForms implements GridField_URLHandler {
* The arguments are experimental API's to support partial content to be passed back to whatever
* controller who wants to display the getCMSFields
*
- * @param Controller $popupController The controller object that will be used to render the pop-up forms
- * @param string $popupFormName The name of the edit form to place into the pop-up form
+ * @param string $name The name of the edit form to place into the pop-up form
*/
- public function __construct($popupController, $popupFormName) {
- $this->popupController = $popupController;
- $this->popupFormName = $popupFormName;
+ public function __construct($name = 'DetailForm') {
+ $this->name = $name;
}
/**
@@ -56,10 +53,22 @@ class GridFieldPopupForms implements GridField_URLHandler {
* @return GridFieldPopupForm_ItemRequest
*/
public function handleItem($gridField, $request) {
- $record = $gridField->getList()->byId($request->param("ID"));
- $handler = new GridFieldPopupForm_ItemRequest($gridField, $this, $record, $this->popupController, $this->popupFormName);
+ $controller = $gridField->getForm()->Controller();
+
+ if(is_numeric($request->param('ID'))) {
+ $record = $gridField->getList()->byId($request->param("ID"));
+ } else {
+ $record = Object::create($gridField->getModelClass());
+ }
+
+ if(!$class = ClassInfo::exists(get_class($this) . "_ItemRequest")) {
+ $class = 'GridFieldPopupForm_ItemRequest';
+ }
+
+ $handler = Object::create($class, $gridField, $this, $record, $controller, $this->name);
$handler->setTemplate($this->template);
- return $handler;
+
+ return $handler->handleRequest($request, $gridField);
}
/**
@@ -75,6 +84,20 @@ class GridFieldPopupForms implements GridField_URLHandler {
function getTemplate() {
return $this->template;
}
+
+ /**
+ * @param String
+ */
+ function setName($name) {
+ $this->name = $name;
+ }
+
+ /**
+ * @return String
+ */
+ function getName() {
+ return $this->name;
+ }
}
class GridFieldPopupForm_ItemRequest extends RequestHandler {
@@ -137,15 +160,29 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
}
public function Link($action = null) {
- return Controller::join_links($this->gridField->Link('item'), $this->record->ID, $action);
+ return Controller::join_links($this->gridField->Link('item'), $this->record->ID ? $this->record->ID : 'new', $action);
}
function edit($request) {
$controller = $this->popupController;
-
+ $form = $this->ItemEditForm($this->gridField, $request);
+
+ // TODO Coupling with CMS
+ if($controller instanceof LeftAndMain) {
+ $form->addExtraClass('cms-edit-form');
+ $form->setTemplate($controller->getTemplatesWithSuffix('_EditForm'));
+ $form->addExtraClass('cms-content center ss-tabset ' . $controller->BaseCSSClasses());
+ if($form->Fields()->hasTabset()) $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');
+ // TODO Link back to controller action (and edited root record) rather than index,
+ // which requires more URL knowledge than the current link to this field gives us.
+ // The current root record is held in session only,
+ // e.g. page/edit/show/6/ vs. page/edit/EditForm/field/MyGridField/....
+ $form->Backlink = $controller->Link();
+ }
+
$return = $this->customise(array(
- 'Backlink' => $this->gridField->getForm()->Controller()->Link(),
- 'ItemEditForm' => $this->ItemEditForm($this->gridField, $request),
+ 'Backlink' => $controller->Link(),
+ 'ItemEditForm' => $form,
))->renderWith($this->template);
if($controller->isAjax()) {
@@ -154,7 +191,8 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
// If not requested by ajax, we need to render it within the controller context+template
return $controller->customise(array(
- $this->popupFormName => $return,
+ // TODO Allow customization
+ 'Content' => $return,
));
}
}
@@ -163,35 +201,40 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
* Builds an item edit form. The arguments to getCMSFields() are the popupController and
* popupFormName, however this is an experimental API and may change.
*
- * In the future, we will probably need to come up with a tigher object representing a partially
+ * @todo In the future, we will probably need to come up with a tigher object representing a partially
* complete controller with gaps for extra functionality. This, for example, would be a better way
* of letting Security/login put its log-in form inside a UI specified elsewhere.
*
* @return Form
*/
function ItemEditForm() {
- $request = $this->popupController->getRequest();
$form = new Form(
$this,
'ItemEditForm',
// WARNING: The arguments passed here are a little arbitrary. This API will need cleanup
$this->record->getCMSFields($this->popupController, $this->popupFormName),
new FieldList(
- $saveAction = new FormAction('doSave', _t('GridFieldDetailsForm.Save', 'Save'))
+ $saveAction = new FormAction('doSave', _t('GridFieldDetailsForm.Save', 'Save')),
+ $deleteAction = new FormAction('doDelete', _t('GridFieldDetailsForm.Delete', 'Delete'))
)
);
- $saveAction->addExtraClass('ss-ui-action-constructive icon-accept');
+ $saveAction->addExtraClass('ss-ui-action-constructive');
+ $deleteAction->addExtraClass('ss-ui-action-destructive');
$form->loadDataFrom($this->record);
return $form;
}
function doSave($data, $form) {
+ $new_record = $this->record->ID == 0;
+
try {
$form->saveInto($this->record);
$this->record->write();
+ if($new_record)
+ $this->gridField->getList()->add($this->record);
} catch(ValidationException $e) {
$form->sessionMessage($e->getResult()->message(), 'bad');
- return Director::redirectBack();
+ return Controller::curr()->redirectBack();
}
// TODO Save this item into the given relationship
@@ -207,6 +250,34 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
return $this->popupController->redirectBack();
}
+ function doDelete($data, $form) {
+ try {
+ $toDelete = $this->record;
+ if (!$toDelete->canDelete()) {
+ throw new ValidationException(_t('GridFieldDetailsForm.DeletePermissionsFailure',"No delete permissions"),0);
+ }
+
+ $toDelete->delete();
+ } catch(ValidationException $e) {
+ $form->sessionMessage($e->getResult()->message(), 'bad');
+ return Director::redirectBack();
+ }
+
+ $message = sprintf(
+ _t('ComplexTableField.SUCCESSEDIT2', 'Deleted %s %s'),
+ $this->record->singular_name(),
+ '"' . htmlspecialchars($this->record->Title, ENT_QUOTES) . '"'
+ );
+
+ $form->sessionMessage($message, 'good');
+
+ //when an item is deleted, redirect to the revelant admin section without the action parameter
+ $controller = Controller::curr();
+ $noActionURL = $controller->removeAction($data['url']);
+
+ return Director::redirect($noActionURL, 302); //redirect back to admin section
+ }
+
/**
* @param String
*/
diff --git a/forms/gridfield/GridFieldTitle.php b/forms/gridfield/GridFieldTitle.php
new file mode 100644
index 000000000..afb4480d6
--- /dev/null
+++ b/forms/gridfield/GridFieldTitle.php
@@ -0,0 +1,13 @@
+ $gridField->customise(array(
+ 'NewLink' => Controller::join_links($gridField->Link('item'), 'new')
+ ))->renderWith('GridFieldTitle')
+ );
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/javascript/GridField.js b/javascript/GridField.js
index 8f046b7bb..f3d6a2ec7 100644
--- a/javascript/GridField.js
+++ b/javascript/GridField.js
@@ -112,7 +112,21 @@
).css({'position':'relative','margin':'0 auto','width':'65%'}).appendTo(eleInput.closest('th'));
}
}
- });
+ });
+
+ $('fieldset.ss-gridfield .new-link').entwine({
+ onclick: function(e) {
+ $(this).trigger('opennewview', $(this).prop('href'));
+ return false;
+ }
+ });
+
+ $('fieldset.ss-gridfield .edit-link').entwine({
+ onclick: function(e) {
+ $(this).trigger('openeditview', $(this).prop('href'));
+ return false;
+ }
+ });
/**
* Allows selection of one or more rows in the grid field.
@@ -146,4 +160,4 @@
});
-}(jQuery));
\ No newline at end of file
+}(jQuery));
diff --git a/model/HasManyList.php b/model/HasManyList.php
index 6e53690f5..5be23c927 100644
--- a/model/HasManyList.php
+++ b/model/HasManyList.php
@@ -63,7 +63,7 @@ class HasManyList extends RelationList {
* @param $itemID The ID of the item to be removed
*/
function removeByID($itemID) {
- $item = $this->byID($item);
+ $item = $this->byID($itemID);
return $this->remove($item);
}
diff --git a/model/Image.php b/model/Image.php
index 7986da6c5..0761a0386 100644
--- a/model/Image.php
+++ b/model/Image.php
@@ -72,6 +72,21 @@ class Image extends File {
parent::defineMethods();
}
+
+ /*
+ * Generate and return the preview image / file upload / replace field for this File
+ * @return FormField
+ */
+ protected function getFilePreview() {
+ $formattedImage = $this->getFormattedImage('AssetLibraryPreview');
+ $thumbnail = $formattedImage ? $formattedImage->URL : '';
+
+ $previewField = new LiteralField("ImageFull",
+ "\n"
+ );
+
+ return $previewField;
+ }
function getCMSFields() {
$fields = parent::getCMSFields();
@@ -81,19 +96,9 @@ class Image extends File {
$urlLink .= "{$this->RelativeLink()}";
$urlLink .= "";
- $big = $this->URL;
- $formattedImage = $this->getFormattedImage('AssetLibraryPreview');
- $thumbnail = $formattedImage ? $formattedImage->URL : '';
-
- // Hmm this required the translated string to be appended to BottomRoot to add this to the Main tab
- $fields->addFieldToTab('Root.Main',
- new ReadonlyField("Dimensions", _t('AssetTableField.DIM','Dimensions'))
- );
- $fields->addFieldToTab('Root.Main',
- new LiteralField("ImageFull",
- "
"
- )
- );
+ //attach the addition file information for an image to the existing FieldGroup create in the parent class
+ $fileAttributes = $fields->FieldByName('Root.Main.FilePreview');
+ $fileAttributes->push(new ReadonlyField("Dimensions", _t('AssetTableField.DIM','Dimensions').self::$labelSeparator));
return $fields;
}
diff --git a/scss/GridField.scss b/scss/GridField.scss
index 3bb86bb12..bb006289f 100644
--- a/scss/GridField.scss
+++ b/scss/GridField.scss
@@ -86,11 +86,34 @@ $gf_border_radius: 7px;
}
}
- tr {
- &.sortable-header {
+ tr {
+ &.title {
+ @include border-top-radius($gf_border_radius);
th {
+ position: relative;
background: $gf_colour_gradient_dark;
+ border-top: 1px solid $gf_colour_border;
+ padding: 5px;
+ min-height: 40px;
+ @include background-image(linear-gradient($gf_colour_gradient_light, $gf_colour_gradient_dark));
+ @include border-top-radius($gf_border_radius);
+ @include single-text-shadow($gf_colour_text_shadow, 0px, -1px, 0);
+ h2{
+ padding: 0px;
+ font-size: 16px;
+ color:#fff;
+ margin:0;
+ display:inline;
+ }
+ .new{
+ font-size: 14px;
+ border-color: $gf_colour_border;
+ float: right;
+ }
}
+ }
+ &.sortable-header {
+ background: $gf_colour_subheader;
}
&:hover {
background: #FFFAD6 !important;
@@ -116,10 +139,10 @@ $gf_border_radius: 7px;
padding: 5px;
border-right: 1px solid $gf_colour_border;
&.main:first-child{
- @include border-top-left-radius($gf_border_radius);
+ //@include border-top-left-radius($gf_border_radius);
}
&.main:last-child{
- @include border-top-right-radius($gf_border_radius);
+ //@include border-top-right-radius($gf_border_radius);
}
div {
&.fieldgroup,&.fieldgroup-field {
@@ -131,7 +154,6 @@ $gf_border_radius: 7px;
}
}
&.extra,&.action {
- background: $gf_colour_gradient_dark;
padding: 0;
cursor: default;
button,button:hover {
@@ -144,7 +166,8 @@ $gf_border_radius: 7px;
&.main{
border-top: 1px solid $gf_colour_border;
color:#fff;
- @include background-image(linear-gradient($gf_colour_gradient_light, $gf_colour_gradient_dark));
+ background: darken($gf_colour_subheader,10%);
+ border-bottom: 1px solid $gf_colour_border;
span{
@include single-text-shadow($gf_colour_text_shadow, 0px, -1px, 0);
}
diff --git a/security/Group.php b/security/Group.php
index e3bc0d34f..90ce0cd9d 100755
--- a/security/Group.php
+++ b/security/Group.php
@@ -63,7 +63,6 @@ class Group extends DataObject {
Requirements::javascript(SAPPHIRE_DIR . '/javascript/PermissionCheckboxSetField.js');
$config = new GridFieldConfig_ManyManyEditor('FirstName', true, 20);
- $config->addComponent(new GridFieldPopupForms(Controller::curr(), 'EditForm'));
$config->addComponent(new GridFieldExporter());
$memberList = new GridField('Members','Members', $this->Members(), $config);
diff --git a/templates/Includes/GridFieldAction_Edit.ss b/templates/Includes/GridFieldAction_Edit.ss
new file mode 100644
index 000000000..0c9d6b18a
--- /dev/null
+++ b/templates/Includes/GridFieldAction_Edit.ss
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/templates/Includes/GridFieldTitle.ss b/templates/Includes/GridFieldTitle.ss
new file mode 100644
index 000000000..199d41d0a
--- /dev/null
+++ b/templates/Includes/GridFieldTitle.ss
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/templates/Includes/GridField_Action.ss b/templates/Includes/GridField_Action.ss
new file mode 100644
index 000000000..0d8b4787d
--- /dev/null
+++ b/templates/Includes/GridField_Action.ss
@@ -0,0 +1 @@
+