From 6cfade0b3d5f497a91df51ec0d6f72423597bc42 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Tue, 22 Mar 2011 16:45:13 +1300 Subject: [PATCH] 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 --- code/CMSBatchActionHandler.php | 4 +- javascript/LeftAndMain.BatchActions.js | 158 +++++++------------------ 2 files changed, 46 insertions(+), 116 deletions(-) diff --git a/code/CMSBatchActionHandler.php b/code/CMSBatchActionHandler.php index 2fe77e03..0341d8e3 100644 --- a/code/CMSBatchActionHandler.php +++ b/code/CMSBatchActionHandler.php @@ -138,8 +138,8 @@ class CMSBatchActionHandler extends RequestHandler { } else { $applicableIDs = $ids; } - - $response = new SS_HTTPResponse(json_encode($applicableIDs)); + + $response = new SS_HTTPResponse(Convert::raw2json(array_values($applicableIDs))); $response->addHeader("Content-type", "application/json"); return $response; } diff --git a/javascript/LeftAndMain.BatchActions.js b/javascript/LeftAndMain.BatchActions.js index ed2b64fc..124c8457 100644 --- a/javascript/LeftAndMain.BatchActions.js +++ b/javascript/LeftAndMain.BatchActions.js @@ -36,23 +36,23 @@ * Constructor: onmatch */ onmatch: function() { - var self = this; + var self = this, tree = $('#sitetree_ul'); - this.setTree($('#sitetree')[0]); - - $(this.getTree()).bind('select_node.jstree', function(e, data) { - self._treeSelectionChanged(data.rslt.obj); + this.setTree(tree); + + tree.bind('check_node.jstree', function(e, data) { + self.serializeFromTree(); }); - + // if tab which contains this form is shown, make the tree selectable $('#TreeActions').bind('tabsselect', function(e, ui) { // 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. if($(ui.panel).attr('id') != 'TreeActions-batchactions' || $(ui.panel).is(':visible')) { // @TODO: this is unneccessarily fired also when switching between two other tabs - $(self.getTree()).removeClass('multiselect'); + tree.removeClass('multiple'); } else { - self._multiselectTransform(); + tree.addClass('multiple'); self.serializeFromTree(); } }); @@ -121,36 +121,29 @@ if(rootNode == null) rootNode = st; 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() { - var id = parseInt(this.id.replace('record-',''), 10); - if(id) allIds.push(id); + $(rootNode).find('li').each(function() { + allIds.push($(this).data('id')); // 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 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= 0) { + $(this).setEnabled(true); + } else { + // De-select the node if it's non-applicable + $(this).removeClass('selected').setEnabled(false); } }); @@ -165,17 +158,8 @@ * (boolean) */ 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 // callback to cancel the actions if(!ids || !ids.length) return false; @@ -193,7 +177,7 @@ * {Array} 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); // Reset failure states - $(tree).find('li').removeClass('failed'); + tree.find('li').removeClass('failed'); var button = this.find(':submit:first'); button.addClass('loading'); @@ -253,43 +237,45 @@ // TODO This should use a more common serialization in a new tree library if(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) { for(id in data.deleted) { - var node = tree.getTreeNodeByIdx(id); - if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node); + var node = tree.getNodeByID(id); + // TODO Remove node + // if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node); } } if(data.error) { for(id in data.error) { - var node = tree.getTreeNodeByIdx(id); + var node = tree.getNodeByID(id); $(node).addClass('failed'); } } // Deselect all nodes - $(tree).find('li').removeClass('selected'); + tree.find('li').removeClass('selected'); // reset selection state // TODO Should unselect all selected nodes as well - // jQuery(tree).removeClass('multiselect'); + tree.removeClass('multiple'); - // Check if current page still exists, and refresh it. - // Otherwise remove the current form - var selectedNode = tree.firstSelected(); - if(selectedNode) { - var selectedNodeId = tree.getIdxOf(selectedNode); - if(data.modified[selectedNode.getIdx()]) { - // only if the current page was modified - selectedNode.selectTreeNode(); - } else if(data.deleted[selectedNode.getIdx()]) { - jQuery('#Form_EditForm').entwine('ss').removeForm(); - } - } else { - jQuery('#Form_EditForm').entwine('ss').removeForm(); - } + // TODO Fix up to work properly with jstree - unclear if state setting is still required in new design + // // Check if current page still exists, and refresh it. + // // Otherwise remove the current form + // var selectedNode = tree.jstree('get_selected'); + // if(selectedNode) { + // var selectedNodeId = selectedNode.getID(); + // if(data.modified[selectedNodeId]) { + // // only if the current page was modified + // tree.jstree('select_node', selectedNode); + // } else if(data.deleted[selectedNodeId]) { + // jQuery('#Form_EditForm').entwine('ss').removeForm(); + // } + // } else { + // jQuery('#Form_EditForm').entwine('ss').removeForm(); + // } // close panel // TODO Coupling with tabs @@ -299,64 +285,8 @@ }); 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(); } + }); });