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/ClientScripting
Note: Since RAP 2.2M1 ClientScripting is included in the RAP core (org.eclipse.rap.rwt bundle). The ClientScripting incubator projects are no longer compatible with RAP 2.2M1+ and must be used only with older RAP versions.
Contents
Overview
Conventional RAP applications are running almost entirely on a Server, with a thin client only rendering a user interface with some limited interactivity. This has several advantages, but it also means all application-relevant events have to be forwarded to the Server before being processed, causing small delays and traffic. Scenarios where interactions occur with a high frequency, like typing or mouse movements, would therefore be undesirable.
This is where RAP ClientScripting can help. ClientScripting allows developers to handle some of the events directly on the client, without creating any http-requests. This is ideal to customize or enhance the behavior of specific widgets, making it much less often necessary to develop RAP custom-widgets.
The scripts themselves are written in JavaScript on a SWT-like API. This allows application developers with SWT-experience to get started right away, and makes porting between SWT and RAP-ClientScripting fairly easy. Even without any JavaScript-experience, this document should provide you with all the basics you need for ClientScripting.
The ClientScripting feature is currently in early development, aiming to enable only some specific use cases. However, all API published here should be stable and is unlikely to change in the future. The project is currently hosted on GitHub available in the RAP incubator. The projects "master" branch is always compatible with the current RAP "master" branch/ nightly build. For RAP releases and milstones, check out the commit with the tag/branch best matching to the version you are using (procided since RAP 2.0M4). We also have a Nightly builds p2 repository (http://download.eclipse.org/rt/rap/incubator/nightly/clientscripting/) and a RAP 2.0 compatible p2 repository (http://download.eclipse.org/rt/rap/incubator/2.0/clientscripting/)
Questions, suggestions and bug reports are welcome!
Java API
Client event processing works like untyped event handling in SWT, with the main difference that the handler itself has to be written in JavaScript, and is added to the widget using a method on the listener itself. It also does (naturally) not have access to all of the resources and functionality that would be available on the server.
The ClientListener Class
Instances of this class represent a JavaScript function that can be attached to any widget for any supported event. It's similar in concept to org.eclipse.swt.widgets.Listener
, but can only be executed on the client.
Constructor Summary | |
---|---|
ClientListener( String scriptCode ) Creates an instance of ClientListener using the given String as JavaScript source code.
|
Example:
widget.addListener( SWT.Verify, new ClientListener( javascript) );
The JavaScript source code can define any number of named function, either with "var myFunction = function(){};
or "function myFunction(){};
". One of the functions has to be named "handleEvent" and take one argument (the event). Example: "var handleEvent = function( event ){ ... };
". The other functions can be called from handleEvent
to be used as helper functions. The order in which the functions are defined is not relevant.
If your script is longer than a few lines, we recommend to read it from an external file. The clientscripting demo provides a util class to help with that.
For the documentation of the "event" object, see the JavaScript chapter below. Note that the function is executed without any context ("this"), meaning that unlike the SWT handleEvent
method, it is not a member of an object.
Supported Event Types
Event Type | Notes |
---|---|
KeyDown
|
Fired once when pressing a key, then repeatedly while holding it down. The doit flag can be used to prevent the character from beeing inserted.
|
KeyUp
|
Fired when releasing a key. |
MouseDown
|
Fired when pressing a mouse button. |
MouseUp
|
Fired when releasing a mouse button. |
MouseMove
|
Fired when moving the mouse within the widget. This type is not supported in server-side RAP, only clientscripting. |
MouseEnter
|
Fired when moving the mouse over the widget. This type is not supported in server-side RAP, only clientscripting. |
MouseExit
|
Fired when moving the mouse out of the widget. This type is not supported in server-side RAP, only clientscripting. |
MouseDoubleClick
|
Fired when clicking twice. |
FocusIn
|
Fired when widget is focused. |
FocusOut
|
Fired when widget is blured. |
Paint
|
Fired when widget appears, is changing size, or when "redraw" is called on the widget either in java, or in clientscripting. Only supported on Canvas .
|
Selection
|
Fired on List widgets when selection changes. Other widgets are currently not supported. |
DefaultSelection
|
Fired on List widgets when an item is double-clicked. (As in SWT and server-side RAP.) Other widgets are currently not supported. |
Modify
|
Fired then the value of the "text" property of a Text widget changes. Not supported on other widgets.
|
Verify
|
Fired then the value of the "text" property of a Text widget is changed by the user. Not supported on other widgets. The doit flag can be used to prevent the change. The "text" field of the event may be changed to replace the inserted text.
|
JavaScript API
The Event Object
This object is given as the first argument when calling a client event listener function. Its API is designed after org.eclipse.swt.widgets.Event
.
Field Summary | |
---|---|
number
|
type the type of event, as defined by the event type constants in object SWT
|
Widget
|
widget an object representing the widget that issued the event. |
boolean
|
doit depending on the event, a flag indicating whether the operation should be allowed. Setting this field to false will cancel the operation. Currently supported only for key and mouse events on Text and Text -like widgets.
|
number
|
keyCode depending on the event, the key code of the key that was typed, as defined by the key code constants in object SWT . When the character field of the event is ambiguous, this field contains the unaffected value of the original character. For example, typing Shift+M or M results in different characters ( 'M' and 'm' ), but the same keyCode (109, character code for 'm').
|
string
|
character depending on the event, the character represented by the key that was typed. This is the final character that results after all modifiers have been applied. For non-printable keys (like arrow-keys) this field is not set. Changing its value has no effect. |
number
|
stateMask depending on the event, the state of the keyboard modifier keys and mouse masks at the time the event was generated. |
number
|
button the button that was pressed or released; 1 for the first button, 2 for the second button, and 3 for the third button, etc. |
number
|
x x coordinate of the pointer at the time of the event |
number
|
y y coordinate of the pointer at the time of the event |
string
|
text depending on the event, the new text that will be inserted. Setting this field will change the text that is about to be inserted or deleted. |
number
|
start depending on the event, the range of text being modified. Setting these fields has no effect. |
number
|
end depending on the event, the range of text being modified. Setting these fields has no effect. |
object
|
gc the graphics context to use when painting |
The fields "keyCode" and "character" are set on key and verify events. "stateMask" is set for key and mouse events. "x", "y" and "button" are set for mouse events. "text", "start" and "end" are set for verify events. "gc" is set only on paint events. The "doit" flag is supported on key and verify events.
GC
The client-side GC does not feature the API of the SWT GC. Instead it supports a subset of the HTML5 Canvas API (http://www.w3.org/TR/2dcontext/):
- Fields:
- strokeStyle
- fillStyle
- lineWidth
- lineJoin
- lineCap
- miterLimit
- globalAlpha
- Methods:
- save
- restore
- beginPath
- closePath
- clearRect (Limitation: in IE 7+8 arguments are ignored, the entire canvas is cleared)
- stroke
- fill
- moveTo
- lineTo
- quadraticCurveTo
- bezierCurveTo
- rect
- arc (Limitation: in IE 7+8 not available in RAP 1.5, only RAP 2.x)
- drawImage
- createLinearGradient (Limitations: In IE 7+8, the gradient can be only be drawn either vertically or horizontally. Calls to "addColorStop" must be in the order of the offsets and can not overwrite previous colorsStops)
- In IE7+8, these are all supported methods. More may be supported on other browser, since the the native HTML5 canvas is used.
- HTML5 canvas does not support drawing ellipses. A possible workaround can be found here.
It is not a good idea to attach a server-side AND a client-side paint listener. Both will be triggered.
The SWT Object
The SWT object contains a number of public contants. It is available as a local variable within the scope of any ClientScripting function. Its API is designed after org.eclipse.swt.SWT
, but the values for the constants may be different. To get an overview of all available constants and their purpose, view the file "js/org/eclipse/rap/clientscripting/SWT.js" from the ClientScripting bundle.
The Widget Object
The Widget object in RAP ClientScripting is an abstract representation of an SWT widget. It has a subset of the API of the actual SWT Widget it represents. In some cases the API may slightly differ.
Setter
All widgets have setter functions for all properties defined in the RAP-Protocol. All setter take exactly one argument. For a case of overloaded setter in SWT, they are usually taking the most complex/complete type of argument. For example, Text
has "setSelection( int start )
", "setSelection( Point selection )
" and "setSelection( int start, int end )
". The setter "setSelection( Point selection )
" is one with the complete data and takes only one argument. Since Point
is represented in ClientScripting as an Array (see Data Types below), the setter is "setSelection( [ start, end ] )
".
For now a list of all the properties is available in the README.md in the ClientScripting bundle. Please be aware that as of now, changing a widgets property with these setter will in most cases only affect it's client side representation. Only properties that can also be changed by a user's interaction with the UI (like selection) will also be updated on the java widget instance. This will be improved in later versions to fully synchronize all properties.
Getter
Currently only some getters are available. A list of all properties that have getters is available in the README.md in the ClientScripting bundle. Note that the getter might return null, but never undefined.
setData, getData and WidgetDataWhiteList
The Widget provides object a setData
and a getData
function. Similar to SWT, these allow to attach data to a widget instance without affecting the widget itself. Unlike SWT any value can be stored with setData, not just objects. By default, the data storage on the client is not synchronized with the data storage on the actual SWT Widget.
Function Summary | |
---|---|
undefined
|
setData( string key, value value ) stores the given value. The key is mandatory. |
value
|
getData( string key ) gets a stored value. The key is mandatory. |
Data attached to the SWT Widget can be transfarred to the ClientScripting widget. To do so, the key for that data has to be added to the WidgetDataWhiteList, like so:
WidetDataWhiteList.addKey( "foo" ); widget.setData( "foo", "myData" );
The key has only to be added once per session, but adding it multiple times has no side effects. The following types are supported:
null |
String |
Byte |
Short |
Integer |
Long |
Double |
Float |
Boolean |
int[] |
boolean[] |
String[] |
Object[] |
Map |
JsonValue |
Changing the value on the client does not change it on the server.
Widgets can not be transferred, but the id can:
Java:
widget.setData( "otherWidget", WidgetUtil.getId( otherWidget ) );
JavaScript:
var otherWidget = rap.getObject( widget.getData( "otherWidget" ) );
ClientScripting enhances the rap#getObject
method so that the returned wrapper is ClientScripting compatible. (It is the same representation as used in event.wigdet.)
Methods on Controls
Controls provide some additional methods:
Function Summary | |
---|---|
boolean
|
forceFocus() forces the control to get keyboard focus, even if it can not be focused by the user (by mouse mouse/keyboard). Returns true if the control got focus, and false if it was unable to.
|
undefined
|
redraw() fires a Paint event. Only useful with Canvas .
|
Data Types
The type and format of the values that can be set/get on the widget objects is a javascript-specific approximation of its SWT counterpart. They are identical to those used in the RAP Protocol.
For simple data types/values the mapping is as follows:
SWT | ClientScripting |
---|---|
void | undefined |
null | null |
boolean | boolean |
int | number, but treated like int |
float | number |
String | string |
char | string with length of 1 |
For complex types see http://wiki.eclipse.org/RAP/Protocol#Common_Data_Types.
Known Limitations
This is a list of limitations on existing features with the current ClientScripting implementation. Limitations are not bugs, those are tracked in bugzilla only. If a bugzilla entry for a listed issue exists, it should be linked, but not all limitations are possible/planned to be fixed in the future.
- As mentioned above, there are only some getter available on the widget object. New ones will added as needed.
- Also mentioned above, many property changes (such as background color) are currently not synchronized with the server.
- The 'streams/1.5' and 'streams/2.0' branches of ClientScripting work with RAP 1.5/2.0, the master is always in sync with the RAP master.
- The doit flag is currently only supported on the Text Widget for Key and Verify events.
- It is not (and will not be) possible to prevent Text Widget selection/carret change by mouse (using doit flag). Its also not supported to set the Text selection property in a MouseDown event. These are also not working (correctly) in SWT. Changing selection on Text on a MouseUp works.
- Verify event:
- Currently only supported on Text.
- Setting the text or selection property of the target within the Verify event is not supported, but it doesn't produce useful results in SWT either. The modiy event is better suited for this.
- Changing the events "text" field has no effect if its empty to begin with. (I.e. deleting can not be used to insert text).
- In SWT, some key constants can be compared with both the keyCode field and the character field (
SWT.DEL, SWT.ESC, SWT.BS, SWT.BS, SWT.CR, SWT.TAB
). In ClientScripting they can only be compared with the keyCode field. The character field will either not be set for these keys, or contain a (javascript) string, while these constants are numbers.
Get a list of open bugs and enhancement requests in our bugzilla. Report bugs or enhancement requests on bugzilla with a "[ClientScripting]" prefix on the summary.
General Restrictions and Discouraged Usage
For the RAP default client, ClientScripting runs in the same environment as the client itself. For reasons of stability, compatibility and security you should not:
- Try to access any internal RAP client API.
- Manipulate any of the ClientScripting objects in an undocumented manner.
- Access any DOM (HTML) elements.
- Manipulate any of JavaScript's own prototypes/constructors (Object, Function, etc.).
- Set a widget's property to any invalid/unsupported values.
Violating any of the above guidelines might create unpredictable results, even if the application seems to run fine at first.
Accessing the window/document Objects is discouraged for cross-browser/cross-client compaibility concerns. You can do so at your own risk.
Creating global variables is also heavily discouraged, and can easily happen by accident if a variable is created without the "var" keyword.
For security reasons you should be aware that, unlike RAP sourcecode written in Java, all ClientScripting functions (JavaScript sourcecode) are currently transferred to the client completely unaltered (including comments), and can be read by any user with enough technical expertice.
JavaScript Hints for Java Developer
Developers experienced with Java programming and less familiar with (or completely new to) JavaScript might find the following hints useful in regard to ClientScripting:
Noteable differences between Java and JavaScript
- JavaScript variables are dynamically typed and have function scope
All local variables in JavaScript are delcared with "var" and can contain any type (undefined, null, number, boolean, string, object). It is not relevant at all where in the function it is declared, its scope is always the entire function.
- Strings are not objects
Strings are primitives in JavaScript, and are compared with "==
" (or "===
"), not ".equals
". However, string primitives can be coerced into a string object, on which several useful methods are available.
- A number is not always a number
When calculating a numeric value in JavaScript, the result might not always be a number, even if it is of the type number. The two cases are infinity
(e.g. "10/0 == infinity
") and NaN
(not a number, e.g. "Math.sqrt( -1 )
"). NaN
can be detected only by using isNaN
(e.g. "isNaN( Math.sqrt( -1 ) ) == true
"). If a number is neither NaN
nor infinity
, it can do most things Javas int
or double
can, including bitwise operations.
- Arrays have dynamic length
Even though their syntax is very similar, JavaScript Arrays behave more like Java Lists than Java Arrays. They can store different types in different slots, and can change their length as needed. They also have differently named, but similarly working methods.
Noteable similarities between Java and JavaScript
- Objects and Maps
JavaScript Objects (created with a literal "{}
") can be used like Java Maps. A "map.put( "key", value )
" would be "map[ key ] = value
", and a " map.get( "key" )
" would be "map[ "key" ]
". In JavaScript, value
could be of any type.
- System.out.println and console.log
Most browser (but not all!) have some form of javascript console. They all have at least one function in common that can be used like System.out.println
, which is console.log
. Some browser also have console.trace
. Browser not supporting console.log
(or in case of InternetExplorer, not having it activated), will crash when calling that method, so remember removing all occurrences of console from your JavaScript code after debugging.
- Math and Math
The Java Math
class and the JavaScript Math
object have almost identical API.
- Date and Date
The JavaScript constructor Date
creates objects almost identical in API to instances of Javas Date
class.
- Regular Expressions and RegExp
JavaScript also supports regular expressions.
- char and string
JavaScript has no char
type. For ClientScripting, a string with a length of one character is used instead. This allows for comparison like "event.character == "A"
", but not "event.character >= 65
". To do that use charCodeAt
. Example: "event.character.charCodeAt( 0 ) >= 65
".