BUGFIX Allowing "batch action" selection in new jstree implementations (first draft, doesn't reflect success/fail state on nodes afterwards)

BUGFIX Passing native JSON array back from CMSBatchActionHandler in order to simplify clientside logic in LeftAndMain.BatchActions.js
This commit is contained in:
Ingo Schommer 2011-03-22 16:45:13 +13:00
parent 6700abe570
commit 6cfade0b3d
2 changed files with 46 additions and 116 deletions

View File

@ -138,8 +138,8 @@ class CMSBatchActionHandler extends RequestHandler {
} else { } else {
$applicableIDs = $ids; $applicableIDs = $ids;
} }
$response = new SS_HTTPResponse(json_encode($applicableIDs)); $response = new SS_HTTPResponse(Convert::raw2json(array_values($applicableIDs)));
$response->addHeader("Content-type", "application/json"); $response->addHeader("Content-type", "application/json");
return $response; return $response;
} }

View File

@ -36,23 +36,23 @@
* Constructor: onmatch * Constructor: onmatch
*/ */
onmatch: function() { onmatch: function() {
var self = this; var self = this, tree = $('#sitetree_ul');
this.setTree($('#sitetree')[0]); this.setTree(tree);
$(this.getTree()).bind('select_node.jstree', function(e, data) { tree.bind('check_node.jstree', function(e, data) {
self._treeSelectionChanged(data.rslt.obj); self.serializeFromTree();
}); });
// if tab which contains this form is shown, make the tree selectable // if tab which contains this form is shown, make the tree selectable
$('#TreeActions').bind('tabsselect', function(e, ui) { $('#TreeActions').bind('tabsselect', function(e, ui) {
// if we are selecting another tab, or the panel is visible (meaning about to be closed), // if we are selecting another tab, or the panel is visible (meaning about to be closed),
// disable tree selection and reset any values. Otherwise enable it. // disable tree selection and reset any values. Otherwise enable it.
if($(ui.panel).attr('id') != 'TreeActions-batchactions' || $(ui.panel).is(':visible')) { if($(ui.panel).attr('id') != 'TreeActions-batchactions' || $(ui.panel).is(':visible')) {
// @TODO: this is unneccessarily fired also when switching between two other tabs // @TODO: this is unneccessarily fired also when switching between two other tabs
$(self.getTree()).removeClass('multiselect'); tree.removeClass('multiple');
} else { } else {
self._multiselectTransform(); tree.addClass('multiple');
self.serializeFromTree(); self.serializeFromTree();
} }
}); });
@ -121,36 +121,29 @@
if(rootNode == null) rootNode = st; if(rootNode == null) rootNode = st;
for(var idx in ids) { for(var idx in ids) {
$(st.getTreeNodeByIdx(idx)).addClass('selected').attr('selected', 'selected'); $($(st).getNodeByID(idx)).addClass('selected').attr('selected', 'selected');
} }
jQuery(rootNode).find('li').each(function() { $(rootNode).find('li').each(function() {
var id = parseInt(this.id.replace('record-',''), 10); allIds.push($(this).data('id'));
if(id) allIds.push(id);
// Disable the nodes while the ajax request is being processed // Disable the nodes while the ajax request is being processed
$(this).removeClass('nodelete').addClass('treeloading'); $(this).addClass('treeloading').setEnabled(false);
}); });
// Post to the server to ask which pages can have this batch action applied // 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(','); var applicablePagesURL = this.find(':input[name=Action]').val() + '/applicablepages/?csvIDs=' + allIds.join(',');
jQuery.getJSON(applicablePagesURL, function(applicableIDs) { 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 // Set a CSS class on each tree node indicating which can be batch-actioned and which can't
jQuery(rootNode).find('li').each(function() { jQuery(rootNode).find('li').each(function() {
$(this).removeClass('treeloading'); $(this).removeClass('treeloading');
var id = parseInt(this.id.replace('record-',''), 10); var id = $(this).data('id');
if(id) { if(id == 0 || $.inArray(id, applicableIDs) >= 0) {
if(applicableIDMap[id] === true) { $(this).setEnabled(true);
$(this).removeClass('nodelete'); } else {
} else { // De-select the node if it's non-applicable
// De-select the node if it's non-applicable $(this).removeClass('selected').setEnabled(false);
$(this).removeClass('selected').addClass('nodelete');
}
} }
}); });
@ -165,17 +158,8 @@
* (boolean) * (boolean)
*/ */
serializeFromTree: function() { serializeFromTree: function() {
var tree = this.getTree(), ids = []; var tree = this.getTree(), ids = tree.getSelectedIDs();
// find all explicitly selected IDs
$(tree).find('li.selected').each(function() {
ids.push(tree.getIdxOf(this));
// // find implicitly selected children
// $(this).find('li').each(function() {
// ids.push(tree.getIdxOf(this));
// });
});
// if no IDs are selected, stop here. This is an implict way for the // if no IDs are selected, stop here. This is an implict way for the
// callback to cancel the actions // callback to cancel the actions
if(!ids || !ids.length) return false; if(!ids || !ids.length) return false;
@ -193,7 +177,7 @@
* {Array} ids * {Array} ids
*/ */
setIDs: function(ids) { setIDs: function(ids) {
this.find(':input[name=csvIDs]').val(ids.join(',')); if(ids) this.find(':input[name=csvIDs]').val(ids.join(','));
}, },
/** /**
@ -230,7 +214,7 @@
this.setIDs(ids); this.setIDs(ids);
// Reset failure states // Reset failure states
$(tree).find('li').removeClass('failed'); tree.find('li').removeClass('failed');
var button = this.find(':submit:first'); var button = this.find(':submit:first');
button.addClass('loading'); button.addClass('loading');
@ -253,43 +237,45 @@
// 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(id in data.modified) { for(id in data.modified) {
tree.setNodeTitle(id, data.modified[id]['TreeTitle']); tree.jstree('set_title', tree.getNodeByID(id), data.modified[id]['TreeTitle']);
} }
} }
if(data.deleted) { if(data.deleted) {
for(id in data.deleted) { for(id in data.deleted) {
var node = tree.getTreeNodeByIdx(id); var node = tree.getNodeByID(id);
if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node); // TODO Remove node
// if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node);
} }
} }
if(data.error) { if(data.error) {
for(id in data.error) { for(id in data.error) {
var node = tree.getTreeNodeByIdx(id); var node = tree.getNodeByID(id);
$(node).addClass('failed'); $(node).addClass('failed');
} }
} }
// Deselect all nodes // Deselect all nodes
$(tree).find('li').removeClass('selected'); tree.find('li').removeClass('selected');
// reset selection state // reset selection state
// TODO Should unselect all selected nodes as well // TODO Should unselect all selected nodes as well
// jQuery(tree).removeClass('multiselect'); tree.removeClass('multiple');
// Check if current page still exists, and refresh it. // TODO Fix up to work properly with jstree - unclear if state setting is still required in new design
// Otherwise remove the current form // // Check if current page still exists, and refresh it.
var selectedNode = tree.firstSelected(); // // Otherwise remove the current form
if(selectedNode) { // var selectedNode = tree.jstree('get_selected');
var selectedNodeId = tree.getIdxOf(selectedNode); // if(selectedNode) {
if(data.modified[selectedNode.getIdx()]) { // var selectedNodeId = selectedNode.getID();
// only if the current page was modified // if(data.modified[selectedNodeId]) {
selectedNode.selectTreeNode(); // // only if the current page was modified
} else if(data.deleted[selectedNode.getIdx()]) { // tree.jstree('select_node', selectedNode);
jQuery('#Form_EditForm').entwine('ss').removeForm(); // } else if(data.deleted[selectedNodeId]) {
} // jQuery('#Form_EditForm').entwine('ss').removeForm();
} else { // }
jQuery('#Form_EditForm').entwine('ss').removeForm(); // } else {
} // jQuery('#Form_EditForm').entwine('ss').removeForm();
// }
// close panel // close panel
// TODO Coupling with tabs // TODO Coupling with tabs
@ -299,64 +285,8 @@
}); });
return false; return false;
},
/**
* Function: _multiselectTransform
*
* Todo:
* This is simulating MultiselectTree functionality, and shouldn't be necessary.
*/
_multiselectTransform : function() {
// make tree selectable
jQuery(this.getTree()).addClass('multiselect');
// auto-select the current node
var node = this.getTree().firstSelected();
if(node){
$(node).removeClass('current').addClass('selected');
node.open();
// Open all existing children, which might trigger further
// ajaxExansion calls to ensure all nodes are selectable
var children = $(node).find('li').each(function() {
this.open();
});
}
},
/**
* Function: _treeSelectionChanged
*
* Only triggers if the field is considered 'active'.
*
* Todo:
* Most of this is basically simulating broken behaviour of the MultiselectTree mixin,
* and should be removed.
*/
_treeSelectionChanged: function(node) {
if(!this._isActive()) return;
if(node.selected) {
$(node).removeClass('selected').attr('selected', false);
} else {
// Select node
$(node).addClass('selected').attr('selected', true);
// Open node in order to allow proper selection of children
if($(node).hasClass('unexpanded')) {
node.open();
}
// Open all existing children, which might trigger further
// ajaxExansion calls to ensure all nodes are selectable
var children = $(node).find('li').each(function() {
this.open();
});
}
this.serializeFromTree();
} }
}); });
}); });