mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 08:05:56 +02:00
ENHANCEMENT: Update the checkboxes available to batch-actions to show only the applicable pages for that particular action.
API CHANGE: Allow for an applicablePages($idArray) method to be defined on a CMSBatchAction class. (from r94761) (from r96819) git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@102700 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
168589a59f
commit
a9f8fa2d24
@ -9,7 +9,8 @@ class CMSBatchActionHandler extends RequestHandler {
|
|||||||
static $batch_actions = array();
|
static $batch_actions = array();
|
||||||
|
|
||||||
static $url_handlers = array(
|
static $url_handlers = array(
|
||||||
'$BatchAction' => 'handleAction'
|
'$BatchAction/applicablepages' => 'handleApplicablePages',
|
||||||
|
'$BatchAction' => 'handleAction',
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $parentController;
|
protected $parentController;
|
||||||
@ -99,7 +100,6 @@ class CMSBatchActionHandler extends RequestHandler {
|
|||||||
$this->recordClass,
|
$this->recordClass,
|
||||||
implode(", ", $idsFromLive)
|
implode(", ", $idsFromLive)
|
||||||
);
|
);
|
||||||
Debug::message($sql);
|
|
||||||
$livePages = Versioned::get_by_stage($this->recordClass, 'Live', $sql);
|
$livePages = Versioned::get_by_stage($this->recordClass, 'Live', $sql);
|
||||||
if($pages) $pages->merge($livePages);
|
if($pages) $pages->merge($livePages);
|
||||||
else $pages = $livePages;
|
else $pages = $livePages;
|
||||||
@ -112,6 +112,28 @@ class CMSBatchActionHandler extends RequestHandler {
|
|||||||
return $actionHandler->run($pages);
|
return $actionHandler->run($pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleApplicablePages($request) {
|
||||||
|
// Find the action handler
|
||||||
|
$actions = Object::get_static($this->class, 'batch_actions');
|
||||||
|
$actionClass = $actions[$request->param('BatchAction')];
|
||||||
|
$actionHandler = new $actionClass['class']();
|
||||||
|
|
||||||
|
// Sanitise ID list and query the database for apges
|
||||||
|
$ids = split(' *, *', trim($request->requestVar('csvIDs')));
|
||||||
|
foreach($ids as $k => $id) $ids[$k] = (int)$id;
|
||||||
|
$ids = array_filter($ids);
|
||||||
|
|
||||||
|
if($actionHandler->hasMethod('applicablePages')) {
|
||||||
|
$applicableIDs = $actionHandler->applicablePages($ids);
|
||||||
|
} else {
|
||||||
|
$applicableIDs = $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = new SS_HTTPResponse(json_encode($applicableIDs));
|
||||||
|
$response->addHeader("Content-type", "application/json");
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a DataObjectSet of ArrayData objects containing the following pieces of info
|
* Return a DataObjectSet of ArrayData objects containing the following pieces of info
|
||||||
* about each batch action:
|
* about each batch action:
|
||||||
|
@ -44,8 +44,8 @@
|
|||||||
$(self.getTree()).removeClass('multiselect');
|
$(self.getTree()).removeClass('multiselect');
|
||||||
} else {
|
} else {
|
||||||
self._multiselectTransform();
|
self._multiselectTransform();
|
||||||
|
self.serializeFromTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this._super();
|
this._super();
|
||||||
@ -85,18 +85,94 @@
|
|||||||
return $('#TreeActions-batchactions').is(':visible');
|
return $('#TreeActions-batchactions').is(':visible');
|
||||||
},
|
},
|
||||||
|
|
||||||
onsubmit: function(e) {
|
/**
|
||||||
var ids = [];
|
* Ajax callbacks determine which pages is selectable in a certain batch action.
|
||||||
var tree = this.getTree();
|
*
|
||||||
|
* @param {Object} rootNode
|
||||||
|
*/
|
||||||
|
refreshSelected : function(rootNode) {
|
||||||
|
var self = this, st = this.getTree(), ids = this.getIDs(), allIds = [];
|
||||||
|
// Default to refreshing the entire tree
|
||||||
|
if(rootNode == null) rootNode = st;
|
||||||
|
|
||||||
|
for(var idx in ids) {
|
||||||
|
$(st.getTreeNodeByIdx(idx)).addClass('selected').attr('selected', 'selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(rootNode).find('li').each(function() {
|
||||||
|
var id = parseInt(this.id.replace('record-',''), 10);
|
||||||
|
if(id) allIds.push(id);
|
||||||
|
|
||||||
|
// Disable the nodes while the ajax request is being processed
|
||||||
|
$(this).removeClass('nodelete').addClass('treeloading');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Post to the server to ask which pages can have this batch action applied
|
||||||
|
var applicablePagesURL = this.find(':input[name=Action]').val() + '/applicablepages/?csvIDs=' + allIds.join(',');
|
||||||
|
jQuery.getJSON(applicablePagesURL, function(applicableIDs) {
|
||||||
|
var i;
|
||||||
|
var applicableIDMap = {};
|
||||||
|
for(i=0;i<applicableIDs.length;i++) applicableIDMap[applicableIDs[i]] = true;
|
||||||
|
|
||||||
|
// Set a CSS class on each tree node indicating which can be batch-actioned and which can't
|
||||||
|
jQuery(rootNode).find('li').each(function() {
|
||||||
|
$(this).removeClass('treeloading');
|
||||||
|
|
||||||
|
var id = parseInt(this.id.replace('record-',''), 10);
|
||||||
|
if(id) {
|
||||||
|
if(applicableIDMap[id] === true) {
|
||||||
|
$(this).removeClass('nodelete');
|
||||||
|
} else {
|
||||||
|
// De-select the node if it's non-applicable
|
||||||
|
$(this).removeClass('selected').addClass('nodelete');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.serializeFromTree();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
serializeFromTree: function() {
|
||||||
|
var tree = this.getTree(), ids = [];
|
||||||
|
|
||||||
// find all explicitly selected IDs
|
// find all explicitly selected IDs
|
||||||
$(tree).find('li.selected').each(function() {
|
$(tree).find('li.selected').each(function() {
|
||||||
ids.push(tree.getIdxOf(this));
|
ids.push(tree.getIdxOf(this));
|
||||||
// find implicitly selected children
|
// // find implicitly selected children
|
||||||
$(this).find('li').each(function() {
|
// $(this).find('li').each(function() {
|
||||||
ids.push(tree.getIdxOf(this));
|
// ids.push(tree.getIdxOf(this));
|
||||||
});
|
// });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// if no IDs are selected, stop here. This is an implict way for the
|
||||||
|
// callback to cancel the actions
|
||||||
|
if(!ids || !ids.length) return false;
|
||||||
|
|
||||||
|
// write IDs to the hidden field
|
||||||
|
this.setIDs(ids);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} ids
|
||||||
|
*/
|
||||||
|
setIDs: function(ids) {
|
||||||
|
this.find(':input[name=csvIDs]').val(ids.join(','));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
getIDs: function() {
|
||||||
|
return this.find(':input[name=csvIDs]').val().split(',');
|
||||||
|
},
|
||||||
|
|
||||||
|
onsubmit: function(e) {
|
||||||
|
var ids = this.getIDs();
|
||||||
|
var tree = this.getTree();
|
||||||
|
|
||||||
// if no nodes are selected, return with an error
|
// if no nodes are selected, return with an error
|
||||||
if(!ids || !ids.length) {
|
if(!ids || !ids.length) {
|
||||||
alert(ss.i18n._t('CMSMAIN.SELECTONEPAGE'));
|
alert(ss.i18n._t('CMSMAIN.SELECTONEPAGE'));
|
||||||
@ -107,12 +183,8 @@
|
|||||||
var type = this.find(':input[name=Action]').val();
|
var type = this.find(':input[name=Action]').val();
|
||||||
if(this.getActions()[type]) ids = this.getActions()[type].apply(this, [ids]);
|
if(this.getActions()[type]) ids = this.getActions()[type].apply(this, [ids]);
|
||||||
|
|
||||||
// if no IDs are selected, stop here. This is an implict way for the
|
// write (possibly modified) IDs back into to the hidden field
|
||||||
// callback to cancel the actions
|
this.setIDs(ids);
|
||||||
if(!ids || !ids.length) return false;
|
|
||||||
|
|
||||||
// write IDs to the hidden field
|
|
||||||
this.find(':input[name=csvIDs]').val(ids.join(','));
|
|
||||||
|
|
||||||
var button = this.find(':submit:first');
|
var button = this.find(':submit:first');
|
||||||
button.addClass('loading');
|
button.addClass('loading');
|
||||||
@ -130,14 +202,16 @@
|
|||||||
statusMessage(msg, (status == 'success') ? 'good' : 'bad');
|
statusMessage(msg, (status == 'success') ? 'good' : 'bad');
|
||||||
},
|
},
|
||||||
success: function(data, status) {
|
success: function(data, status) {
|
||||||
|
var id;
|
||||||
|
|
||||||
// TODO This should use a more common serialization in a new tree library
|
// TODO This should use a more common serialization in a new tree library
|
||||||
if(data.modified) {
|
if(data.modified) {
|
||||||
for(var id in data.modified) {
|
for(id in data.modified) {
|
||||||
tree.setNodeTitle(id, data.modified[id]['TreeTitle']);
|
tree.setNodeTitle(id, data.modified[id]['TreeTitle']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(data.deleted) {
|
if(data.deleted) {
|
||||||
for(var id in data.deleted) {
|
for(id in data.deleted) {
|
||||||
var node = tree.getTreeNodeByIdx(id);
|
var node = tree.getTreeNodeByIdx(id);
|
||||||
if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node);
|
if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node);
|
||||||
}
|
}
|
||||||
@ -221,10 +295,18 @@
|
|||||||
this.open();
|
this.open();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.serializeFromTree();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#Form_BatchActionsForm :select[name=Action]').entwine({
|
||||||
|
onchange: function(e) {
|
||||||
|
$(e.target.form).entwine('ss').refreshSelected();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
/**
|
/**
|
||||||
* Publish selected pages action
|
* Publish selected pages action
|
||||||
|
Loading…
Reference in New Issue
Block a user