mirror of
https://github.com/symbiote/silverstripe-gridfieldextensions.git
synced 2024-10-22 17:05:39 +02:00
parent
b93b32b3f9
commit
974c981721
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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 = $("<div></div>").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 = $("<div></div>").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);
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script type="text/x-tmpl" class="ss-gridfield-add-inline-template">
|
||||
<tr class="ss-gridfield-inline-new">
|
||||
<tr class="ss-gridfield-item ss-gridfield-inline-new">
|
||||
<% loop $Me %>
|
||||
<% if $IsActions %>
|
||||
<td$Attributes>
|
||||
|
@ -1 +1,2 @@
|
||||
<span class="handle"><span class="icon"></span></span>
|
||||
<span class="handle"><span class="icon"></span></span>
|
||||
$SortField
|
||||
|
@ -32,13 +32,18 @@ class GridFieldOrderableRowsTest extends SapphireTest {
|
||||
);
|
||||
|
||||
$originalOrder = $parent->MyManyMany()->sort('ManyManySort')->column('ID');
|
||||
$desiredOrder = array_reverse($originalOrder);
|
||||
$desiredOrder = array();
|
||||
|
||||
// Make order non-contiguous, and 1-based
|
||||
foreach(array_reverse($originalOrder) as $index => $id) {
|
||||
$desiredOrder[$index * 2 + 1] = $id;
|
||||
}
|
||||
|
||||
$this->assertNotEquals($originalOrder, $desiredOrder);
|
||||
|
||||
$reflection->invoke($orderable, $grid, $desiredOrder);
|
||||
|
||||
$newOrder = $parent->MyManyMany()->sort('ManyManySort')->column('ID');
|
||||
$newOrder = $parent->MyManyMany()->sort('ManyManySort')->map('ManyManySort', 'ID')->toArray();
|
||||
|
||||
$this->assertEquals($desiredOrder, $newOrder);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user