silverstripe-framework/admin/javascript/LeftAndMain.BatchActions.js
Sam Minnee 3ee8f505b7 MINORE: Remove training whitespace.
The main benefit of this is so that authors who make use of
.editorconfig don't end up with whitespace changes in their PRs.

Spaces vs. tabs has been left alone, although that could do with a
tidy-up in SS4 after the switch to PSR-1/2.

The command used was this:

for match in '*.ss' '*.css' '*.scss' '*.html' '*.yml' '*.php' '*.js' '*.csv' '*.inc' '*.php5'; do
	find . -path ./thirdparty -not -prune -o -path ./admin/thirdparty -not -prune -o -type f -name "$match" -exec sed -E -i '' 's/[[:space:]]+$//' {} \+
	find . -path ./thirdparty -not -prune -o -path ./admin/thirdparty -not -prune -o -type f -name "$match" | xargs perl -pi -e 's/ +$//'
done
2016-01-07 10:15:54 +13:00

397 lines
11 KiB
JavaScript

/**
* File: LeftAndMain.BatchActions.js
*/
(function($) {
$.entwine('ss.tree', function($){
/**
* Class: #Form_BatchActionsForm
*
* Batch actions which take a bunch of selected pages,
* usually from the CMS tree implementation, and perform serverside
* callbacks on the whole set. We make the tree selectable when the jQuery.UI tab
* enclosing this form is opened.
*
* Events:
* register - Called before an action is added.
* unregister - Called before an action is removed.
*/
$('#Form_BatchActionsForm').entwine({
/**
* Variable: Actions
* (Array) Stores all actions that can be performed on the collected IDs as
* function closures. This might trigger filtering of the selected IDs,
* a confirmation message, etc.
*/
Actions: [],
getTree: function() {
return $('.cms-tree');
},
fromTree: {
oncheck_node: function(e, data){
this.serializeFromTree();
},
onuncheck_node: function(e, data){
this.serializeFromTree();
}
},
/**
* @func registerDefault
* @desc Register default bulk confirmation dialogs
*/
registerDefault: function() {
// Publish selected pages action
this.register('admin/pages/batchactions/publish', function(ids) {
var confirmed = confirm(
ss.i18n.inject(
ss.i18n._t(
"CMSMAIN.BATCH_PUBLISH_PROMPT",
"You have {num} page(s) selected.\n\nDo you really want to publish?"
),
{'num': ids.length}
)
);
return (confirmed) ? ids : false;
});
// Unpublish selected pages action
this.register('admin/pages/batchactions/unpublish', function(ids) {
var confirmed = confirm(
ss.i18n.inject(
ss.i18n._t(
"CMSMAIN.BATCH_UNPUBLISH_PROMPT",
"You have {num} page(s) selected.\n\nDo you really want to unpublish"
),
{'num': ids.length}
)
);
return (confirmed) ? ids : false;
});
// Delete selected pages action
// @deprecated since 4.0 Use archive instead
this.register('admin/pages/batchactions/delete', function(ids) {
var confirmed = confirm(
ss.i18n.inject(
ss.i18n._t(
"CMSMAIN.BATCH_DELETE_PROMPT",
"You have {num} page(s) selected.\n\nDo you really want to delete?"
),
{'num': ids.length}
)
);
return (confirmed) ? ids : false;
});
// Delete selected pages action
this.register('admin/pages/batchactions/archive', function(ids) {
var confirmed = confirm(
ss.i18n.inject(
ss.i18n._t(
"CMSMAIN.BATCH_ARCHIVE_PROMPT",
"You have {num} page(s) selected.\n\nAre you sure you want to archive these pages?\n\nThese pages and all of their children pages will be unpublished and sent to the archive."
),
{'num': ids.length}
)
);
return (confirmed) ? ids : false;
});
// Restore selected archived pages
this.register('admin/pages/batchactions/restore', function(ids) {
var confirmed = confirm(
ss.i18n.inject(
ss.i18n._t(
"CMSMAIN.BATCH_RESTORE_PROMPT",
"You have {num} page(s) selected.\n\nDo you really want to restore to stage?\n\nChildren of archived pages will be restored to the root level, unless those pages are also being restored."
),
{'num': ids.length}
)
);
return (confirmed) ? ids : false;
});
// Delete selected pages from live action
this.register('admin/pages/batchactions/deletefromlive', function(ids) {
var confirmed = confirm(
ss.i18n.inject(
ss.i18n._t(
"CMSMAIN.BATCH_DELETELIVE_PROMPT",
"You have {num} page(s) selected.\n\nDo you really want to delete these pages from live?"
),
{'num': ids.length}
)
);
return (confirmed) ? ids : false;
});
},
onadd: function() {
this.registerDefault();
this._super();
},
/**
* @func register
* @param {string} type
* @param {function} callback
*/
register: function(type, callback) {
this.trigger('register', {type: type, callback: callback});
var actions = this.getActions();
actions[type] = callback;
this.setActions(actions);
},
/**
* @func unregister
* @param {string} type
* @desc Remove an existing action.
*/
unregister: function(type) {
this.trigger('unregister', {type: type});
var actions = this.getActions();
if(actions[type]) delete actions[type];
this.setActions(actions);
},
/**
* @func refreshSelected
* @param {object} rootNode
* @desc Ajax callbacks determine which pages is selectable in a certain batch action.
*/
refreshSelected : function(rootNode) {
var self = this,
st = this.getTree(),
ids = this.getIDs(),
allIds = [],
viewMode = $('.cms-content-batchactions-button'),
actionUrl = this.find(':input[name=Action]').val();
// Default to refreshing the entire tree
if(rootNode == null) rootNode = st;
for(var idx in ids) {
$($(st).getNodeByID(idx)).addClass('selected').attr('selected', 'selected');
}
// If no action is selected, enable all nodes
if(!actionUrl || actionUrl == -1 || !viewMode.hasClass('active')) {
$(rootNode).find('li').each(function() {
$(this).setEnabled(true);
});
return;
}
// Disable the nodes while the ajax request is being processed
$(rootNode).find('li').each(function() {
allIds.push($(this).data('id'));
$(this).addClass('treeloading').setEnabled(false);
});
// Post to the server to ask which pages can have this batch action applied
// Retain existing query parameters in URL before appending path
var actionUrlParts = $.path.parseUrl(actionUrl);
var applicablePagesUrl = actionUrlParts.hrefNoSearch + '/applicablepages/';
applicablePagesUrl = $.path.addSearchParams(applicablePagesUrl, actionUrlParts.search);
applicablePagesUrl = $.path.addSearchParams(applicablePagesUrl, {csvIDs: allIds.join(',')});
jQuery.getJSON(applicablePagesUrl, function(applicableIDs) {
// 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 = $(this).data('id');
if(id == 0 || $.inArray(id, applicableIDs) >= 0) {
$(this).setEnabled(true);
} else {
// De-select the node if it's non-applicable
$(this).removeClass('selected').setEnabled(false);
$(this).prop('selected', false);
}
});
self.serializeFromTree();
});
},
/**
* @func serializeFromTree
* @return {boolean}
*/
serializeFromTree: function() {
var tree = this.getTree(), ids = tree.getSelectedIDs();
// write IDs to the hidden field
this.setIDs(ids);
return true;
},
/**
* @func setIDS
* @param {array} ids
*/
setIDs: function(ids) {
this.find(':input[name=csvIDs]').val(ids ? ids.join(',') : null);
},
/**
* @func getIDS
* @return {array}
*/
getIDs: function() {
// Map empty value to empty array
var value = this.find(':input[name=csvIDs]').val();
return value
? value.split(',')
: [];
},
onsubmit: function(e) {
var self = this, ids = this.getIDs(), tree = this.getTree(), actions = this.getActions();
// if no nodes are selected, return with an error
if(!ids || !ids.length) {
alert(ss.i18n._t('CMSMAIN.SELECTONEPAGE', 'Please select at least one page'));
e.preventDefault();
return false;
}
// apply callback, which might modify the IDs
var type = this.find(':input[name=Action]').val();
if(actions[type]) {
ids = this.getActions()[type].apply(this, [ids]);
}
// Discontinue processing if there are no further items
if(!ids || !ids.length) {
e.preventDefault();
return false;
}
// write (possibly modified) IDs back into to the hidden field
this.setIDs(ids);
// Reset failure states
tree.find('li').removeClass('failed');
var button = this.find(':submit:first');
button.addClass('loading');
jQuery.ajax({
// don't use original form url
url: type,
type: 'POST',
data: this.serializeArray(),
complete: function(xmlhttp, status) {
button.removeClass('loading');
// Refresh the tree.
// Makes sure all nodes have the correct CSS classes applied.
tree.jstree('refresh', -1);
self.setIDs([]);
// Reset action
self.find(':input[name=Action]').val('').change();
// status message (decode into UTF-8, HTTP headers don't allow multibyte)
var msg = xmlhttp.getResponseHeader('X-Status');
if(msg) statusMessage(decodeURIComponent(msg), (status == 'success') ? 'good' : 'bad');
},
success: function(data, status) {
var id, node;
if(data.modified) {
var modifiedNodes = [];
for(id in data.modified) {
node = tree.getNodeByID(id);
tree.jstree('set_text', node, data.modified[id]['TreeTitle']);
modifiedNodes.push(node);
}
$(modifiedNodes).effect('highlight');
}
if(data.deleted) {
for(id in data.deleted) {
node = tree.getNodeByID(id);
if(node.length) tree.jstree('delete_node', node);
}
}
if(data.error) {
for(id in data.error) {
node = tree.getNodeByID(id);
$(node).addClass('failed');
}
}
},
dataType: 'json'
});
// Never process this action; Only invoke via ajax
e.preventDefault();
return false;
}
});
$('.cms-content-batchactions-button').entwine({
onmatch: function () {
this._super();
this.updateTree();
},
onunmatch: function () {
this._super();
},
onclick: function (e) {
this.updateTree();
},
updateTree: function () {
var tree = $('.cms-tree'),
form = $('#Form_BatchActionsForm');
this._super();
if(this.data('active')) {
tree.addClass('multiple');
tree.removeClass('draggable');
form.serializeFromTree();
} else {
tree.removeClass('multiple');
tree.addClass('draggable');
}
$('#Form_BatchActionsForm').refreshSelected();
}
});
/**
* Class: #Form_BatchActionsForm :select[name=Action]
*/
$('#Form_BatchActionsForm select[name=Action]').entwine({
onchange: function(e) {
var form = $(e.target.form),
btn = form.find(':submit'),
selected = $(e.target).val();
if(!selected || selected == -1) {
btn.attr('disabled', 'disabled').button('refresh');
} else {
btn.removeAttr('disabled').button('refresh');
}
// Refresh selected / enabled nodes
$('#Form_BatchActionsForm').refreshSelected();
// TODO Should work by triggering change() along, but doesn't - entwine event bubbling?
this.trigger("liszt:updated");
this._super(e);
}
});
});
})(jQuery);