You can use EGL or JavaScript™ to
create a new widget type.
Rich UI widgets
A
Rich UI widget is written
in EGL and is of type
RUIWidget (specifically, egl.ui.rui.RUIWidget).
You often need to do only as follows:
Here is the outline of an H3 definition, which requires
no
import statements:
Handler H3 type RUIWidget{tagName = "h3", onConstructionFunction = start,
@VEWidget{
category = "New Widgets",
template = "my.package.H3{ text=\"The Heading Text\" }",
smallIcon = "icons/h3small.gif",
largeIcon = "icons/h3large.gif" }}
text String { @EGLProperty { getMethod=getText, setMethod=setText },
@VEProperty{}};
function start()
class = "EglRuiH3";
end
function setText(textIn String in)
text = textIn;
this.innerText = textIn;
end
function getText() returns (String)
return (text);
end
end
Given this definition, you can create widgets
that are based on the type H3. For example, the following declaration
creates a box with a nested H3 widget:
ui Box { children = [
new H3 { text = "Summary" }
]};
@VEWidget
When
you write a Rich UI widget
(or an external-type widget—type egl.ui.rui.Widget—as described in
another topic), you can specify the complex property
@VEWidget.
The EGL editor uses the details of any @VEWidget property in the workspace,
adding entries to the palette when you refresh the palette. The property
has the following fields:
- category (type
STRING)
- In the palette, the category in which the widget is
listed. The
categories are listed in alphabetical order.
If the category does
not exist, a new category will be created with the name you specify.
The category is particularly useful to distinguish same-named widgets
such as Rich UI buttons and Dojo buttons.
- description (type STRING)
- In the palette, the description
that is displayed when the user
hovers over the widget entry.
- displayName (type
STRING).
- In the palette, the widget name. The names are listed
in alphabetical
order within a category.
The default value is the name of either
the external type or the handler of type RUIWidget.
- template (type STRING)
- The part of the
widget type declaration that follows the widget
name, excluding the semicolon. In the example, the declaration includes
a set-value block, as is necessary to avoid an error. Here is an example
declaration:
myH3 my.package.H3{ text="The Heading Text" };
If
you want the EGL system code to specify the widget type and to include
a qualifier (such as
my.package) only if necessary,
start the template string with the
typeName variable.
Here is an example:
template = "${typeName}{}"
Here is a related declaration, assuming that the
widget type shown earlier is in the same package as the handler that
receives the declaration:
myH3 H3{};
Here is another example:
template = "${typeName}{ text=\"The Heading Text\" }"
Here is the related declaration:
myH3 H3{ text="The Heading Text" };
- smallIcon (type STRING)
- The
path for the gif file that contains the small icon that is
displayable on the palette. The path is relative to the project directory.
For example, if the project is com.egl, the gif files listed earlier
are in com.egl/icons.
- largeIcon (type
STRING)
- The path for the gif file that contains the large
icon that is
displayable on the palette. The path is relative to the project directory.
For example, if the project is com.egl, the gif files listed earlier
are in com.egl/icons.
- container (type
@VEContainer)
- Specify the container field
as follows:
container{@VEContainer{}}
The
presence of
container has the following
implications:
- At run time, the widget can include other widgets.
- At development time, the EGL developer can drag-and-drop other
widgets into the widget being defined.
- The widget must include
a field named children.
The field named children must be of type
Widget[] ; and you must define the property @EGLProperty for
that field, as described later.
In
addition,
@VEWidget lets
you specify which RUIWidget properties and events (and external-type
properties and events) are to be displayed in the
Properties view.
For example, a displayed entry for
backgroundColor is
provided for any handler of type RUIWidget (or even for a widget provided
by an external type); but
backgroundColor might
not be appropriate for the widget you are defining. Here are the
@VEWidget property
fields that filter the properties and events that are otherwise displayed
by default:
- eventFilter (STRING[])
- An
array of event names (such as ["onClick", "OnScroll"])
to include or exclude from display, depending on the value of eventFilterType.
- eventFilterType (type INT)
- One
of the following values (either the integer or the related
constant):
- RUILib.EXCLUDE_ALL excludes all the events defined
for RUIWidget
(type egl.ui.rui.RUIWidget) and, in the case of external types, for
Widget (type egl.ui.rui.Widget). In this case, any values for eventFilter are
ignored.
- RUILib.EXCLUDE_ALL_EXCEPT excludes all the events
defined for
RUIWidget and Widget except those specified in the value of eventFilter.
- RUILib.INCLUDE_ALL includes all the events defined for RUIWidget
and Widget. In this case, values for eventFilter are
ignored.
- RUILib.INCLUDE_ALL_EXCEPT includes all the events
defined for
RUIWidget and Widget except those specified in the value of eventFilter.
- propertyFilter (STRING[])
- An array of property names (such as ["font", "fontSize"])
to include or exclude from display, depending on the value of propertyFilterType.
- propertyFilterType (type INT)
- One
of the following values (either the integer or the related
constant):
- RUILib.EXCLUDE_ALL excludes all the properties defined
for RUIWidget
(type egl.ui.rui.RUIWidget) and, in the case of external types, for
Widget (type egl.ui.rui.Widget). In this case, any values for propertyFilter are
ignored.
- RUILib.EXCLUDE_ALL_EXCEPT excludes all the properties
defined
for RUIWidget and Widget except those specified in the value of propertyFilter.
- RUILib.INCLUDE_ALL includes all the events defined for RUIWidget
and Widget. In this case, values for propertyFilter are
ignored.
- RUILib.INCLUDE_ALL_EXCEPT includes all the events
defined for
RUIWidget and Widget except those specified in the value of propertyFilter.
Here is an example of an external
type for
which the only displayed event types are
onScroll and
onChange and
for which the only displayed properties are
color and
backgroundColor:
ExternalType DojoButton extends DojoBase type JavaScriptObject {
relativePath = "dojo/widgets",
javaScriptName = "DojoButton",
includeFile = "dojo/widgets/dojobutton.html",
@VEWidget{
category = "Dojo",
template = "dojo.widgets.DojoButton { text = \"Button\" }",
displayName = "Button",
smallIcon = "icons/ctool16/dijit_button_pal16.gif",
largeIcon = "",
propertyFilterType = RUILib.EXCLUDE_ALL_EXCEPT,
propertyFilter = ["color", "backgroundColor"],
eventFilterType = RUILib.EXCLUDE_ALL_EXCEPT,
eventFilterType = ["onScroll", "onChange"]
}
Changes to @VEWidget are
available to the EGL editor only if you refresh the palette. You refresh
the palette by clicking the Refresh palette tool on the Design surface,
as noted in Using the tools on the Design surface.
@EGLProperty
@EGLProperty identifies
EGL functions that get and set the EGL field value when an EGL Rich
UI application uses the property. You can use this property without
specifying function names if the names of the functions are specified
with the word
get or
set followed by the variable name.
For example, if the variable is
UpperLimit and the
Rich UI Widget type includes functions named
getUpperLimit() and
setUpperLimit(),
you only need to add the complex property, as in this example:
UpperLimit INT { @EGLProperty{} };
The
property fields in
@EGLProperty are as follows:
- getMethod
- A string
(enclosed in quotation marks) containing the name of
the get method for the specified variable (do not include parentheses).
The method has no parameters, and its return value has the same type
as the field.
- setMethod
- A string (enclosed in quotation marks) containing the name of
the set method for the specified variable (do not include parentheses).
The method has one parameter that has the same type as the field.
By convention the setMethod does not have a return value, but no error
condition results if the method returns a value.
To
indicate that a field is read only or
write only, you can specify only one of the two property fields. If
the Rich UI application tries to read or write to a property for which
the read or write is not supported, an error occurs before the EGL
generator accesses the application code.
@VEProperty
When you write a Rich UI widget
(or an external-type widget, as described in another topic), you can
ensure that widget-specific properties are in the Properties view
whenever you use the EGL editor to create a widget of the new type.
You make the properties available by setting @VEProperty for
each widget field that you want to list in the Properties view. @VEProperty is
useful only when the @VEWidget and @EGLProperty properties
are set.
Here are example uses of
@VEProperty::
mySimpleProperty String {
@EGLProperty{},
@VEProperty{category = "Basic"}};
myChoiceProperty String{
@EGLProperty{},
@VEProperty{category = "Advanced",
propertyType = "choice",
choices = [
@VEPropertyChoice {displayName = "3D", id = "3"},
@VEPropertyChoice {displayName = "4D", id = "4"}
]}};
Not shown are the functions
that get and set the EGL properties.
The property fields in
@VEProperty are
as follows:
- category
- The category in which the property is listed in the Properties view.
If the category does not exist, a new category is created with the
name you specify. The category field takes a string.
The
categories in the Properties view are in
reverse order of their initial reference in the Rich UI widget or
external type. The last-specified category is listed first, and the
categories that are available for all widgets are displayed last.
Similarly, the properties in a given category are in reverse order
of declaration in the Rich UI widget or external type.
- propertyType
- The
type of value required in the property. By default, the type
is the type of the field in the widget definition. The only valid
value for propertyType is choice, which is used if you intend
to specify an array of choices, as shown in the previous example.
- choices
- An
array of @VEPropertyChoice elements,
each of which includes at least the first of the following two fields:
- displayName
- A string
that represents the choice in the Properties view.
This value is required.
- id
- A string that holds the content assigned to the property in the
Rich UI application. This value is required. The type of the assigned
value must be the same as the type of the property that is receiving
the value.
Changes to @VEProperty are
available to a file in the EGL editor only if you refresh the palette
and the file. To refresh the palette, click the Refresh palette tool
on the Design surface, as noted in Using the tools on the Design
surface. To refresh the file, click the Refresh Web page tool
on the Preview tab, as noted in Running a Web application in the
EGL editor.
@VEEvent
When
you write a Rich UI widget
that uses the targetWidget property (or when you write an external-type
widget, as described in another topic), you can declare event types
that are not otherwise defined. In this way, you can let the business
developer think more clearly about defining a sequence of tasks. Also,
the developer can assign an event handler at the Events view.
The
next example shows use of a customized button (MyButton), which uses
the property @VEEvent. If you try out the example in your workspace,
note that the EGL developer can now use the EGL editor for the following
purposes: to create a button of type MyButton and to assign event
handlers for the newly defined events (onPreClick and onPostClick).
Here
is a handler that accesses a button of type MyButton:
package pkg;
import com.ibm.egl.rui.widgets.Button;
handler MyHandler type RUIhandler {initialUI = [ someButton ]}
someButton MyButton{text = "fresh",
onPreClick ::= respondToPreClick,
onClick ::= respondToClick,
onPostClick ::= respondToPostClick};
function respondToPreClick(e Event in)
sysLib.writeStdout("in pre");
end
function respondToClick(e Event in)
sysLib.writeStdout("in click");
end
function respondToPostClick(e Event in)
sysLib.writeStdout("in post");
end
end
Here is the definition of MyButton:
package pkg;
import com.ibm.egl.rui.widgets.Button;
handler MyButton type RUIWidget {
targetWidget = internalButton,
@VEWidget{
category = "New EGL Widgets",
template = "pkg.myButton{ text=\"myButton\" }"}
}
text string {@EGLProperty{setMethod = setText,
getMethod = getText},
@VEProperty{}};
internalButton Button{onClick ::= respondToClick};
onPreClick EventHandler[] {@VEEvent{}};
onClick EventHandler[] {@VEEvent{}};
onPostClick EventHandler[] {@VEEvent{}};
private function setText(text String in)
internalButton.text = text;
end
private function getText() returns (String)
return ( internalButton.text );
end
private function respondToClick(e Event in)
preSize int = onPreClick.getSize();
clickSize int = onClick.getSize();
postSize int = onPostClick.getSize();
for (i int from 1 to preSize by 1)
OnPreClick[i](e);
end
for (i int from 1 to clickSize by 1)
OnClick[i](e);
end
for (i int from 1 to postSize by 1)
OnPostClick[i](e);
end
end
end
Changes to @VEEvent are
available to a file in the EGL editor only if you refresh the palette
and the file. To refresh the palette, click the Refresh palette tool
on the Design surface, as noted in Using the tools on the Design
surface. To refresh the file, click the Refresh Web page tool
on the Preview tab, as noted in Running a Web application in the
EGL editor.
@Override
Use
the
@Override property
if want to override a function that is available in any widget. For
example, the definition of the Box widget overrides the function
removeChild,
as shown here:
function removeChildren() {@Override}
// EGL statements are here
end
For a list of functions that are available in
all widgets, see Widget properties and functions.
External type widgets
You can create an
external type widget by writing custom JavaScript or
by accessing specialized JavaScript libraries.
To
create a new Rich UI widget based on JavaScript,
do as follows:
- Create a JavaScript file
to contain
the code for the widget. Invoke egl.defineWidget and specify the following
arguments:
- The package name of the EGL external type that
defines the widget;
for example, egl.rui.widgets)
- The name of the widget class
(for example, Button); that class
name is the name of the external type you will create
- The
package name of the EGL external type that defines the parent
widget; however, if that parent type is widget (the most elemental
choice), specify egl.ui.rui
- The name of the parent widget
class (for example, Label)
- The HTML element type (for example,
button)
Here is the example:
egl.defineWidget( 'egl.rui.widgets', 'Button',
'egl.rui.widgets', 'Label',
'button', { } );
- Within
the curly brackets ( { } ), define the JavaScript functions
to reflect the following outline, separating one function from the
next with a comma:
"functionName" : function(/*parameters*/)
{ //JavaScript Source }
Here is an example:
"getSelected" : function() {
return this.check.checked;
},
"setSelected" : function(value) {
this.check.checked = value;
},
"toString" : function() {
return "[CheckBox, text=\""+this.egl$$DOMElement.innerHTML+"\"]";
}
- Each widget can specify the following functions
for the JavaScript runtime to invoke:
- The function constructor is invoked
whenever a new widget instance is created, and that function can be
used, for example, to initialize data
- The function egl$$initializeDOMElement is
invoked whenever the HTML element is being created for the widget,
and that function can be used, for example, to set initial properties
on the element
- The function childrenChanged is
invoked
whenever the application developer updates the children property
of the new widget, if any.
Each widget also has a field
called this.egl$$DOMElement,
which represents the HTML element (or top-level HTML element) created
for the widget.
- In an EGL source file, create an EGL external
type that extends
from egl.ui.rui.Widget or from an existing widget. The External Type
needs a stereotype of JavaScriptObject,
as described in External type for JavaScript.