Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
RAP/Incubator/DropDown
The DropDown incubator project aims to provide a simple and efficient text input assist for RAP, also known as "type ahead", "auto suggest", "auto complete" or "field assist" in various frameworks. The current git master is only compatible to RAP master, but there is also a RAP 2.1 compatible branch that has the same features and API. P2 repositories for both versions can be found here.
Contents
The DropDown Widget
The org.eclipse.rap.addons.dropdown.DropDown
widget can be found in the org.eclipse.rap.addons.dropdown
bundle and is basically a free-floating List
(including setItems
and Selection
event support) that can be attached to a Text
widget or any other control. When made visible (DropDown.show()
), the DropDown will be placed below the widget. It will hide automatically if the parent (Text) looses focus, ESC is pressed or an item in the DropDown is clicked. While it is visible (and the parent is focused), the selection can be changed using the "Up" and "Down" keys.
This is the full extend of its functionality.
AutoSuggest
The org.eclipse.rap.addons.autosuggest.AutoSuggest
component aims to provide a complete solution for text input assistance. It wraps the DropDown widget and requires only the Text widget and a data source to work properly. It can be found in the org.eclipse.rap.addons.autosuggest
bundle, which has a dependency to the RAP/ClientScripting project if you use the RAP 2.1 version. (It has no special dependencies in RAP 2.2+ since these RAP versions already include ClientScripting.)
DataSource
A minimal setup of a AutoSuggest requires an instance of DataSource
, which in turn requires a DataProvider
.
Example:
Text text = new Text( parent, SWT.BORDER ); DataSource dataSource = new DataSource(); dataSource.setDataProvider( new ArrayDataProvider( "text1", "text2", "text3" ) ); AutoSuggest autoSuggest = new AutoSuggest( text ); autoSuggest.setDataSource( dataSource );
The AutoSuggest
will be disposed automatically with the Text
widget. Please be aware that DataSources are not disposed automatically and live on the client as long as the session does or until they are disposed maually. Equal DataSources should be re-used instead of re-created to not waste client memory or create unncecessary traffic.
Templates
Unless set up differently, the suggestions that are presented to the user are simple strings that are identical to the string that will be inserted when a suggestion is selected. To allow different forms of presentation a template can be set on the data source. Currently the only available template is ColumnTemplate
, which allows prestenting the suggestions as table with multiple columns. When using ColumnTemplate
a matching data provider needs to be implemented, ColumnDataProvider
. This provider allows defining a column text for each suggestion (getTexts
), as well as the text that is actually inserted (getValue
).
Example:
Text text = new Text( parent, SWT.BORDER ); DataSource dataSource = new DataSource(); dataSource.setTemplate( new ColumnTemplate( 50, 150, 150 ) ); // the column widths ColumnDataProvider dataProvider = new ColumnDataProvider() { public Iterable<?> getSuggestions() { return Arrays.asList( someArray ); // for example an array of string arrays (String[][]) } public String getValue( Object element ) { String[] value = ( String[] )element; return value[ 0 ]; } public String[] getTexts( Object element ) { String[] value = ( String[] )element; return new String[] { value[ 0 ], value[ 2 ], value[ 3 ] }; } } ); dataSource.setDataProvider( dataProvider ); AutoSuggest autoSuggest = new AutoSuggest( text ); autoSuggest.setDataSource( dataSource );
Adanced Customization
The AutoSuggest class can be extended to modify it's behavior and/or add new features/API. This is not 100% future-proof as some of the JavaScript API that is used is considered internal, but there are currently no fundamental changes planned for Autosuggest/DropDown. (This may change, especially if these Components are migrated from the Incubator to RAP core.)
Attaching a Custom a JavaScript File
To make any signficant changes to AutoSuggest it is necessary to load your own JavaScript implementation of the AutoSuggest logic. To do so, extend the AutoSuggest class like this:
public class CustomAutoSuggest extends AutoSuggest { public CustomAutoSuggest( Text text ) { super( text ); } @Override protected ClientListener getAutoSuggestListener() { return CustomAutoSuggestClientListener.getInstance(); } }
Copy the files ResourceLoaderUtil.java
and AutoSuggest.js
from the org.eclipse.rap.addons.autosuggest
source bundle to an internal package that is accessible by CustomAutoSuggest. Rename AutoSuggest.js
to CustomAutoSuggest.js
. Then add the implementation for CustomAutoSuggestClientListener
to the same package:
public class CustomAutoSuggestClientListener extends ClientListener { public static CustomAutoSuggestClientListener getInstance() { return SingletonUtil.getSessionInstance( CustomAutoSuggestClientListener.class ); } private CustomAutoSuggestClientListener() { super( getText() ); } private static String getText() { String path = "path/to/your/CustomAutoSuggest.js"; return ResourceLoaderUtil.readTextContent( path ); } }
Now you should be able to use CustomAutoSuggest like the normal AutoSuggest class.
Understanding and Customizing AutoSuggest.js
The AutoSuggest instance is represented on the client by a simple model object (API is below), however this is not what AutoSuggest.js is. AutoSuggest.js contains the client logic that manages the interaction between DropDown, Text and the data model. It's handleEvent function gets all important events from the client representations of DropDown, Text and Autosuggest(model) and delegates them. First, all important properties of Text and DropDown are synchronized with the model in the "sync"/"forward" functions. Usually you don't have to touch those. The logic itself is implemented within the functions starting with "on", which are called whenever a significant event (usually a value change) occurs on the model. They all have one parameter (the event object) and have the model object as their context ("this").
The model is a simple container of key/value pairs that fires a change event whenever a value is modified. The implementation can be found in Model.js in the AutoSuggest bundle. The API consists of the following methods:
set( property, value [, options ] ) | options may be any object and is attached to the change event |
get( property ) | returns the value for this property, or undefined is none is set |
notify( eventType [, eventProperties ] ) | eventType may be any string. eventProperties may be any object given to the listeners as the first (and only) argument |
The following properties are used on the AutoSuggest model:
property | type | set by | description |
---|---|---|---|
autoComplete | boolean | server | enables autocomplete behavior |
dataSourceId | string | server | id of yet another model that contains the suggestions (see DataSource.java) |
autoSuggestListenerId | string | server | id of the handleEvent function of AutoSuggest.js |
textWidgetId | string | server | id of the text widget |
dropDownWidgetId | string | server | id of the dropDown widget |
text | string | client | text currently set on the text widget |
userText | string | client | text last entered by the user |
suggestionsVisible | boolean | client | visibility of the dropDown widget |
suggestions | array of any type (e.g. string) | client (server via DataSource) | all available suggestions provided by DataSource |
filter | function | client (server via DataSource) | function that returns boolean for call "filter( suggestion, userText );" |
template | function | client (server via DataSource, not implemented yet) | function that returns string to be displayed by dropDown for a given suggestion |
currentSuggestions | array of any type (e.g. string) | client | suggestions matching current userText |
currentSuggestionTexts | array of string | client | currentSuggestions as displayed by dropDown |
selectedSuggestionIndex | number | client | index of the user selected suggestion in the currentSuggestions array |
replacementText | string | client | text suggested to be entered into text widget |
textSelection | array of number ( [ start, length ] ) | client | text to be marked as selected (inserted) - synced only from model->text, not back |
In case the ColumnDataProvider is used on the server side, a suggestion will be an array of strings (with the first used as the replacementText and the rest as the columns in dropDown), otherwise it's just a string.
The following events are used on the AutoSuggest model:
type | fired by | description |
---|---|---|
change | set call (server or client) | event object described below |
accept | client | user wants to accept a suggestion (equals defaultSelection on dropDown caused by click or enter) |
suggestionSelected | client | successfully accepted an suggestion (this is what the server listens to) |
A change event object fired by a "set" call on the model has the following fields:
value | the new value |
type | usually "change" |
property | name of the property that changed |
options | the options object given as the third parameter on the "set" call, see below |
source | the object that fired the event, i.e. the model |
When a property changes, an options object is given in the change event, which currently may have one property "action" that indicates what caused the change.
action | properties | description |
---|---|---|
sync | text, suggestionsVisible, selectedSuggestionIndex, replacementText | value synchronized from widget to model (except replacementText) |
typing | userText, currentSuggestions | changed due to user typing text |
deleting | userText, currentSuggestions | changed due to user deleting text |
refresh | currentSuggestions | changed due to changed DataSource |
selection | replacementText | changed due to changed selectedSuggestionIndex (user selects suggestion) |
(replacementText giving an action "sync" is not quite semantically correct as it's more an internal reset, may be changed.)
Adding new properties to AutoSuggest
(RAP 2.2+ version only.) To enable the application developer to customize the AutoSuggest him/herself, it is possible to add public setter. Such a setter has to call set on the remoteObject to forward the property to the client-side AutoSuggest model:
public void setEagerAutoComplete( boolean value ) { remoteObject.set( "eagerAutoComplete", value ); }
On the model, this property is now available without any further changes:
if( this.get( "eagerAutoComplete" ) ) {
Note that the default value of a property that has not been set on the model is undefined
. However, since undefined
is falsy in JavaScript it can be used like a boolean that is false.
Accessing Text and DropDown client widgets
Here are some further information, in case you need to use properties or events that are not yet forwarded to the model, or need to access the widgets directly for some reason.
The client Text widget API is documented here: http://download.eclipse.org/rt/rap/doc/2.2/guide/reference/jsdoc/symbols/Text.html
The client DropDown widget API consists of the following methods:
setItems( items ) | expects an array of string. When columns are used, the cells are separated by tabs. |
getItemCount() | returns number |
setSelectionIndex( index ) | expects an number between 0 and items.length - 1 |
getSelectionIndex() | returns number |
setVisible( value ) | expects boolean |
getVisible() | returns boolean |
show() | same as setVisible( true ) |
hide() | same as setVisible( true ) |
setData( key, value ) | attach any value to the widget |
getData( key ) | returns data attached in a script or by the server |
DropDown and Text fire events according to http://download.eclipse.org/rt/rap/doc/2.2/guide/reference/jsdoc/symbols/Event.html
Currently, the following events are forwarded from DropDown to the AutoSuggest.js handleEvent function:
SWT.Show, SWT.Hide, SWT.Selection, SWT.DefaultSelection
These are all events available on DropDown.
By default, the following events are forwarded from Text to the AutoSuggest.js handleEvent function:
SWT.Modify, SWT.Verify
It is possible (RAP 2.2+ version only) to add more events to that list by overwriting getTextEventTypes in AutoSuggest.java:
@Override protected int[] getTextEventTypes() { return new int[]{ SWT.Modify, SWT.Verify, SWT.MouseDown }; }
Unit Tests
There is a jasmine test suite in the AutoSuggest test bundle. It can be used with the modified AutoSuggest.js to prevent breaking existing functionality. However, you will have to adjust most paths in the index.html to point to your location of the
org.eclipse.rap.jstestrunner
, org.eclipse.rap.addons.autosuggest
and org.eclipse.rap.rwt
bundles
The first argument of "TestUtil.loadResource( "AutoSuggest.js", listenerPrefix + "AutoSuggest.js" );" needs to remain unchanged, while the second is the relative path to your CustomAutoSuggest.js.
The index.html has to be loaded from an http server.