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:
Ingo Schommer 2010-04-13 06:42:21 +00:00
parent 168589a59f
commit a9f8fa2d24
2 changed files with 126 additions and 22 deletions

View File

@ -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:

View File

@ -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