Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Orion/Dialog Support"

(Dialogs (modal and modeless))
(Dialogs (modal and modeless))
Line 6: Line 6:
  
 
=== Programming a dialog ===
 
=== Programming a dialog ===
Dialogs are implemented as an object which uses the <tt>Dialog</tt> prototype.  By convention, most Orion dialogs define a constructor whose sole parameter is an options object describing how the dialog is to be used.  This will be shown in the example code, but keep in mind that the client-facing API of the dialog is completely up to the developer.  The main requirement for implementation is that the <tt>Dialog</tt> prototype be used and the life-cycle methods called appropriately.  An example is the best way to demonstrate the behavior.  
+
Dialogs are implemented as an object which uses the <tt>Dialog</tt> prototype.  By convention, most Orion dialogs define a constructor whose sole parameter is an options object describing how the dialog is to be used.  This will be shown in the example code, but keep in mind that the client-facing API of the dialog is completely up to the developer.  The main requirement for implementation is that the <tt>Dialog</tt> prototype be used and the life-cycle functions called appropriately.  An example is the best way to demonstrate the behavior.  
  
 
<pre>
 
<pre>
Line 33: Line 33:
  
 
=== The Dialog life-cycle ===
 
=== The Dialog life-cycle ===
The dialog life-cycle is driven by the client code.  The <tt>Dialog</tt> prototype contains life-cycle methods that must be called by the client to initiate the dialog.  The stages of a dialog's life and sample code are as follows:
+
The dialog life-cycle is driven by the client code.  The <tt>Dialog</tt> prototype contains life-cycle functions that must be called by the client to initiate the dialog.  The stages of a dialog's life and sample code are as follows:
  
 
* Setting up the dialog template.  The dialog's content is described in an HTML string specified in a dialog variable called <tt>TEMPLATE</tt>.  By convention, most Orion dialogs define this variable in-line in the .js file that defines the dialog.  Developers who prefer to use separate HTML files may do so using any preferred template/fragment mechanism.  The key point is that the HTML is bound to the variable before initiating the dialog creation.
 
* Setting up the dialog template.  The dialog's content is described in an HTML string specified in a dialog variable called <tt>TEMPLATE</tt>.  By convention, most Orion dialogs define this variable in-line in the .js file that defines the dialog.  Developers who prefer to use separate HTML files may do so using any preferred template/fragment mechanism.  The key point is that the HTML is bound to the variable before initiating the dialog creation.
Line 51: Line 51:
 
</pre>
 
</pre>
  
* Dialog definition and setting up the basic (non-DOM) options.  This is driven by the client API.  Our convention is to call an internal <tt>_init</tt> method which reads the client options and sets up any necessary internal state.  The last thing to do in this method is to call the <tt>Dialog._initialize</tt> method.  The initialize sequence will look for special variables that drive the behavior of a dialog.  For example, a <tt>title</tt> will cause a title string to appear in the dialog frame.  An array of <tt>buttons</tt> will cause buttons to be created.  In this example, we are just setting a title.  The rest of the work in here pertains to our specific implementation until we call <tt>_initialize</tt>.
+
* Dialog definition and setting up the basic (non-DOM) options.  This is driven by the client API.  Our convention is to call an internal <tt>_init</tt> function which reads the client options and sets up any necessary internal state.  The last thing to do in this function is to call the <tt>Dialog._initialize</tt> function.  The initialize sequence will look for special variables that drive the behavior of a dialog.  For example, a <tt>title</tt> will cause a title string to appear in the dialog frame.  An array of <tt>buttons</tt> will cause buttons to be created.  In this example, we are just setting a title.  The rest of the work in here pertains to our specific implementation until we call <tt>_initialize</tt>.
 
<pre>
 
<pre>
 
OpenResourceDialog.prototype._init = function(options) {
 
OpenResourceDialog.prototype._init = function(options) {
Line 72: Line 72:
 
};
 
};
 
</pre>
 
</pre>
* Binding to the DOM elements.  Hooking events and other behavior that is dependent on the existence of the DOM elements happens in the <tt>_bindToDOM</tt> method.  This method is called by the dialog during the initialization process.  When this method is called, you can use the following variables to access the DOM:
+
* Binding to the DOM elements.  Hooking events and other behavior that is dependent on the existence of the DOM elements happens in the <tt>_bindToDOM</tt> function.  This function is called by the dialog during the initialization process.  When this function is called, you can use the following variables to access the DOM:
 
** <tt>this.$frameParent</tt> refers to the parent node of the entire dialog.  This is usually the document body, and typically does not need to be accessed by application dialog code.
 
** <tt>this.$frameParent</tt> refers to the parent node of the entire dialog.  This is usually the document body, and typically does not need to be accessed by application dialog code.
 
** <tt>this.$frame</tt> refers to the div element that frames the dialog. This typically does not need to be accessed by application dialogs.  
 
** <tt>this.$frame</tt> refers to the div element that frames the dialog. This typically does not need to be accessed by application dialogs.  
 
** <tt>this.$parent</tt> refers to the div element that parents the client template.  Clients may want to refer to this parent when querying the dialog content for a particular node.
 
** <tt>this.$parent</tt> refers to the div element that parents the client template.  Clients may want to refer to this parent when querying the dialog content for a particular node.
 
** <tt>this.$buttonContainer</tt> refers to the div element containing any autogenerated buttons.  This won't exist if no buttons were defined.
 
** <tt>this.$buttonContainer</tt> refers to the div element containing any autogenerated buttons.  This won't exist if no buttons were defined.
** Your content field id's are bound to $ instance variables during the <tt>_initialize</tt> method.  For example:
+
** Your content field id's are bound to $ instance variables during the <tt>_initialize</tt> function.  For example:
 
<pre>
 
<pre>
 
this.$fileName.addEventListener("input", function() { // do something }, false);
 
this.$fileName.addEventListener("input", function() { // do something }, false);
Line 83: Line 83:
  
 
The variable <tt>$fileName</tt> refers to the DOM node whose id is "fileName".  All nodes assigned an id in the template will be bound to a $ variable.
 
The variable <tt>$fileName</tt> refers to the DOM node whose id is "fileName".  All nodes assigned an id in the template will be bound to a $ variable.
 +
 +
* Modal behavior.  If the dialog should have modal behavior, set a modal flag before initialization. 
 +
<pre>
 +
MyModalDialog.prototype._init = function(options) {
 +
// Set values for things that dialog cares about, such as title. 
 +
this.title = "My Modal Dialog";
 +
this.modal = true;
 +
        ...
 +
</pre>
 +
 +
* Showing the dialog.  The dialog will not appear until the <tt>show()</tt> function is called.  This function is implemented by the Dialog prototype.  If your dialog needs to do some extra work during this time, the following optional functions may be implemented:
 +
** <tt>_beforeShowing</tt> is called just before the dialog is made visible.  Here, dom node values may be populated, etc.
 +
** <tt>_afterShowing</tt> is called just after the dialog is made visible.  This is a good place to set initial focus in the dialog.
 +
 +
* Finishing the dialog.  Most dialogs provide a button that the user pushes to indicate that the dialog is completed.  The text for the button is specified, in addition to the callback to use when the button is pressed.  In this example, an "OK" button is created, and it will call the application's <tt>done</tt> function.
 +
<pre>
 +
MyModalDialog.prototype._init = function(options) {
 +
// Set values for things that dialog cares about, such as title. 
 +
this.title = "My Modal Dialog";
 +
this.modal = true;
 +
        ...
 +
this.buttons = [{text: messages['OK'], callback: this.done.bind(this)}];
 +
        this._initialize();
 +
}
 +
</pre>
 +
 +
* Hiding and cleaning up.  The standard dialog frame provides a close icon that can be used to hide the dialog.  The application dialog will also typically hide the dialog when it's finished.  Either way, the <tt>hide()</tt> function is used to hide the dialog.  To clean up any listeners or other resources allocated by the dialog, use the following functions:
 +
** <tt>_beforeHiding</tt> is called just before the dialog is hidden.  Typically listeners are removed here.
 +
** <tt>_afterHiding</tt> is called just after the dialog is hidden for any final cleanup.  The DOM nodes still exist during this call.
 +
 +
* Destroying DOM nodes.  As of this writing, the DOM nodes are destroyed after the "hiding" sequence.  We assume clients recreate the dialog each time it is used.  If this usage pattern changes, we could always add an option that determines whether the dialog is actually destroyed when hidden
 +
  
 
=== Launching a dialog ===
 
=== Launching a dialog ===
=== More Examples ===
+
As mentioned previously, the developer of an individual dialog determines the API, but using the conventions discussed above, a typical sequence is to create the dialog using a constructor, passing in some function that is called when the dialog is finished.  Then, the client calls the <tt>show()</tt> function to show the dialog.  Most of the nitty gritty work done by the caller is done in the function passed to the dialog on creation. 
 +
 
 +
<pre>
 +
var dialog = new openResource.OpenResourceDialog({
 +
searcher: searcher,
 +
searchRenderer:searcher.defaultRenderer,
 +
favoriteService:favoriteService,
 +
onHide:  function() {
 +
if (editor) {
 +
editor.getTextView().focus();
 +
}
 +
}
 +
});
 +
dialog.show();
 +
</pre>
  
 
== Popup dialogs ==
 
== Popup dialogs ==

Revision as of 15:30, 2 January 2013

In Orion 2.0, we no longer rely on the dijit toolkit for our dialog implementations. Instead, we use lightweight Orion constructs and CSS. This document describes how to implement an Orion dialog.

Dialogs (modal and modeless)

The module "orion/webui/dialog" provides support for dialog behavior. This class defines a lightweight life-cycle for dialogs, provides optional modal behavior, template support, and automatic button creation.

Programming a dialog

Dialogs are implemented as an object which uses the Dialog prototype. By convention, most Orion dialogs define a constructor whose sole parameter is an options object describing how the dialog is to be used. This will be shown in the example code, but keep in mind that the client-facing API of the dialog is completely up to the developer. The main requirement for implementation is that the Dialog prototype be used and the life-cycle functions called appropriately. An example is the best way to demonstrate the behavior.

define(['i18n!orion/widgets/nls/messages','orion/webui/dialog'], 
		function(messages, dialog) {

/* This is the client facing API of OpenResourceDialog.  Up to the developer to decide what this looks like. */

/**
 * Usage: <code>new OpenResourceDialog(options).show();</code>
 * 
 * @name orion.webui.dialogs.OpenResourceDialog
 * @class A dialog that searches for files by name or wildcard.
 * @param {String} [options.title] Text to display in the dialog's titlebar.
 * @param {orion.searchClient.Searcher} options.searcher The searcher to use for displaying results.
 * @param {Function} options.onHide a function to call when the dialog is hidden.  Optional.
 */

function OpenResourceDialog(options) {
	this._init(options);
}
	
/* Use the Dialog prototype to inherit the common dialog behavior.  */
OpenResourceDialog.prototype = new dialog.Dialog();

The Dialog life-cycle

The dialog life-cycle is driven by the client code. The Dialog prototype contains life-cycle functions that must be called by the client to initiate the dialog. The stages of a dialog's life and sample code are as follows:

  • Setting up the dialog template. The dialog's content is described in an HTML string specified in a dialog variable called TEMPLATE. By convention, most Orion dialogs define this variable in-line in the .js file that defines the dialog. Developers who prefer to use separate HTML files may do so using any preferred template/fragment mechanism. The key point is that the HTML is bound to the variable before initiating the dialog creation.

The OpenResourceDialog defines the TEMPLATE in line.

OpenResourceDialog.prototype.TEMPLATE = 
'<div role="search">' + //$NON-NLS-0$
  '<div><label for="fileName">'+messages['Type the name of a file to open (? = any character, * = any string):']+'</label></div>' + //$NON-NLS-1$ //$NON-NLS-0$
  '<div><input id="fileName" type="text" placeholder="'+messages['Search']+'"</input></div>' + //$NON-NLS-1$ //$NON-NLS-0$
  '<div id="crawlingProgress"></div>' + //$NON-NLS-0$
  '<div id="favresults" style="max-height:400px; height:auto; overflow-y:auto;"></div>' + //$NON-NLS-0$
  '<div id="results" style="max-height:400px; height:auto; overflow-y:auto;" aria-live="off"></div>' + //$NON-NLS-0$
  '<div id="statusbar"></div>' + //$NON-NLS-0$
'</div>'; //$NON-NLS-0$
  • Dialog definition and setting up the basic (non-DOM) options. This is driven by the client API. Our convention is to call an internal _init function which reads the client options and sets up any necessary internal state. The last thing to do in this function is to call the Dialog._initialize function. The initialize sequence will look for special variables that drive the behavior of a dialog. For example, a title will cause a title string to appear in the dialog frame. An array of buttons will cause buttons to be created. In this example, we are just setting a title. The rest of the work in here pertains to our specific implementation until we call _initialize.
OpenResourceDialog.prototype._init = function(options) {
	// Set values for things that dialog cares about, such as title.  
	this.title = options.title || messages['Find File Named'];

	// Set internal values, validate the options, etc.
	this._searcher = options.searcher;
	this._onHide = options.onHide;
	this._contentTypeService = new mContentTypes.ContentTypeService(this._searcher.registry);
	if (!this._searcher) {
		throw new Error("Missing required argument: searcher"); //$NON-NLS-0$
	}	
	...

	// If the dialog template is not in the TEMPLATE variable by default, then read the template from a file and set into the variable now.

	// Start the dialog initialization.
	this._initialize();
};
  • Binding to the DOM elements. Hooking events and other behavior that is dependent on the existence of the DOM elements happens in the _bindToDOM function. This function is called by the dialog during the initialization process. When this function is called, you can use the following variables to access the DOM:
    • this.$frameParent refers to the parent node of the entire dialog. This is usually the document body, and typically does not need to be accessed by application dialog code.
    • this.$frame refers to the div element that frames the dialog. This typically does not need to be accessed by application dialogs.
    • this.$parent refers to the div element that parents the client template. Clients may want to refer to this parent when querying the dialog content for a particular node.
    • this.$buttonContainer refers to the div element containing any autogenerated buttons. This won't exist if no buttons were defined.
    • Your content field id's are bound to $ instance variables during the _initialize function. For example:
this.$fileName.addEventListener("input", function() { // do something }, false);

The variable $fileName refers to the DOM node whose id is "fileName". All nodes assigned an id in the template will be bound to a $ variable.

  • Modal behavior. If the dialog should have modal behavior, set a modal flag before initialization.
MyModalDialog.prototype._init = function(options) {
	// Set values for things that dialog cares about, such as title.  
	this.title = "My Modal Dialog";
	this.modal = true;
        ...
  • Showing the dialog. The dialog will not appear until the show() function is called. This function is implemented by the Dialog prototype. If your dialog needs to do some extra work during this time, the following optional functions may be implemented:
    • _beforeShowing is called just before the dialog is made visible. Here, dom node values may be populated, etc.
    • _afterShowing is called just after the dialog is made visible. This is a good place to set initial focus in the dialog.
  • Finishing the dialog. Most dialogs provide a button that the user pushes to indicate that the dialog is completed. The text for the button is specified, in addition to the callback to use when the button is pressed. In this example, an "OK" button is created, and it will call the application's done function.
MyModalDialog.prototype._init = function(options) {
	// Set values for things that dialog cares about, such as title.  
	this.title = "My Modal Dialog";
	this.modal = true;
        ...
	this.buttons = [{text: messages['OK'], callback: this.done.bind(this)}]; 
        this._initialize();
}
  • Hiding and cleaning up. The standard dialog frame provides a close icon that can be used to hide the dialog. The application dialog will also typically hide the dialog when it's finished. Either way, the hide() function is used to hide the dialog. To clean up any listeners or other resources allocated by the dialog, use the following functions:
    • _beforeHiding is called just before the dialog is hidden. Typically listeners are removed here.
    • _afterHiding is called just after the dialog is hidden for any final cleanup. The DOM nodes still exist during this call.
  • Destroying DOM nodes. As of this writing, the DOM nodes are destroyed after the "hiding" sequence. We assume clients recreate the dialog each time it is used. If this usage pattern changes, we could always add an option that determines whether the dialog is actually destroyed when hidden


Launching a dialog

As mentioned previously, the developer of an individual dialog determines the API, but using the conventions discussed above, a typical sequence is to create the dialog using a constructor, passing in some function that is called when the dialog is finished. Then, the client calls the show() function to show the dialog. Most of the nitty gritty work done by the caller is done in the function passed to the dialog on creation.

var dialog = new openResource.OpenResourceDialog({
	searcher: searcher, 
	searchRenderer:searcher.defaultRenderer, 
	favoriteService:favoriteService,
	onHide:  function() { 
		if (editor) {
			editor.getTextView().focus(); 
		}
	}
});
dialog.show();

Popup dialogs

Popup dialogs provide lightweight, tooltip-style dialogs, including automatic dismissal by clicking outside of the dialog.

Programming a popup

Launching a popup

Examples

Back to the top