Jump to content
MediaWiki

OOUI/Windows/Process Dialogs

From mediawiki.org
OOUI
OOUI is in maintenance mode. New code should use Codex .
Introduction
Getting started
Working with widgets
See also

v · d · e

Process dialog windows encapsulate a process and all of the code necessary to complete it. If the process terminates with an error, a customizable error interface alerts users to the trouble, permitting the user to dismiss the error and try again when relevant. The ProcessDialog class is always extended and customized with the methods and static properties required for each process.

The process dialog box consists of a header that visually represents the ‘working’ state of long processes with an animation. The header contains the dialog title as well as two ActionWidgets: a ‘safe’ action on the left (e.g., ‘Cancel’) and a ‘primary’ action on the right (e.g., ‘Done’). These actions are called ‘special’ actions. Any additional actions are called ‘other’ actions and are displayed in the dialog footer. Note that which actions are ‘special’ and which ‘other’ can be changed dynamically and/or accessed with the action set's getSpecial() or getOthers() methods.

Simple example

[edit ]

The following example illustrates a process dialog window with two ActionWidgets (‘Cancel’ and ‘Done’) displayed in its header. The dialog body contains a layout and message. Note that the window is not populated with this content when it is instantiated. Instead, its contents are added just before the window is opened for the first time, when the window manager calls the window's initialize() method. For an example of a window that is populated with contextual content passed at the time of opening, scroll down to the next example.

An example of a ProcessDialog

// Example: Creating and opening a process dialog window. 
// Subclass ProcessDialog.
functionProcessDialog(config){
ProcessDialog.super.call(this,config);
}
OO.inheritClass(ProcessDialog,OO.ui.ProcessDialog);
// Specify a name for .addWindows()
ProcessDialog.static.name='myDialog';
// Specify a static title and actions.
ProcessDialog.static.title='Process dialog';
ProcessDialog.static.actions=[
{
action:'save',
label:'Done',
flags:'primary'
},
{
label:'Cancel',
flags:'safe'
}
];
// Use the initialize() method to add content to the dialog's $body,
// to initialize widgets, and to set up event handlers.
ProcessDialog.prototype.initialize=function(){
ProcessDialog.super.prototype.initialize.apply(this,arguments);
this.content=newOO.ui.PanelLayout({
padded:true,
expanded:false
});
this.content.$element.append('<p>This is a process dialog window. The header contains the title and two buttons: \'Cancel\' (a safe action) on the left and \'Done\' (a primary action) on the right. </p>');
this.$body.append(this.content.$element);
};
// Use the getActionProcess() method to specify a process to handle the
// actions (for the 'save' action, in this example).
ProcessDialog.prototype.getActionProcess=function(action){
if(action){
returnnewOO.ui.Process(()=>{
this.close({
action:action
});
});
}
// Fallback to parent handler.
returnProcessDialog.super.prototype.getActionProcess.call(this,action);
};
// Get dialog height.
ProcessDialog.prototype.getBodyHeight=function(){
returnthis.content.$element.outerHeight(true);
};
// Create and append the window manager.
varwindowManager=newOO.ui.WindowManager();
$(document.body).append(windowManager.$element);
// Create a new dialog window.
varprocessDialog=newProcessDialog({
size:'small'
});
// Add windows to window manager using the addWindows() method.
windowManager.addWindows([processDialog]);
// Open the window.
windowManager.openWindow(processDialog);

The ‘primary’ and ‘safe’ actions (as well as any other actions specified) comprise an ActionSet . An action set can consist of multiple action widgets configured with the same action and/or the same flags. If multiple ‘safe’ and ‘primary’ actions are specified, the process dialog renders the first 'safe' and 'primary' action in its header. If an action is changed--to use a new flag, for example--the user interface is updated accordingly. To defer updating the interface until after all actions have been changed, use the forEach() method to iterate over the actions and update the user interface at the end of the iteration.

Using window data to set value of a text input when opening the dialog

[edit ]

The next example illustrates how the getSetupProcess() method is used to configure a window with contextual data that is passed at the time of opening.

An example of a ProcessDialog

// Example: Using getSetupProcess() to configure a window with data passed 
// at the time the window is opened. 
// Make a subclass of ProcessDialog 
functionMyDialog(config){
MyDialog.super.call(this,config);
}
OO.inheritClass(MyDialog,OO.ui.ProcessDialog);
// Specify a name for .addWindows()
MyDialog.static.name='myDialog';
// Specify the static configurations: title and action set
MyDialog.static.actions=[
{
flags:'primary',
label:'Continue',
action:'open'
},
{
flags:'safe',
label:'Cancel'
}
];
// Customize the initialize() function to add content and layouts: 
MyDialog.prototype.initialize=function(){
MyDialog.super.prototype.initialize.call(this);
this.panel=newOO.ui.PanelLayout({
padded:true,
expanded:false
});
this.content=newOO.ui.FieldsetLayout();
this.urlInput=newOO.ui.TextInputWidget();
this.field=newOO.ui.FieldLayout(this.urlInput,{
label:'Click continue to open the link in a new window',
align:'top'
});
this.content.addItems([this.field]);
this.panel.$element.append(this.content.$element);
this.$body.append(this.panel.$element);
this.urlInput.connect(this,{'change':'onUrlInputChange'});
};
// Specify any additional functionality required by the window (disable opening an empty URL, in this case)
MyDialog.prototype.onUrlInputChange=function(value){
this.actions.setAbilities({
open:!!value.length
});
};
// Specify the dialog height (or don't to use the automatically generated height).
MyDialog.prototype.getBodyHeight=function(){
// Note that "expanded: false" must be set in the panel's configuration for this to work.
// When working with a stack layout, you can use:
// return this.panels.getCurrentItem().$element.outerHeight( true );
returnthis.panel.$element.outerHeight(true);
};
// Use getSetupProcess() to set up the window with data passed to it at the time 
// of opening (e.g., url: 'http://www.mediawiki.org', in this example). 
MyDialog.prototype.getSetupProcess=function(data){
data=data||{};
returnMyDialog.super.prototype.getSetupProcess.call(this,data)
.next(function(){
// Set up contents based on data
this.urlInput.setValue(data.url);
},this);
};
// Specify processes to handle the actions.
MyDialog.prototype.getActionProcess=function(action){
if(action==='open'){
// Create a new process to handle the action
returnnewOO.ui.Process(function(){
window.open(this.urlInput.getValue());
},this);
}
// Fallback to parent handler
returnMyDialog.super.prototype.getActionProcess.call(this,action);
};
// Use the getTeardownProcess() method to perform actions whenever the dialog is closed. 
// This method provides access to data passed into the window's close() method 
// or the window manager's closeWindow() method.
MyDialog.prototype.getTeardownProcess=function(data){
returnMyDialog.super.prototype.getTeardownProcess.call(this,data)
.first(function(){
// Perform any cleanup as needed
},this);
};
// Create and append a window manager.
varwindowManager=newOO.ui.WindowManager();
$(document.body).append(windowManager.$element);
// Create a new process dialog window.
varmyDialog=newMyDialog();
// Add the window to window manager using the addWindows() method.
windowManager.addWindows([myDialog]);
// Open the window! 
windowManager.openWindow(myDialog,{url:'https://www.mediawiki.org'});

For a full list of supported methods and configuration options for process dialogs, please see the code-level documentation.

Action sets

[edit ]

ActionSets manage the behavior of the actions that comprise them, allowing developers to control which actions are available for specific contexts (modes) and circumstances (abilities):

  • modes: When an action widget is configured with modes (e.g., ‘edit’ or ‘preview’), the action set can make the action available or not based on those modes (set with the setMode() method). Each action will only be available if it is configured for the current mode. (See below example.)
  • abilities: When an action widget is configured with an action, the action set can make that action available or not based on abilities (set with the setAbilities() method). If a ‘save’ action is used to save content, for example, abilities can be used to disable the action until the content is determined to be valid. If multiple action widgets execute the ‘save’ action, all will be disabled until the criteria are met.
  • flags: primary and safe flags control the layout of the options. back and close flags provide defaults icons. See OOUI/Elements/Flagged#ProcessDialog.

The following example illustrates an action set that contains four action widgets: a primary action (‘continue’), two safe actions (‘cancel’ and ‘back’), and a ‘help’ action. Several of the actions have also been configured with modes: ‘edit’ or ‘help.’

// Example: an action set that contains four action widgets.
ProcessDialog.static.actions=[
{
action:'continue',
modes:'edit',
label:'Continue',
flags:['primary','progressive']
},
{
action:'help',
modes:'edit',
label:'Help'
},
{
modes:'edit',
label:'Cancel',
flags:['safe','close']
},
{
action:'back',
modes:'help',
label:'Back',
flags:['safe','back']
}
];

The process dialog in the next example uses the above action set to customize available actions based on the modes.

Example: Using modes and action sets.

Example: Using modes and action sets.

// Example: A process dialog that uses an action set with modes.
// Subclass ProcessDialog.
functionProcessDialog(config){
ProcessDialog.super.call(this,config);
}
OO.inheritClass(ProcessDialog,OO.ui.ProcessDialog);
// Specify a name for .addWindows()
ProcessDialog.static.name='myDialog';
// Specify a title and an action set that uses modes ('edit' and 'help' mode, in this example).
ProcessDialog.static.title='Process dialog';
ProcessDialog.static.actions=[
{
action:'continue',
modes:'edit',
label:'Continue',
flags:['primary','progressive']
},
{
action:'help',
modes:'edit',
label:'Help'
},
{
modes:'edit',
label:'Cancel',
flags:['safe','close']
},
{
action:'back',
modes:'help',
label:'Back',
flags:['safe','back']
}
];
// Customize the initialize() method to add content and set up event handlers. 
// This example uses a stack layout with two panels: one displayed for 
// edit mode and one for help mode.
ProcessDialog.prototype.initialize=function(){
ProcessDialog.super.prototype.initialize.apply(this,arguments);

this.panel1=newOO.ui.PanelLayout({padded:true,expanded:false});
this.panel1.$element.append('<p>This dialog uses an action set configured with modes. This is edit mode. Click \'help\' to see help mode. </p>');
this.panel2=newOO.ui.PanelLayout({padded:true,expanded:false});
this.panel2.$element.append('<p>This is help mode. Only the \'back\' button is configured to be visible here. Click \'back\' to return to \'edit\' mode</p>');
this.stackLayout=newOO.ui.StackLayout({
items:[this.panel1,this.panel2]
});
this.$body.append(this.stackLayout.$element);
};
// Set up the initial mode of the window ('edit', in this example.) 
ProcessDialog.prototype.getSetupProcess=function(data){
returnProcessDialog.super.prototype.getSetupProcess.call(this,data)
.next(function(){
this.actions.setMode('edit');
},this);
};
// Use the getActionProcess() method to set the modes and displayed item.
ProcessDialog.prototype.getActionProcess=function(action){

if(action==='help'){
// Set the mode to help.
this.actions.setMode('help');
// Show the help panel.
this.stackLayout.setItem(this.panel2);
}elseif(action==='back'){
// Set the mode to edit.
this.actions.setMode('edit');
// Show the edit panel.
this.stackLayout.setItem(this.panel1);
}elseif(action==='continue'){
vardialog=this;
returnnewOO.ui.Process(function(){
// Do something about the edit.
dialog.close();
});
}
returnProcessDialog.super.prototype.getActionProcess.call(this,action);
};
// Get dialog height.
ProcessDialog.prototype.getBodyHeight=function(){
returnthis.panel1.$element.outerHeight(true);
};
// Create and append the window manager.
varwindowManager=newOO.ui.WindowManager();
$(document.body).append(windowManager.$element);
// Create a new dialog window.
varprocessDialog=newProcessDialog({
size:'medium'
});
// Add windows to window manager using the addWindows() method.
windowManager.addWindows([processDialog]);
// Open the window.
windowManager.openWindow(processDialog);

For a full list of supported methods and configuration options for action sets, please see the code-level documentation.

Processes and errors

[edit ]

Process dialogs execute a process, which is a list of ‘steps’ that are called in sequence. If the process fails, an error is generated. Depending on how the error is configured, users can dismiss the error and try the process again, or not.

Each ‘step’ of a process can be a number, a jQuery promise, or a function:

  • function: If the step is a function, the process will execute it. Optionally, a function context can be specified as well. The process will stop if the function returns a Boolean ‘false’.
  • promise: If the step is a jQuery promise, the process will use the promise to either continue to the next step when the promise is resolved or to stop when the promise is rejected.
  • number: If the step is a number, the process will wait for the specified number of milliseconds before proceeding.

A ‘step’ can be added to the beginning of a process with the first() method, or to the end of it with the next() method.

The process is started with the execute() method, which returns a promise that is either resolved when all steps have completed or rejected with an error message if any of the steps return a Boolean ‘false’ or a promise is rejected. If a process is stopped, its remaining steps will not be performed.

The error messages used by the process dialog are configured with a required string argument (or jQuery selection) that is used as the error message as well as optional settings (recoverable or warning) that influence the appearance and functionality of the error interface.

The basic error message contains a formatted error message as well as two buttons: ‘Dismiss’ and ‘Try again’ (i.e., the error is recoverable by default). If recoverable is set to false, the ‘Try again’ button will not be rendered and the widget that initiated the failed process will be disabled.

Errors can also be configured as warnings. If warning is set to true, the error interface will include a ‘Dismiss’ and a ‘Continue’ button, which will try the process again. A warning might be used before a destructive action, such as ‘Delete all files’ to confirm that this is the user’s intent. It is the responsibility of the developer to ensure that the warning is not triggered a second time if the user chooses to continue.

Note that the appearance of the error message can be customized by using a jQuery selection instead of a string for the value of the required message argument. A jQuery selection will allow you to add links and/or spans for styling select parts of the error message. The error title is not configurable.

The following is an example of a process dialog that has been configured to display a recoverable error message (for the ‘Save’ process) and a non-recoverable error message (for the ‘Delete’ process). The example also uses a time delay to demonstrate how the window visually represents a long-running process with a header animation.

Example: Processes and errors.

// Example: a process dialog with customized error interfaces.
functionBrokenDialog(config){
BrokenDialog.super.call(this,config);
this.broken=false;
}
OO.inheritClass(BrokenDialog,OO.ui.ProcessDialog);
// Specify a name for .addWindows()
BrokenDialog.static.name='brokenDialog';
// Specify static actions and title
BrokenDialog.static.title='Broken dialog';
BrokenDialog.static.actions=[
{action:'save',label:'Save',flags:['primary','constructive']},
{action:'delete',label:'Delete',flags:'destructive'},
{action:'cancel',label:'Cancel',flags:'safe'}
];
// Get the height.
BrokenDialog.prototype.getBodyHeight=function(){
return250;
};

// Add content to the dialog body and setup event handlers.
BrokenDialog.prototype.initialize=function(){
BrokenDialog.super.prototype.initialize.apply(this,arguments);
this.content=newOO.ui.PanelLayout({padded:true});
this.fieldset=newOO.ui.FieldsetLayout({
label:'Dialog with error handling',icon:'alert'
});
this.description=newOO.ui.LabelWidget({
label:'Deleting will fail and will not be recoverable. '+
'Saving will fail the first time, but succeed the second time.'
});
this.fieldset.addItems([this.description]);
this.content.$element.append(this.fieldset.$element);
this.$body.append(this.content.$element);
};
// Add a 'broken' function to getSetupProcess() for purposes of this example.
BrokenDialog.prototype.getSetupProcess=function(data){
returnBrokenDialog.super.prototype.getSetupProcess.call(this,data)
.next(function(){
this.broken=true;
},this);
};

BrokenDialog.prototype.getActionProcess=function(action){
returnBrokenDialog.super.prototype.getActionProcess.call(this,action)
.next(function(){
return1000;
},this)
.next(function(){
varclosing;
if(action==='save'){
if(this.broken){
this.broken=false;
returnnewOO.ui.Error('Server did not respond');
}
}elseif(action==='delete'){
returnnewOO.ui.Error('Permission denied',{recoverable:false});
}
closing=this.close({action:action});
if(action==='save'){
// Return a promise to remain pending while closing
returnclosing;
}
returnBrokenDialog.super.prototype.getActionProcess.call(this,action);
},this);
};
// Create and append the window manager.
varwindowManager=newOO.ui.WindowManager();
$(document.body).append(windowManager.$element);
// Make the window. 
varbrokenDialog=newBrokenDialog({
size:'medium'
});
// Add windows to the window manager using the window manager’s addWindows() method.
windowManager.addWindows([brokenDialog]);
windowManager.openWindow(brokenDialog);

For a full list of supported methods and configuration options, please see the code-generated documentation for processes and errors.

OOUI is maintained by the Design System Team .

Get help:

AltStyle によって変換されたページ (->オリジナル) /