diff --git a/etemplate/js/et2_extension_nextmatch_actions.js b/etemplate/js/et2_extension_nextmatch_actions.js index 8ec25864df..1ac0e4e69b 100644 --- a/etemplate/js/et2_extension_nextmatch_actions.js +++ b/etemplate/js/et2_extension_nextmatch_actions.js @@ -102,6 +102,16 @@ function nm_action(_action, _senders, _target, _ids) egw.open_link(url,target,_action.data.width+'x'+_action.data.height); break; + case 'long_task': + // Run a long task once for each ID with a nice dialog instead of + // freezing for a while. If egw_open is set, and only 1 row selected, + // egw_open will be used instead. + if(idsArr.length > 1 || typeof _action.data.egw_open == 'undefined') + { + et2_dialog.long_task(null,_action.data.message||_action.caption,_action.data.title,_action.data.menuaction,idsArr); + break; + } + // Fall through case 'egw_open': var params = _action.data.egw_open.split('-'); // type-appname-idNum (idNum is part of id split by :), eg. "edit-infolog" diff --git a/etemplate/js/et2_widget_dialog.js b/etemplate/js/et2_widget_dialog.js index 130ae0e3a0..2c8ad99bef 100644 --- a/etemplate/js/et2_widget_dialog.js +++ b/etemplate/js/et2_widget_dialog.js @@ -443,7 +443,7 @@ jQuery.extend(et2_dialog, * Show a confirmation dialog * * @param function _callback Function called when the user clicks a button. The context will be the et2_dialog widget, and the button constant is passed in. - * @param String _message Message to be place in the dialog. Usually just text, but DOM nodes will work too. + * @param String _message Message to be place in the dialog. * @param String _title Text in the top bar of the dialog. * @param any _value passed unchanged to callback as 2. parameter * @param integer|Array _buttons One of the BUTTONS_ constants defining the set of buttons at the bottom of the box @@ -467,7 +467,7 @@ jQuery.extend(et2_dialog, * Show a prompt dialog * * @param function _callback Function called when the user clicks a button. The context will be the et2_dialog widget, and the button constant is passed in. - * @param String _message Message to be place in the dialog. Usually just text, but DOM nodes will work too. + * @param String _message Message to be place in the dialog. * @param String _title Text in the top bar of the dialog. * @param String _value for prompt, passed to callback as 2. parameter * @param integer|Array _buttons One of the BUTTONS_ constants defining the set of buttons at the bottom of the box @@ -523,4 +523,127 @@ jQuery.extend(et2_dialog, et2_dialog.show_dialog(callbackDialog, egw.lang(dialogMsg),egw.lang(titleMsg), {},et2_dialog.BUTTON_YES_NO, et2_dialog.WARNING_MESSAGE); }, + + /** + * Show a dialog for a long-running, multi-part task + * + * Given a server url and a list of parameters, this will open a dialog with + * a progress bar, asynchronously call the url with each parameter, and update + * the progress bar. + * Any output from the server will be displayed in a box. + * + * When all tasks are done, the callback will be called with boolean true. It will + * also be called if the user clicks a button (OK or CANCEL), so be sure to + * check to avoid executing more than intended. + * + * @param function _callback Function called when the user clicks a button, + * or when the list is done processing. The context will be the et2_dialog + * widget, and the button constant is passed in. + * @param String _message Message to be place in the dialog. Usually just + * text, but DOM nodes will work too. + * @param String _title Text in the top bar of the dialog. + * @param {string} _menuaction the menuaction function which should be called and + * which handles the actual request. If the menuaction is a full featured + * url, this one will be used instead. + * @param {Array[]} _list - List of parameters, one for each call to the + * address. Multiple parameters are allowed, in an array. + * + * @return {et2_dialog} + */ + long_task: function(_callback, _message, _title, _menuaction, _list) + { + // Special action for cancel + var buttons = [ + {"button_id": et2_dialog.OK_BUTTON,"text": egw.lang('ok'), "default":true, "disabled":true}, + {"button_id": et2_dialog.CANCEL_BUTTON,"text": egw.lang('cancel'), click: function() { + // Cancel run + cancel = true; + $j("button[button_id="+et2_dialog.CANCEL_BUTTON+"]", dialog.div.parent()).button("disable"); + update.call(_list.length,''); + }} + ]; + var dialog = et2_createWidget("dialog", { + template: egw.webserverUrl+'/etemplate/templates/default/long_task.xet', + value: { + content: { + message: _message + } + }, + callback: function(_button_id, _value) { + if(_button_id == et2_dialog.CANCEL_BUTTON) + { + cancel = true; + } + if (typeof _callback == "function") + { + _callback.call(this, _button_id, _value.value); + } + }, + title: _title||egw.lang('please wait...'), + buttons: buttons + }); + + // OK starts disabled + $j("button[button_id="+et2_dialog.OK_BUTTON+"]", dialog.div.parent()).button("disable"); + + var log = null; + var progressbar = null; + var cancel = false; + + // Updates progressbar & log, calls next step + var update = function(response) { + // context is index + var index = this || 0; + + progressbar.set_value(100*(index/_list.length)); + + // Display response information + switch(response.type) + { + case 'error': + log.append("
"+response.data+"
"); + break; + default: + if(response) + { + log.append("
"+response+"
"); + } + } + // Scroll to bottom + var height = log[0].scrollHeight; + log.scrollTop(height); + + // Fire next step + if(!cancel && index < _list.length) + { + var parameters = _list[index]; + if(typeof parameters != 'object') parameters = [parameters]; + + // Async request, we'll take the next step in the callback + egw.json(_menuaction, parameters, update, index+1,true,index+1).sendRequest(); + } + else + { + // All done + if(!cancel) progressbar.set_value(100); + $j("button[button_id="+et2_dialog.CANCEL_BUTTON+"]", dialog.div.parent()).button("disable"); + $j("button[button_id="+et2_dialog.OK_BUTTON+"]", dialog.div.parent()).button("enable"); + if (!cancel && typeof _callback == "function") + { + _callback.call(dialog, true); + } + } + }; + + $j(dialog.template.DOMContainer).on('load', function() { + // Get access to template widgets + log = $j(dialog.template.widgetContainer.getWidgetById('log').getDOMNode()); + progressbar = dialog.template.widgetContainer.getWidgetById('progressbar'); + + // Start + window.setTimeout(function() {update.call(0,'');},0); + }); + + return dialog; + } }); diff --git a/etemplate/templates/default/long_task.xet b/etemplate/templates/default/long_task.xet new file mode 100644 index 0000000000..bdd10e60db --- /dev/null +++ b/etemplate/templates/default/long_task.xet @@ -0,0 +1,27 @@ + + + + + \ No newline at end of file