diff --git a/code/GridFieldAddNewInlineButton.php b/code/GridFieldAddNewInlineButton.php index fd3578c..d30af17 100755 --- a/code/GridFieldAddNewInlineButton.php +++ b/code/GridFieldAddNewInlineButton.php @@ -101,7 +101,14 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S $content = $field->Field(); } else { - $content = null; + $content = $grid->getColumnContent($record, $column); + + // Convert GridFieldEditableColumns to the template format + $content = str_replace( + '[GridFieldEditableColumns][0]', + '[GridFieldAddNewInlineButton][{%=o.num%}]', + $content + ); } $attrs = ''; @@ -129,7 +136,10 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S } $class = $grid->getModelClass(); + /** @var GridFieldEditableColumns $editable */ $editable = $grid->getConfig()->getComponentByType('GridFieldEditableColumns'); + /** @var GridFieldOrderableRows $sortable */ + $sortable = $grid->getConfig()->getComponentByType('GridFieldOrderableRows'); $form = $editable->getForm($grid, $record); if(!singleton($class)->canCreate()) { @@ -143,6 +153,12 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S $form->loadDataFrom($fields, Form::MERGE_CLEAR_MISSING); $form->saveInto($item); + // Check if we are also sorting these records + if ($sortable) { + $sortField = $sortable->getSortField(); + $item->setField($sortField, $fields[$sortField]); + } + if($list instanceof ManyManyList) { $extra = array_intersect_key($form->getData(), (array) $list->getExtraFields()); } diff --git a/code/GridFieldEditableColumns.php b/code/GridFieldEditableColumns.php index 2e2b12c..b69d4e6 100644 --- a/code/GridFieldEditableColumns.php +++ b/code/GridFieldEditableColumns.php @@ -45,7 +45,7 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements // (ie. Maybe its readonly due to certain circumstances, or removed and not editable) $cmsFields = $record->getCMSFields(); $cmsField = $cmsFields->dataFieldByName($colRelation[0]); - if (!$cmsField || $cmsField->isReadonly() || $cmsField->isDisabled()) + if (!$cmsField || $cmsField->isReadonly() || $cmsField->isDisabled()) { return parent::getColumnContent($grid, $record, $col); } @@ -70,9 +70,9 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements $field->setName($this->getFieldName($field->getName(), $grid, $record)); $field->setValue($value); - + if ($field instanceof HtmlEditorField) { - return $field->FieldHolder(); + return $field->FieldHolder(); } return $field->forTemplate(); @@ -91,6 +91,9 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements return; } + /** @var GridFieldOrderableRows $sortable */ + $sortable = $grid->getConfig()->getComponentByType('GridFieldOrderableRows'); + $form = $this->getForm($grid, $record); foreach($value[__CLASS__] as $id => $fields) { @@ -109,6 +112,12 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements $form->loadDataFrom($fields, Form::MERGE_CLEAR_MISSING); $form->saveInto($item); + // Check if we are also sorting these records + if ($sortable) { + $sortField = $sortable->getSortField(); + $item->setField($sortField, $fields[$sortField]); + } + if($list instanceof ManyManyList) { $extra = array_intersect_key($form->getData(), (array) $list->getExtraFields()); } @@ -199,7 +208,7 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements // // Allows use of 'MyBool.Nice' and 'MyHTML.NoHTML' so that // GridFields not using inline editing still look good or - // revert to looking good in cases where the field isn't + // revert to looking good in cases where the field isn't // available or is readonly // $colRelation = explode('.', $col); diff --git a/code/GridFieldOrderableRows.php b/code/GridFieldOrderableRows.php index 1fd5048..76db38b 100755 --- a/code/GridFieldOrderableRows.php +++ b/code/GridFieldOrderableRows.php @@ -33,9 +33,9 @@ class GridFieldOrderableRows extends RequestHandler implements protected $sortField; /** - * If set to true, when an item is re-ordered, it will update on the + * If set to true, when an item is re-ordered, it will update on the * database and refresh the gridfield. When set to false, it will only - * update the sort order when the record is saved. + * update the sort order when the record is saved. * * @var boolean */ @@ -196,7 +196,22 @@ class GridFieldOrderableRows extends RequestHandler implements } public function getColumnContent($grid, $record, $col) { - return ViewableData::create()->renderWith('GridFieldOrderableRowsDragHandle'); + // In case you are using GridFieldEditableColumns, this ensures that + // the correct sort order is saved. If you are not using that component, + // this will be ignored by other components, but will still work for this. + $sortFieldName = sprintf( + '%s[GridFieldEditableColumns][%s][%s]', + $grid->getName(), + $record->ID, + $this->getSortField() + ); + $sortField = new HiddenField($sortFieldName, false, $record->getField($this->getSortField())); + $sortField->addExtraClass('ss-orderable-hidden-sort'); + $sortField->setForm($grid->getForm()); + + return ViewableData::create()->customise(array( + 'SortField' => $sortField + ))->renderWith('GridFieldOrderableRowsDragHandle'); } public function getColumnAttributes($grid, $record, $col) { @@ -262,14 +277,16 @@ class GridFieldOrderableRows extends RequestHandler implements $this->httpError(403); } - // Save any un-comitted changes to the gridfield + // Save any un-committed changes to the gridfield if(($form = $grid->getForm()) && ($record = $form->getRecord()) ) { $form->loadDataFrom($request->requestVars(), true); $grid->saveInto($record); } - $ids = $request->postVar('order'); - if (!$this->executeReorder($grid, $ids)) + // Get records from the `GridFieldEditableColumns` column + $data = $request->postVar($grid->getName()); + $sortedIDs = $this->getSortedIDs($data); + if (!$this->executeReorder($grid, $sortedIDs)) { $this->httpError(400); } @@ -277,6 +294,26 @@ class GridFieldOrderableRows extends RequestHandler implements return $grid->FieldHolder(); } + /** + * Get mapping of sort value to ID from posted data + * + * @param array $data Raw posted data + * @return array + */ + protected function getSortedIDs($data) { + if (empty($data['GridFieldEditableColumns'])) { + return array(); + } + + $sortedIDs = array(); + foreach($data['GridFieldEditableColumns'] as $id => $recordData) { + $sortValue = $recordData[$this->sortField]; + $sortedIDs[$sortValue] = $id; + } + ksort($sortedIDs); + return $sortedIDs; + } + /** * Handles requests to move an item to the previous or next page. */ @@ -343,23 +380,21 @@ class GridFieldOrderableRows extends RequestHandler implements public function handleSave(GridField $grid, DataObjectInterface $record) { if (!$this->immediateUpdate) { - $list = $grid->getList(); $value = $grid->Value(); - if (isset($value['GridFieldEditableColumns']) && $value['GridFieldEditableColumns']) - { - $rows = $value['GridFieldEditableColumns']; - $ids = array(); - foreach ($rows as $id => $data) - { - $ids[] = $id; - } - $this->executeReorder($grid, $ids); + $sortedIDs = $this->getSortedIDs($value); + if ($sortedIDs) { + $this->executeReorder($grid, $sortedIDs); } } } - protected function executeReorder(GridField $grid, $ids) { - if(!is_array($ids)) { + /** + * @param GridField $grid + * @param array $sortedIDs List of IDS, where the key is the sort field value to save + * @return bool + */ + protected function executeReorder(GridField $grid, $sortedIDs) { + if(!is_array($sortedIDs)) { return false; } $field = $this->getSortField(); @@ -376,10 +411,10 @@ class GridFieldOrderableRows extends RequestHandler implements } $list = $grid->getList(); $sortterm .= '"'.$this->getSortTable($list).'"."'.$field.'"'; - $items = $list->filter('ID', $ids)->sort($sortterm); + $items = $list->filter('ID', $sortedIDs)->sort($sortterm); // Ensure that each provided ID corresponded to an actual object. - if(count($items) != count($ids)) { + if(count($items) != count($sortedIDs)) { return false; } @@ -408,11 +443,11 @@ class GridFieldOrderableRows extends RequestHandler implements } // Perform the actual re-ordering. - $this->reorderItems($list, $current, $ids); + $this->reorderItems($list, $current, $sortedIDs); return true; } - protected function reorderItems($list, array $values, array $order) { + protected function reorderItems($list, array $values, array $sortedIDs) { $sortField = $this->getSortField(); /** @var SS_List $map */ $map = $list->map('ID', $sortField); @@ -433,13 +468,13 @@ class GridFieldOrderableRows extends RequestHandler implements if (!$isVersioned) { $sortTable = $this->getSortTable($list); $additionalSQL = (!$list instanceof ManyManyList) ? ', "LastEdited" = NOW()' : ''; - foreach(array_values($order) as $pos => $id) { - if($map[$id] != $pos) { + foreach($sortedIDs as $sortValue => $id) { + if($map[$id] != $sortValue) { DB::query(sprintf( 'UPDATE "%s" SET "%s" = %d%s WHERE %s', $sortTable, $sortField, - $pos, + $sortValue, $additionalSQL, $this->getSortTableClauseForIds($list, $id) )); @@ -450,10 +485,10 @@ class GridFieldOrderableRows extends RequestHandler implements // *_versions table is updated. This ensures re-ordering works // similar to the SiteTree where you change the position, and then // you go into the record and publish it. - foreach(array_values($order) as $pos => $id) { - if($map[$id] != $pos) { + foreach($sortedIDs as $sortValue => $id) { + if($map[$id] != $sortValue) { $record = $class::get()->byID($id); - $record->$sortField = $pos; + $record->$sortField = $sortValue; $record->write(); } } diff --git a/javascript/GridFieldExtensions.js b/javascript/GridFieldExtensions.js index 96be60e..819bb34 100644 --- a/javascript/GridFieldExtensions.js +++ b/javascript/GridFieldExtensions.js @@ -1,327 +1,391 @@ -(function($) { - $.entwine("ss", function($) { - /** - * GridFieldAddExistingSearchButton - */ - - $(".add-existing-search-dialog").entwine({ - loadDialog: function(deferred) { - var dialog = this.addClass("loading").children(".ui-dialog-content").empty(); - - deferred.done(function(data) { - dialog.html(data).parent().removeClass("loading"); - }); - } - }); - - $(".ss-gridfield .add-existing-search").entwine({ - onclick: function() { - var dialog = $("
").appendTo("body").dialog({ - modal: true, - resizable: false, - width: 500, - height: 600, - close: function() { - $(this).dialog("destroy").remove(); - } - }); - - dialog.parent().addClass("add-existing-search-dialog").loadDialog( - $.get(this.prop("href")) - ); - dialog.data("grid", this.closest(".ss-gridfield")); - - return false; - } - }); - - $(".add-existing-search-dialog .add-existing-search-form").entwine({ - onsubmit: function() { - this.closest(".add-existing-search-dialog").loadDialog($.get( - this.prop("action"), this.serialize() - )); - return false; - } - }); - - $(".add-existing-search-dialog .add-existing-search-items a").entwine({ - onclick: function() { - var link = this.closest(".add-existing-search-items").data("add-link"); - var id = this.data("id"); - - var dialog = this.closest(".add-existing-search-dialog") - .addClass("loading") - .children(".ui-dialog-content") - .empty() - - $.post(link, { id: id }, function() { - dialog.data("grid").reload(); - dialog.dialog("close"); - }); - - return false; - } - }); - - $(".add-existing-search-dialog .add-existing-search-pagination a").entwine({ - onclick: function() { - this.closest(".add-existing-search-dialog").loadDialog($.get( - this.prop("href") - )); - return false; - } - }); - - /** - * GridFieldAddNewInlineButton - */ - - $(".ss-gridfield.ss-gridfield-editable").entwine({ - reload: function(opts, success) { - var grid = this; - var added = grid.find("tbody:first").find(".ss-gridfield-inline-new").detach(); - - this._super(opts, function() { - if(added.length) { - added.appendTo(grid.find("tbody:first")); - grid.find("tbody:first").children(".ss-gridfield-no-items").hide(); - } - - if(success) success.apply(grid, arguments); - }); - }, - onpaste: function(e) { - // The following was used as a basis for clipboard data access: - // http://stackoverflow.com/questions/2176861/javascript-get-clipboard-data-on-paste-event-cross-browser - var clipboardData = typeof e.originalEvent.clipboardData !== "undefined" ? e.originalEvent.clipboardData : null; - if (clipboardData) { - // Get current input wrapper div class (ie. 'col-Title') - var input = $(e.target); - var inputType = input.attr('type'); - if (inputType === 'text' || inputType === 'email') - { - var lastInput = this.find(".ss-gridfield-inline-new:last").find("input"); - if (input.attr('type') === 'text' && input.is(lastInput) && input.val() === '') - { - var inputWrapperDivClass = input.parent().attr('class'); - // Split clipboard data into lines - var lines = clipboardData.getData("text/plain").match(/[^\r\n]+/g); - var linesLength = lines.length; - // If there are multiple newlines detected, split the data into new rows automatically - if (linesLength > 1) - { - var elementsChanged = []; - for (var i = 1; i < linesLength; ++i) - { - this.trigger("addnewinline"); - var row = this.find(".ss-gridfield-inline-new:last"); - var rowInput = row.find("."+inputWrapperDivClass).find("input"); - rowInput.val(lines[i]); - elementsChanged.push(rowInput); - } - // Store the rows added via this method so they can be undo'd. - input.data('pasteManipulatedElements', elementsChanged); - // To set the current row to not just be all the clipboard data, must wait a frame - setTimeout(function() { - input.val(lines[0]); - }, 0); - } - } - } - } - }, - onkeyup: function(e) { - if (e.keyCode == 90 && e.ctrlKey) - { - var target = $(e.target); - var elementsChanged = target.data("pasteManipulatedElements"); - if (typeof elementsChanged !== "undefined" && elementsChanged && elementsChanged.length) - { - for (var i = 0; i < elementsChanged.length; ++i) - { - elementsChanged[i].closest('tr').remove(); - } - target.data("pasteManipulatedElements", []); - } - } - }, - onaddnewinline: function(e) { - if(e.target != this[0]) { - return; - } - - var tmpl = window.tmpl; - var row = this.find(".ss-gridfield-add-inline-template:last"); - var num = this.data("add-inline-num") || 1; - - tmpl.cache[this[0].id + "ss-gridfield-add-inline-template"] = tmpl(row.html()); - - this.find("tbody:first").append(tmpl(this[0].id + "ss-gridfield-add-inline-template", { num: num })); - this.find("tbody:first").children(".ss-gridfield-no-items").hide(); - this.data("add-inline-num", num + 1); - } - }); - - $(".ss-gridfield-add-new-inline").entwine({ - onclick: function() { - this.getGridField().trigger("addnewinline"); - 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.ss-gridfield-inline-new:first").remove(); - } - - return false; - } - }); - - /** - * GridFieldAddNewMultiClass - */ - - $(".ss-gridfield-add-new-multi-class .ss-ui-button").entwine({ - onclick: function() { - var link = this.data("href"); - var cls = this.parents(".ss-gridfield-add-new-multi-class").find("select").val(); - - if(cls && cls.length) { - this.getGridField().showDetailView(link.replace("{class}", 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"); - } - } - }); - - /** - * GridFieldEditableColumns - */ - - $('.ss-gridfield.ss-gridfield-editable .ss-gridfield-item td').entwine({ - onclick: function(e) { - // Prevent the default row click action when clicking a cell that contains a field - if (this.find('.editable-column-field').length) { - e.stopPropagation(); - } - } - }); - - /** - * GridFieldOrderableRows - */ - - $(".ss-gridfield-orderable tbody").entwine({ - onadd: function() { - var self = this; - - var helper = function(e, row) { - return row.clone() - .addClass("ss-gridfield-orderhelper") - .width("auto") - .find(".col-buttons") - .remove() - .end(); - }; - - var update = function() { - var grid = self.getGridField(); - - var data = grid.getItems().map(function() { - return { name: "order[]", value: $(this).data("id") }; - }); - - if (grid.data("immediate-update")) - { - grid.reload({ - url: grid.data("url-reorder"), - data: data.get() - }); - } - else - { - // Tells the user they have unsaved changes when they - // try and leave the page after sorting, also updates the - // save buttons to show the user they've made a change. - var form = $('.cms-edit-form'); - form.addClass('changed'); - } - }; - - this.sortable({ - handle: ".handle", - helper: helper, - opacity: .7, - update: update - }); - }, - onremove: function() { - if(this.data('sortable')) { - this.sortable("destroy"); - } - } - }); - - $(".ss-gridfield-orderable .ss-gridfield-previouspage, .ss-gridfield-orderable .ss-gridfield-nextpage").entwine({ - onadd: function() { - var grid = this.getGridField(); - - if(this.is(":disabled")) { - return false; - } - - var drop = function(e, ui) { - var page; - - if($(this).hasClass("ss-gridfield-previouspage")) { - page = "prev"; - } else { - page = "next"; - } - - grid.find("tbody").sortable("cancel"); - grid.reload({ - url: grid.data("url-movetopage"), - data: [ - { name: "move[id]", value: ui.draggable.data("id") }, - { name: "move[page]", value: page } - ] - }); - }; - - this.droppable({ - accept: ".ss-gridfield-item", - activeClass: "ui-droppable-active ui-state-highlight", - disabled: this.prop("disabled"), - drop: drop, - tolerance: "pointer" - }); - }, - onremove: function() { - if(this.hasClass("ui-droppable")) this.droppable("destroy"); - } - }); - }); -})(jQuery); +(function($) { + $.entwine("ss", function($) { + /** + * GridFieldAddExistingSearchButton + */ + + $(".add-existing-search-dialog").entwine({ + loadDialog: function(deferred) { + var dialog = this.addClass("loading").children(".ui-dialog-content").empty(); + + deferred.done(function(data) { + dialog.html(data).parent().removeClass("loading"); + }); + } + }); + + $(".ss-gridfield .add-existing-search").entwine({ + onclick: function() { + var dialog = $("
").appendTo("body").dialog({ + modal: true, + resizable: false, + width: 500, + height: 600, + close: function() { + $(this).dialog("destroy").remove(); + } + }); + + dialog.parent().addClass("add-existing-search-dialog").loadDialog( + $.get(this.prop("href")) + ); + dialog.data("grid", this.closest(".ss-gridfield")); + + return false; + } + }); + + $(".add-existing-search-dialog .add-existing-search-form").entwine({ + onsubmit: function() { + this.closest(".add-existing-search-dialog").loadDialog($.get( + this.prop("action"), this.serialize() + )); + return false; + } + }); + + $(".add-existing-search-dialog .add-existing-search-items a").entwine({ + onclick: function() { + var link = this.closest(".add-existing-search-items").data("add-link"); + var id = this.data("id"); + + var dialog = this.closest(".add-existing-search-dialog") + .addClass("loading") + .children(".ui-dialog-content") + .empty(); + + $.post(link, { id: id }, function() { + dialog.data("grid").reload(); + dialog.dialog("close"); + }); + + return false; + } + }); + + $(".add-existing-search-dialog .add-existing-search-pagination a").entwine({ + onclick: function() { + this.closest(".add-existing-search-dialog").loadDialog($.get( + this.prop("href") + )); + return false; + } + }); + + /** + * GridFieldAddNewInlineButton + */ + + $(".ss-gridfield.ss-gridfield-editable").entwine({ + reload: function(opts, success) { + var grid = this; + // Record position of all items + var added = []; + var index = 0; // 0-based index + grid.find("tbody:first .ss-gridfield-item").each(function() { + // Record inline items with their original positions + if ($(this).is(".ss-gridfield-inline-new")) { + added.push({ + 'index': index, + 'row': $(this).detach() + }); + } + index++; + }); + + this._super(opts, function() { + var body = grid.find("tbody:first"); + $.each(added, function(i, item) { + var row = item['row'], + index = item['index'], + replaces; + // Insert at index position + if (index === 0) { + body.prepend(row); + } else { + // Find item that we could potentially insert this row after + replaces = body.find('.ss-gridfield-item:nth-child(' + index + ')'); + if (replaces.length) { + replaces.after(row); + } else { + body.append(row); + } + } + grid.find("tbody:first").children(".ss-gridfield-no-items").hide(); + }); + + if(success) success.apply(grid, arguments); + }); + }, + onpaste: function(e) { + // The following was used as a basis for clipboard data access: + // http://stackoverflow.com/questions/2176861/javascript-get-clipboard-data-on-paste-event-cross-browser + var clipboardData = typeof e.originalEvent.clipboardData !== "undefined" ? e.originalEvent.clipboardData : null; + if (clipboardData) { + // Get current input wrapper div class (ie. 'col-Title') + var input = $(e.target); + var inputType = input.attr('type'); + if (inputType === 'text' || inputType === 'email') + { + var lastInput = this.find(".ss-gridfield-inline-new:last").find("input"); + if (input.attr('type') === 'text' && input.is(lastInput) && input.val() === '') + { + var inputWrapperDivClass = input.parent().attr('class'); + // Split clipboard data into lines + var lines = clipboardData.getData("text/plain").match(/[^\r\n]+/g); + var linesLength = lines.length; + // If there are multiple newlines detected, split the data into new rows automatically + if (linesLength > 1) + { + var elementsChanged = []; + for (var i = 1; i < linesLength; ++i) + { + this.trigger("addnewinline"); + var row = this.find(".ss-gridfield-inline-new:last"); + var rowInput = row.find("."+inputWrapperDivClass).find("input"); + rowInput.val(lines[i]); + elementsChanged.push(rowInput); + } + // Store the rows added via this method so they can be undo'd. + input.data('pasteManipulatedElements', elementsChanged); + // To set the current row to not just be all the clipboard data, must wait a frame + setTimeout(function() { + input.val(lines[0]); + }, 0); + } + } + } + } + }, + onkeyup: function(e) { + if (e.keyCode == 90 && e.ctrlKey) + { + var target = $(e.target); + var elementsChanged = target.data("pasteManipulatedElements"); + if (typeof elementsChanged !== "undefined" && elementsChanged && elementsChanged.length) + { + for (var i = 0; i < elementsChanged.length; ++i) + { + elementsChanged[i].closest('tr').remove(); + } + target.data("pasteManipulatedElements", []); + } + } + }, + onaddnewinline: function(e) { + if(e.target != this[0]) { + return; + } + + var tmpl = window.tmpl; + var row = this.find(".ss-gridfield-add-inline-template:last"); + var num = this.data("add-inline-num") || 1; + + tmpl.cache[this[0].id + "ss-gridfield-add-inline-template"] = tmpl(row.html()); + + this.find("tbody:first").append(tmpl(this[0].id + "ss-gridfield-add-inline-template", { num: num })); + this.find("tbody:first").children(".ss-gridfield-no-items").hide(); + this.data("add-inline-num", num + 1); + + // Rebuild sort order fields + $(".ss-gridfield-orderable tbody").rebuildSort(); + } + }); + + $(".ss-gridfield-add-new-inline").entwine({ + onclick: function() { + this.getGridField().trigger("addnewinline"); + 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.ss-gridfield-inline-new:first").remove(); + } + + return false; + } + }); + + /** + * GridFieldAddNewMultiClass + */ + + $(".ss-gridfield-add-new-multi-class .ss-ui-button").entwine({ + onclick: function() { + var link = this.data("href"); + var cls = this.parents(".ss-gridfield-add-new-multi-class").find("select").val(); + + if(cls && cls.length) { + this.getGridField().showDetailView(link.replace("{class}", 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"); + } + } + }); + + /** + * GridFieldEditableColumns + */ + + $('.ss-gridfield.ss-gridfield-editable .ss-gridfield-item td').entwine({ + onclick: function(e) { + // Prevent the default row click action when clicking a cell that contains a field + if (this.find('.editable-column-field').length) { + e.stopPropagation(); + } + } + }); + + /** + * GridFieldOrderableRows + */ + + $(".ss-gridfield-orderable tbody").entwine({ + rebuildSort: function() { + var grid = this.getGridField(); + + // Get lowest sort value in this list (respects pagination) + var minSort = null; + grid.getItems().each(function() { + // get sort field + var sortField = $(this).find('.ss-orderable-hidden-sort'); + if (sortField.length) { + var thisSort = sortField.val(); + if (minSort === null && thisSort > 0) { + minSort = thisSort; + } else if (thisSort > 0) { + minSort = Math.min(minSort, thisSort); + } + } + }); + minSort = Math.max(1, minSort); + + // With the min sort found, loop through all records and re-arrange + var sort = minSort; + grid.getItems().each(function() { + // get sort field + var sortField = $(this).find('.ss-orderable-hidden-sort'); + if (sortField.length) { + sortField.val(sort); + sort++; + } + }); + }, + onadd: function() { + var self = this; + + var helper = function(e, row) { + return row.clone() + .addClass("ss-gridfield-orderhelper") + .width("auto") + .find(".col-buttons") + .remove() + .end(); + }; + + var update = function(event, ui) { + // If the item being dragged is unsaved, don't do anything + var postback = true; + if (ui.item.hasClass('ss-gridfield-inline-new')) { + postback = false; + } + + // Rebuild all sort hidden fields + self.rebuildSort(); + + // Check if we are allowed to postback + var grid = self.getGridField(); + if (grid.data("immediate-update") && postback) + { + grid.reload({ + url: grid.data("url-reorder") + }); + } + else + { + // Tells the user they have unsaved changes when they + // try and leave the page after sorting, also updates the + // save buttons to show the user they've made a change. + var form = $('.cms-edit-form'); + form.addClass('changed'); + } + }; + + this.sortable({ + handle: ".handle", + helper: helper, + opacity: .7, + update: update + }); + }, + onremove: function() { + if(this.data('sortable')) { + this.sortable("destroy"); + } + } + }); + + $(".ss-gridfield-orderable .ss-gridfield-previouspage, .ss-gridfield-orderable .ss-gridfield-nextpage").entwine({ + onadd: function() { + var grid = this.getGridField(); + + if(this.is(":disabled")) { + return false; + } + + var drop = function(e, ui) { + var page; + + if($(this).hasClass("ss-gridfield-previouspage")) { + page = "prev"; + } else { + page = "next"; + } + + grid.find("tbody").sortable("cancel"); + grid.reload({ + url: grid.data("url-movetopage"), + data: [ + { name: "move[id]", value: ui.draggable.data("id") }, + { name: "move[page]", value: page } + ] + }); + }; + + this.droppable({ + accept: ".ss-gridfield-item", + activeClass: "ui-droppable-active ui-state-highlight", + disabled: this.prop("disabled"), + drop: drop, + tolerance: "pointer" + }); + }, + onremove: function() { + if(this.hasClass("ui-droppable")) this.droppable("destroy"); + } + }); + }); +})(jQuery); diff --git a/templates/GridFieldAddNewInlineRow.ss b/templates/GridFieldAddNewInlineRow.ss index 90a4dc0..3096bfd 100644 --- a/templates/GridFieldAddNewInlineRow.ss +++ b/templates/GridFieldAddNewInlineRow.ss @@ -1,5 +1,5 @@