Document revision: 2024-10-28
Refers to WEBDLG2 version: B0840 2409-1
Table of contents
Overview
The plugin interface allows to extend WEBDLG2 with customized user interface
controls. A plugin consists of JavaScript code (functionality) and optional
CSS rules (visual appearance).
Plugins need to be registered by name. A plugin name must
follow a defined naming scheme:
- The name must start with an upper case letter (A-Z).
- The remaining part of the name must consist only of lower case letters
(a-z) or digits (0-9) or the underscore character (_).
Plugin DLG objects are then instantiated with DLG NEW using the
"plugin." DLG class name prefix, for example:
DLG NEW "main.bigone","plugin.Snowball"
This instantiates the "main.bigone" DLG object of the "Snowball" plugin class.
When registered, the plugin class implementation is
installed in the web browser main thread, and an associated proxy DLG
class is created in the application's eloqwebd2 session.
The proxy class is used to handle DLG GET and
DLG SET requests from the application and to synchronize
attribute values from/to the plugin DLG objects
instantiated in the web browser.
As a reference, we recommend the plugin
examples which demonstrate working implementations of various WEBDLG2
plugin use cases along with documented source code.
Plugin registration
The eq.plugin() JavaScript API is used to register a plugin.
It takes two arguments, both are required. The first argument is the
plugin name as described above. The second
argument is the plugin class descriptor which is an object providing
the plugin properties and its implementation.
For example:
eq.plugin("Snowball", {
// Attribute descriptor.
atr : [
[ "weight", eq.atrGET|eq.atrSET|eq.atrSTR|eq.atrPRI ],
[ "diameter", eq.atrGET|eq.atrSET|eq.atrSTR|eq.atrPRI ]
],
// Class properties.
prp : {
minVersion : 3,
classList : 'snowball',
changeEvent : 'input',
actionEvent : 'click',
border : true
},
// API: Constructor.
apiInit : function(dlg, el) {
// this - plugin instance
// dlg - Dlg dialog instance
// el - plugin object DIV container element
// Set up the instance members variables.
this.weight = 0.0;
this.diameter = 0.0;
// Set up the DOM elements …
},
// API: Set attribute value.
apiSetAttr : function(dlg, id, el, atr, idx, val) {
// this - plugin instance
// dlg - Dlg dialog instance
// id - plugin object DOM identifier
// el - plugin object DIV container element
// atr - attribute name
// idx - attribute index string or null
// val - value, val.i (integer) or val.s (string)
switch (atr) {
case 'weight':
this.weight = parseFloat(val.s);
break;
case 'diameter':
this.diameter = parseFloat(val.s);
break;
}
},
// API: Change event occurred.
apiOnChange : function(dlg, id, el, e) {
// this - plugin instance
// dlg - Dlg dialog instance
// id - plugin object DOM identifier
// el - plugin object DIV container element
// e - Event object
// Handle the 'input' changeEvent ...
},
// Static methods.
// ---------------
static : {
// Static API: Class installation.
install : function() {
// this - plugin class
console.log(this.name + " plugin installed.");
}
}
});
This is an incomplete example of a "Snowball" plugin class providing the
GET/SET string attributes "weight" and "diameter".
The apiSetAttr() method is invoked as
necessary to synchronize the attribute values as set
by the application.
When instantiated, a DIV container
DOM element is created, attributed with the "snowball"
class name and a border, then the
apiInit() constructor method is invoked
to allow setting up the plugin object as well as the
DOM element.
The input DOM event is recognized as
change event, as such it causes invocation of
the apiOnChange() method provided in the
implementation. The
click DOM event is recognized as
action event, as such it may cause a rule
submission.
The install() method is invoked when
the plugin has been installed. This is a static method, i.e., it does not
operate on an instance but on the class. The static object allows
to define static methods and/or class variables.
The class is defined in the eq.c namespace with a "plg" prefix in
the web browser main thread. For example:
- "Snowball" plugin class
- defined as: eq.c.plgSnowball
super class: eq.c.DlgPlugin
base class: eq.c.DlgElement
- static install() method
- defined as: eq.c.plgSnowball.install()
- apiInit() instance method
- defined as: eq.c.plgSnowball.prototype.apiInit()
A plugin registration as shown above is typically contained in a text file
having the plugin name plus the .js extension, for example
Snowball.js. If necessary, the associated CSS rules to define the
visual appearance are typically contained in an accompanying .css
file, for example Snowball.css.
To use the plugin, configure an URI in
the eloqwebd2.uri file for the
directory containing the plugin files, for example:
[/plugin]
Path = /directory/in/web/server/document/hierarchy
This configuration associates the /plugin URI with the plugin
directory in the file system. Now the
application can be configured to
load the plugin by setting
PluginURL
as shown below:
PluginURL = /plugin/Snowball.js
PluginURL = /plugin/Snowball.css
Alternatively, the plugin files may be integrated into the
HTML documents. This is necessary
when using an external web server.
For example:
<script async
src="/path/to/Snowball.js">
</script>
<link href="/path/to/Snowball.css"
rel="stylesheet" type="text/css">
As shown here, using the <script async> attribute is recommended
to avoid that the script potentially delays loading the document
(1).
Attribute descriptor
The plugin class descriptor is expected to define
the atr property providing the attribute descriptor,
for example:
atr : [
[ "weight", eq.atrGET|eq.atrSET|eq.atrSTR|eq.atrPRI ],
[ "diameter", eq.atrGET|eq.atrSET|eq.atrSTR|eq.atrPRI ]
]
The attribute descriptor is an array of one or more attribute items.
Each attribute item defines one plugin attribute as an array of two items.
The first item specifies the attribute name. The second item consists of a
combination of attribute flags which control how the
eloqwebd2 proxy class handles the
associated attribute values.
Flags affecting the access method:
- eq.atrGET
- attribute supports DLG GET
- eq.atrSET
- attribute supports DLG SET
- eq.atrGET | eq.atrSET
- attribute supports both DLG GET and DLG SET
Flags affecting the data type:
- eq.atrINT
- data type is integer
- eq.atrINT | eq.atrIDX
- data type is integer, may be indexed
- eq.atrSTR
- data type is string
- eq.atrSTR | eq.atrIDX
- data type is string, may be indexed
- eq.atrINT | eq.atrSTR
- data type is either integer or string
- eq.atrINT | eq.atrSTR | eq.atrIDX
- data type is either integer or string, may be indexed
Flags affecting the behavior:
- eq.atrPRI
- attribute has priority
- eq.atrNOC
- attribute values are not cached
- eq.atrLST
- attribute values are stored as list
- eq.atrSYN
- attribute values are synchronized immediately
Indexed attributes
The eq.atrIDX flag specifies that attribute values
may be indexed, i.e., the attribute name may have
an optional […] suffix.
The apiSetAttr() and
apiGetAttr() methods take an idx
argument which is an index string (the suffix string between the first
[ and the last ]), or null if the value is not
indexed. For example:
// API: Set attribute value.
apiSetAttr : function(dlg, id, el, atr, idx, val) {
var ix = idx ? idx.split('][') : null;
…
Here, the resulting ix is an array of index dimensions, or
null if the value is not indexed. This way, line[1]
as well as cell[2][3] are recognized.
The eq.atrPRI behavior flag
The default behavior is that DLG SET causes
attribute values to be cached in the
eloqwebd2 proxy object, and
DLG GET returns these cached values to the application, or zero
or an empty string, respectively, in case a value has not been set.
DLG DO and DLG DRAW synchronize the cached values
with the plugin DLG object in the web browser by invoking the
apiSetAttr() method.
Please note: Attribute values are synchronized only
once unless they are modified via DLG SET.
If none of the behavior flags are set, the cached values are
synchronized in the order they were set by the application.
If the eq.atrPRI flag is set, attribute values are
prioritized on synchronization, i.e., they are synchronized
in the order they are specified in the atr
attribute descriptor before any other attribute
value not having the eq.atrPRI flag set.
For example, consider the atr attribute descriptor
of the Editgrid plugin example:
atr : [
[ 'columns', eq.atrGET|eq.atrSET |eq.atrINT|eq.atrPRI ],
[ 'delim', eq.atrGET|eq.atrSET |eq.atrSTR|eq.atrPRI ],
[ 'activecolumn', eq.atrGET|eq.atrSET |eq.atrINT ],
[ 'activeline', eq.atrGET|eq.atrSET |eq.atrINT ],
[ 'cx', eq.atrGET|eq.atrSET |eq.atrINT ],
[ 'cy', eq.atrGET|eq.atrSET |eq.atrINT ],
[ 'colreadonly', eq.atrGET|eq.atrSET|eq.atrIDX|eq.atrINT ],
[ 'colwidth', eq.atrGET|eq.atrSET|eq.atrIDX|eq.atrINT ],
[ 'header', eq.atrGET|eq.atrSET|eq.atrIDX|eq.atrSTR ],
[ 'add', eq.atrSET|eq.atrLST|eq.atrSTR|eq.atrNOC ],
[ 'cell', eq.atrGET|eq.atrSET|eq.atrIDX|eq.atrSTR|eq.atrNOC ],
[ 'clear', eq.atrSET |eq.atrINT
|eq.atrSTR|eq.atrNOC ],
[ 'content', eq.atrGET|eq.atrSET |eq.atrSTR|eq.atrNOC ],
[ 'del', eq.atrSET|eq.atrIDX|eq.atrINT|eq.atrNOC ],
[ 'insert', eq.atrSET|eq.atrIDX|eq.atrSTR|eq.atrNOC ],
[ 'line', eq.atrGET|eq.atrSET|eq.atrIDX|eq.atrSTR|eq.atrNOC ]
]
Regardless in which order the attribute values were set by
the application, synchronization affects first the "columns" value and then the
"delim" value before any other value is synchronized.
The Editgrid plugin example uses
this to ensure that the number of columns and the column delimiter are known
before any content or headers are synchronized.
The other attribute values need to be synchronized in the
order they were set by the application because they may depend on each other.
A typical example would be that first the old content is cleared, then the new
content is set, and finally the active line and column are specified.
The eq.atrNOC behavior flag
As shown above, the Editgrid plugin
example sets the eq.atrNOC flag on all
attributes which affect the content, to specify that these
attribute values are not cached.
The Editgrid plugin example
provides several methods to modify the content such as setting or clearing
it all at once, or adding to existing content, or modifying or inserting or
deleting a line. The application always expects to DLG GET
a consistent result, regardless of how the content has been set.
For example, the application might DLG SET the entire content and
then DLG GET a specific cell content.
The eloqwebd2 proxy object does not have any
means to derive a "cell" value from a cached "content" value. Instead, the
DLG GET needs to be forwarded to the plugin DLG object in the
web browser by invoking the apiGetAttr()
method.
In the eloqwebd2 proxy object, a
DLG SET on an attribute having the
eq.atrNOC flag set invalidates all cached values of any other
eq.atrNOC attributes.
In the above example, setting a "content" value invalidates a previously
cached "cell" value. The following DLG GET will not find a valid
"cell" value. Also, the "cell" attribute has the
eq.atrNOC flag set. As a consequence, a synchronization takes place,
and the apiGetAttr() method is invoked on
the plugin DLG object in the web browser to obtain the "cell" value requested
by the application.
Please note: In case of the
Editgrid plugin example, this is
necessary to ensure correct behavior. However, this kind of
DLG GET synchronization is considered expensive regarding
application performance.
The eq.atrLST behavior flag
The eq.atrLST flag may be set to specify that multiple
DLG SET invocations need to be stored as list.
On synchronization, the list is transferred to the plugin DLG object in the
web browser by invoking the apiSetAttr()
method for each DLG SET invocation.
The Editgrid plugin example sets
the eq.atrLST flag for the "add" attribute which
allows repeated DLG SET invocations to add to the existing
content line-by-line.
Please note: eq.atrLST attributes must
not be indexed, i.e., the eq.atrIDX and eq.atrLST flags
are mutually exclusive.
The eq.atrSYN behavior flag
In certain cases it might be necessary to set the eq.atrSYN flag to
always enforce immediate synchronization on both DLG GET and
DLG SET, i.e., to go beyond the
eq.atrNOC behavior.
The Filetransfer plugin example
uses the eq.atrSYN flag along with the eq.atrNOC flag to
implement the "select" and "upload" and "download" and "transfer" and "close"
attributes because they require immediate action in the
application user interface.
Please note: A synchronous DLG SET does not automatically
take place when the eq.atrSYN flag is set. As mentioned in the
DLG v2
protocol documentation, the application in addition needs to assign a
status return variable, such as:
DLG SET "Main.file.transfer",Buf$;Rc
Regarding the Filetransfer plugin
example, please also note how it maintains its state using static
class variables to allow that the state's lifetime might span multiple
DLG object instantiations.
Class properties
The plugin class descriptor is expected to define
the prp property providing the class properties,
for example:
// Class properties.
prp : {
minVersion : 3,
classList : 'snowball',
changeEvent : 'input',
actionEvent : 'click',
border : true
},
- minVersion
- Required, specifies the minimum plugin API version which should be 3 for
new plugins, as shown above. If the installed WEBDLG2 is too old so that it
does not meet this minimum plugin API version, the plugin is not loaded,
and an error message is logged in the web browser console.
- classList
- Optional, space-separated list of
CSS class names which are set on the
DIV container
element. The eq-plugin and
eq-control
class names are added, as well as the eq-rule
class name if a nonzero rule attribute value
is set.
- changeEvent
- Optional, space-separated list of DOM
event types which should trigger
a change event, i.e., invoke the
apiOnChange() method.
- actionEvent
- Optional, space-separated list of DOM
event types which should trigger
an action event, i.e., invoke the
apiOnEvent() method if a nonzero
rule attribute value is set and, if the
event is accepted, invoke the
apiOnSubmit() method and submit
the rule to the application.
- focusable
- Optional, needs to be set to false if the plugin object should
not be focusable. The default value is true.
- border
- Optional, needs to be set to true to add a CSS border to the
DIV container
element. The default value is false.
Temporary objects
When the dialog containing the DLG plugin object is not (yet) present in the
web browser, DLG GET and DLG SET called on an
attribute having the
eq.atrNOC and/or
eq.atrSYN flags may need to create a
temporary object.
In other words, the eq.atrNOC and/or
eq.atrSYN flags may require immediate
synchronization in a situation where the DLG plugin object's parent dialog
has not (yet) been defined in the DOM. This is solved by creating a
temporary object to invoke its
apiSetAttr() or
apiGetAttr() method, after which the
temporary object is deleted, i.e., the temporary object
never appears in the user interface.
Dlg.temp may be used to avoid unnecessary
actions on temporary objects, such as setting CSS properties which
never come into effect because the
DOM elements never become visible.
Similarly, the Dlg.grid properties may be
checked whether or not they are undefined, as shown in the
Editgrid plugin example.
A plugin using the eq.atrSYN flag might be
designed to never appear in the user interface, i.e., it might expect that a
temporary object is used for every invocation of its
apiSetAttr() or
apiGetAttr() method. In such a case,
static class variables are typically used to allow that the
lifetime of the plugin's state might span multiple DLG object instantiations,
as shown in the Filetransfer
plugin example.
Static API
Any of the methods listed below may be implemented in the
static object in the plugin
class descriptor. The static methods below operate on the plugin
class, i.e., this refers to the class.
install()
Arguments:
Optional class constructor, invoked when the plugin has been
installed, i.e., when the plugin class is defined in the
eq.c namespace.
dispose()
Arguments:
Optional cleanup method, invoked when the application has ended.
Instance API
Any of the methods listed below may be implemented in the
plugin class descriptor.
apiInit(dlg, el)
Arguments:
this | - plugin instance |
dlg | - Dlg dialog instance |
el | - plugin object
DIV container
element |
Constructor, invoked when a plugin instance is created and the
DIV container
element has been set up in the DOM.
Typically, implementing this method is required to set up the instance and the
user interface.
It may also be used to set up static class variables not possible to
initialize using the class constructor.
For example, the Datepicker plugin
example sets up static class variables based on the
application locale which is available as soon as the
application has started, i.e., which is not available yet when the
class constructor is invoked.
Similarly, the Editgrid plugin
example initializes static class variables based on the
strings configuration which might not yet be
set up when the class constructor is
invoked.
apiDispose(dlg, id)
Arguments:
Optional destructor, invoked when a plugin instance is deleted.
Please note: Any associated
DOM element has already been removed before the
destructor is invoked.
apiSetAttr(dlg, id, el, atr, idx, val)
Arguments:
this | - plugin instance |
dlg | - Dlg dialog instance |
id | - plugin object
DOM identifier |
el | - plugin object
DIV container
element |
atr | - attribute name |
idx | - attribute index string or
null |
val | - value, val.i (integer)
or val.s (string) |
Invoked to set an attribute value. This method is required
if DLG SET attributes are defined. Every
attribute having the eq.atrSET flag needs to be handled.
For indexed values, idx is the index string,
i.e., the attribute name suffix string between the first
[ and the last ], or null if the value is not
indexed.
The val object has either the i or the s property
set, depending on whether an integer or a string value is passed. The other
property is undefined.
apiGetAttr(dlg, id, el, atr, idx)
Arguments:
Invoked to synchronously get an attribute value.
This method is required if DLG GET attributes
are defined which have the eq.atrNOC
and/or eq.atrSYN flags set. Each of these
attributes need to be handled.
For indexed values, idx is the index string,
i.e., the attribute name suffix string between the first
[ and the last ], or null if the value is not
indexed.
apiGetAttr() is expected to return either an integer or a string
value, or undefined if no value can be returned.
If not undefined, an integer is assumed if the returned value's
type is number, otherwise a string is assumed.
Alternatively, null may be returned if a value is not available
immediately, for example if a
promise needs to be fulfilled before a value can be
returned. The plugin is expected to invoke
DlgPlugin.onUpdateReturn() as soon
as the value is available.
Please note: The WEBDLG2 user interface is blocked until a value is
returned.
apiSetSensitive(dlg, id, el, sensitive)
Arguments:
this | - plugin instance |
dlg | - Dlg dialog instance |
id | - plugin object
DOM identifier |
el | - plugin object
DIV container
element |
sensitive | - boolean true or false |
Invoked when the sensitive aka. enabled state has changed. Typically, this
method is required to propagate the sensitive aka. enabled state to
INPUT child elements if present.
By default, the eq-disabled
CSS class name is added on the container
element if the sensitive aka. enabled state is
false.
apiOnEvent(dlg, id, el, e)
Arguments:
Optional event filter, invoked when an
action event has been triggered and a
nonzero rule attribute value is set.
This method is expected to return true to accept the
event, or to return false to discard
the event. When accepted, the
apiOnSubmit() method is invoked if
implemented, then the rule is submitted to the application.
apiOnKey(dlg, id, el, e)
Arguments:
Optional key event handler, expected to return:
true | - consume
event |
false | - pass
event to default handler |
null | - delegate
event to target |
The default handler recognizes accelerator keys as well as the focus
navigation Tab and Enter and cursor keys. The target is the
DOM element where the
event originates, e.g., an
INPUT element.
This method is typically used to implement plugin specific
KeyboardEvent behavior. For example, it might register
changed attribute values, or it might
submit a rule to the application.
apiOnTypeAhead(dlg, id, el, key)
Arguments:
Invoked when the dialog is about to become interactive
to process a single type-ahead key stoke. This method is typically
required if the key event handler is
implemented.
It is expected to return true if the key stroke has been processed,
or false to pass the key stroke to the default handler which
recognizes the focus navigation Tab and Enter keys.
apiOnSubmit(dlg, id, el, ev)
Arguments:
this | - plugin instance |
dlg | - Dlg dialog instance |
id | - plugin object
DOM identifier |
el | - plugin object
DIV container
element |
ev | - DLG event object |
Optional, invoked when the rule is about to be submitted to the application.
This method could, for example, be implemented to unconditionally register
changed attribute values before the rule
is submitted (see also apiChanged() below).
It could also be used to modify the DLG event object, which is used to
delegate the rule submission to the associated eloqwebd2 DLG session.
DLG event object properties:
ev.id | - the DLG object which has triggered the rule
submission (the dialog if not set) |
ev.type | - the
event type which has triggered the rule
submission
| ev.ev | - secondary RuleOverride event if present
|
For example, the TabBox sets ev.id to the selected tab.
This way, the rule of the active tab's GroupBox is submitted.
apiOnChange(dlg, id, el, e)
Arguments:
Optional event handler, invoked when a change
event has been triggered. It is expected to return true to
continue processing the
event, relevant if this
event type is also registered as
action event, or false to stop
processing the
event.
The event type is internally registered to have
been triggered by this DLG object, which causes the
apiChanged() method to be invoked
the next time a rule is submitted to the application.
This method is typically used to implement plugin specific behavior, except on
KeyboardEvent which may be handled by the
apiOnKey() method. For example, it might
register changed attribute values, or it
might submit a rule to the application.
apiFocusElement(dlg, el)
Arguments:
this | - plugin instance |
dlg | - Dlg dialog instance |
el | - plugin object
DIV container
element |
Required if the focusable
DOM element is different from the plugin object
DIV container. This method is invoked when the focus is
about to be set, it is expected to return the
DOM element which should gain the focus.
apiFocusGained(dlg, ct)
Arguments:
this | - plugin instance |
dlg | - Dlg dialog instance |
ct | - DOM control gaining the focus |
Optional notification method invoked when the plugin DLG object is
about to gain the focus.
apiFocusLost(dlg, el)
Arguments:
this | - plugin instance |
dlg | - Dlg dialog instance |
el | - plugin object
DIV container
element |
Optional notification method invoked when the plugin DLG object is
about to lose the focus.
apiChanged(dlg, id, el, ty)
Arguments:
Optional, invoked when the rule is about to be submitted to the application
and one or more change event
types have been triggered before.
Please note: The apiChanged() method is invoked after
the apiOnSubmit() method, if implemented,
has been invoked.
This method could, for example, be implemented to register a
changed attribute value if the ty
array contains a particular
event type.
apiOnUpdate(dlg, id, el, atr, idx)
Arguments:
Optional notification method, invoked after
apiSetAttr() when an
attribute value has been
synchronously set.
Setting the font
The apiSetAttr() method is invoked with
the "font" attribute name to notify a plugin object that the font properties
should be set.
The apiSetAttr() val argument
refers to an object containing the properties:
val.font | - font object |
val.fontRules | - font CSS rules or undefined |
The font object may be used to invoke
DlgElement.setFont() to set the font
properties of a specific
element, as demonstrated in the
Datepicker plugin example.
Alternatively, the font CSS rules may be used to invoke
DlgElement.setCssRule(), especially to
apply the font properties to multiple
elements, as demonstrated in the
Editgrid plugin example.
Please note: The val.fontRules property is undefined
if the font object does not contain any font properties.
DlgPlugin super class API
Plugin classes are derived from DlgPlugin, defined in the
eq.c namespace as eq.c.DlgPlugin.
Please note: These DlgPlugin instance methods can be invoked
when the application is interactive.
DlgPlugin.intAttrChanged(id, type, atr, idx, iv)
DlgPlugin.stringAttrChanged(id, type, atr, idx, sv)
Arguments:
These instance methods register changed attribute values
to be transferred to the associated proxy DLG object during the next
rule submission.
If implemented, the apiChanged() method
will then be invoked with the specified type which should, but is not
required to, be one of the registered
change event
types.
DlgPlugin.submit(id, el, type, rule)
Arguments:
The DlgPlugin.submit() instance method submits a rule to the
application.
The id and el arguments need to specify the
same DLG object, which may be any DLG object in the
current dialog. The DLG object's rule is submitted
if rule is omitted or passed as undefined.
DlgPlugin.onUpdateReturn(dlg, id, val)
Arguments:
dlg | - Dlg dialog instance |
id | - plugin object
DOM identifier |
val | - integer or string value, or undefined |
The DlgPlugin.onUpdateReturn() instance method is used to return a
value after apiGetAttr() could not
immediately return a value to the associated proxy DLG object.
An integer or a string value is expected to be passed in the val
argument, or undefined if no value can be returned.
If not undefined, an integer is assumed if the value's
type is number, otherwise a string is assumed.
Please note: The plugin implementation needs to save the this
plugin instance and the dlg and id arguments passed to the
apiGetAttr() method, then later invoke
the DlgPlugin.onUpdateReturn() method on the same plugin instance
with exactly these arguments, as demonstrated in the
Filetransfer plugin example.
DlgElement base class API
DlgElement is the base class for any DLG object class, defined in
the eq.c namespace as eq.c.DlgElement.
DlgElement.setFont(el, fn)
Arguments:
The DlgElement.setFont() instance method sets an
element's font properties.
The font object specifies the
font family and/or the
font size and/or the
italic font style and/or the
bold font weight.
If any is present in the font object, the
DOM element's
inline style is set appropriately, and the
eq-font
CSS class name is added.
See also: eq.Dom.setFont()
DlgElement.setCssRule(id, type, rule)
Arguments:
id | - DLG object
DOM identifier |
type | - rule type |
rule | - rule string, or array of rule strings, or null |
The DlgElement.setCssRule() instance method sets, or modifies, or
deletes, a dynamic CSS rule. This way, CSS properties may be defined
for a
DOM element or a group of
DOM elements at once. This avoids
needing to modify the
inline style of multiple
elements and works even if the
elements don't yet exist.
The type argument should be an integer identifying the specific CSS
rule. Plugins should use type values above 100 to ensure unique
identifiers.
The type identifier allows to later modify or delete a rule.
If the rule argument is passed as null or undefined
the rule is deleted. When a DLG object is deleted, the associated rules are
deleted as well.
The use of dynamic CSS rules is demonstrated in the
Editgrid plugin example which uses
different id values to set font and height and
width rules, such as (simplified):
apiSetAttr : function(dlg, id, el, atr, idx, val) {
var cls = this.constructor;
…
switch (atr) {
case 'font': {
…
this.setCssRule(id, cls.cssRule.font,
">*" + val.fontRules);
…
this.setCssRule(id, cls.cssRule.height,
" .cell>*{height:" + cssHeight + "}");
…
this.setCssRule(id, cls.cssRule.width, [
">.hdr>.r>*,",
">.row>.r>*>*{width:" + cssWidth + "}"
]);
…
}
}
},
…
static : {
…
cssRule : {
font : 101,
height : 102,
width : 110
}
}
The DlgElement.setCssRule() method prepends all rule strings with the
specified DLG object
DOM identifier. For example, assuming the eq-i42
identifier, the rules below would be set:
#eq-i42 > * {
font-family: sans-serif;
font-size: 13pt;
}
#eq-i42 .cell > * {
height: 1.5em
}
#eq-i42 > .hdr > .r > *,
#eq-i42 > .row > .r > * > * {
width: 11.282ch
}
Here, spaces have been added for better readability. In the first rule, the
val.fontRules have been expanded. In the second and third rules, the
calculated height and width values have been inserted. Also,
the third rule demonstrates how both rule strings are separately prepended with
the eq-i42 DLG object
DOM identifier.
Dlg dialog API
Each dialog has an associated Dlg instance which is passed to the
plugin instance methods listed above. The Dlg
class is defined in the eq.c namespace as eq.c.Dlg.
Dlg.grid
The grid instance member represents the dialog raster used for
position and size calculations, based on the dialog font or, if the dialog font
is not set, the default
font.
- grid.wr
- Number of pixels of the CSS ch
relative length unit.
- grid.wp
- Number of pixels of the letter X width.
- grid.wf
- Dialog raster width factor. For example, the function below calculates
the CSS width in ch units from dialog raster width units passed as
w:
var cssWidth = function(dlg, w) {
if (w)
return (Math.round(w * dlg.grid.wf * 1000) / 1000) + 'ch';
return 0;
}
- grid.hr
- Number of pixels of the CSS em
relative length unit.
- grid.hp
- Number of pixels of the letter X height.
- grid.hf
- Dialog raster height factor. For example, the function below calculates
the CSS height in em units from dialog raster height units passed as
h:
var cssHeight = function(dlg, h) {
if (h)
return (Math.round(h * dlg.grid.hf * 1000) / 1000) + 'em';
return 0;
}
Please note: The above grid properties are undefined
if the dialog is temporary.
For example, the cssHeight() function above uses grid.hf,
consequently it should not be invoked if the dialog is
temporary, such as:
if (dlg.grid.hf !== undefined) {
var height = cssHeight(dlg, 1);
…
}
Dlg.temp
The temp instance member is true if the dialog is
temporary.
Dlg.eds
The eds instance member is a
Map object containing all
DlgElement instances belonging to a dialog.
A DlgElement instance may be obtained by DLG
object DOM identifier, such as:
var self = eq.app.currDlg.eds.get(el.id);
This is typically used in static methods where this does not refer to
the plugin instance.
Dlg.copyFontToElement(el)
Arguments:
The Dlg.copyFontToElement() instance method copies the dialog font
to the specified
DOM element. If the dialog font is not set, the
default font is copied.
If configured, the
FontSizeFactor is applied.
See also: eq.Dom.adjustElementFontSize()
App application API
The App application class is defined in the eq.c namespace as
eq.c.App.
The eq.app instance refers to the current application.
Please note: eq.app is a singleton because the current
implementation supports one application per web browser window or tab.
eq.app.locale
The locale instance member is an object specifying the application
locale. Its tag property contains the corresponding
IETF BCP 47 language tag.
eq.app.idle
The idle instance member is a boolean indicating whether the
application is idle or interactive.
true | - application is idle |
false | - application is interactive |
On DLG DO or Dialog.do, eq.app.idle becomes
false, the current dialog is set up, and
the application becomes interactive.
Outside DLG DO or Dialog.do, eq.app.idle is
true, and any user interaction is blocked.
eq.app.currDlg
The currDlg instance member refers to the current dialog,
i.e., the Dlg dialog instance on which
DLG DO or Dialog.do has been called, or null
when the application is idle.
currDlg refers to the same Dlg dialog
instance as passed to the plugin instance methods listed
above.
eq.app.pendingMouseDown
The pendingMouseDown instance member may be used in the
apiFocusGained() method to check if
it is invoked due to a
mousedown event,
as demonstrated in the Datepicker
and Editgrid plugin examples:
apiFocusGained : function(dlg, ct) {
// Select on focus except on mouse click or if focus doesn't change.
if ( eq.app.pendingMouseDown === undefined
&& ct !== document.activeElement) {
ct.select();
ct.scrollLeft = ct.scrollWidth;
}
}
This selects the entire
INPUT element content and scrolls it to the right, except
when the apiFocusGained() method is
invoked due to a
mousedown event, or when the
INPUT element already has the focus.
eq.app.pendingTabMode
eq.app.pendingTabModeId
The pendingTabMode and pendingTabModeId instance members may
be used in the apiFocusElement()
method to set the focus to the expected
child element during tab navigation.
A forward navigation into the plugin object, for example when pressing the Tab
key, is typically expected to set the focus to the first
child element, while a backward navigation into the object,
for example when pressing the Shift+Tab key combination, is typically expected
to set the focus to the last
child element.
eq.app.pendingTabMode values:
1 | - forward navigation |
-1 | - backward navigation |
undefined | - not a tab navigation |
When eq.app.pendingTabMode is set, i.e., not undefined, the
corresponding eq.app.pendingTabModeId should be checked to match the
plugin object
DOM identifier, such as:
apiFocusElement : function(dlg, el) {
var tab = eq.app.pendingTabMode;
if (tab !== undefined && el.id === eq.app.pendingTabModeId)
…
}
eq.app.setFocus(id, el)
Arguments:
The eq.app.setFocus() instance method sets the focus to the
specified DLG object.
Specifying the el argument is optional but saves a
document.getElementById() invocation in case the
element reference is available anyway.
The method returns true if setting the focus has the side effect of
submitting a rule to the application, otherwise it returns false.
Potentially, a
blur event is triggered by the
element losing the focus, which may cause a rule
submission.
Nothing happens if the
element already has the focus.
eq.app.pendingFocus
The pendingFocus instance member is typically set after
eq.app.setFocus() returned true
to indicate that a rule is submitted. In this case, pendingFocus
schedules an action to execute when the focus is set the next time the
application is about to become interactive again.
eq.app.pendingFocus needs to be set to an object having the
properties:
The action callback function is invoked when the focus is set the next
time the application is about to become interactive
again, given that the
DOM identifier of the focused
DOM identifier is the same as the specified id
property.
action callback function arguments:
this | - the eq.app.pendingFocus object |
el | - DLG object
DOM element |
This is demonstrated in the
Datepicker plugin example,
such as (simplified):
apiOnChange : function(dlg, id, el, e) {
…
if (eq.app.setFocus(id, el)) {
…
eq.app.pendingFocus = {
id : id,
act : function(el) {
// Execute later after rule has been processed.
}
};
return false;
}
…
}
eq.app.makeOverlay(el, ov, onClose)
Arguments:
The eq.app.makeOverlay() instance method sets up the overlay
element so that it becomes a direct
body child. Furthermore, its
z-index is set to the highest
body children
z-index plus 1. In addition, the eq-overlay
CSS class name is added.
As a result, the overlay visually appears above all
elements displayed in the web browser window or tab.
The owner
element is passed to the close callback
function when the overlay is closed.
An overlay is closed explicitly by invoking the
eq.app.closeOverlay() method.
It is closed implicitly when a
mousedown event is triggered outside the
overlay. In both cases, the close callback function is
invoked.
close callback function arguments:
this | - internal overlay descriptor |
el | - owner
DOM element |
ov | - overlay
DOM element |
arg | - optional argument or undefined |
The close callback function is responsible for removing the
overlay
element from the
body. Usually, this is fulfilled when the
overlay
element is moved back into the owner
element, as described in the next section.
The arg argument may be set when explicitly closing the
overlay by invoking the
eq.app.closeOverlay() method, otherwise
arg is undefined.
Typically, the overlay
element is a child of the owner
element, for example a pulldown menu or a
ComboBox list. When the menu or list is opened,
eq.app.makeOverlay() is invoked, passing the menu or
list as overlay
element, which is then detached from the owner
element, then becoming a top-level
element as described above.
eq.app.closeOverlay(el, arg)
Arguments:
el | - optional owner
DOM element |
arg | - optional argument or undefined |
The eq.app.closeOverlay() instance method explicitly closes
the current overlay. Nothing happens
if there is no overlay present.
If the el argument is specified, it must match the owner
element specified to open the
current overlay.
If the arg argument is specified, it is passed to the
close callback function.
eq.app.moveCapture(arg, onMove, onEnd)
Arguments:
arg | - argument passed to callback functions |
onMove | - move callback function |
onEnd | - optional move ended callback function |
The eq.app.moveCapture() instance method may be called when the
primary pointer is down, typically when
the apiOnChange() method is invoked on a
mousedown or
pointerdown change
event.
A move capture is started which invokes the move callback
function whenever the pointer is moved. The capture ends
on a mouseup or
pointerup or
pointercancel event, or when the current
user interaction is interrupted for whatever reason, for example if the
browser window or tab loses focus, or if the application terminates.
The arg argument is passed to the callback functions.
move callback function arguments:
When specified, the move ended callback function is invoked when the
capture ends.
move ended callback function arguments:
this | - internal capture descriptor |
arg | - argument |
e | -
mouseup or
pointerup event object or
undefined |
The move ended callback function e event argument is
undefined if invoked due to an interrupted user interaction.
Please note: The Datepicker
plugin example demonstrates how to use the move capture
functionality when its calendar popup is opened and when the selected day is
changed.
Dom utilities
The eq.Dom namespace defines a collection of utility functions.
eq.Dom.scrollIntoView(dlg, el)
Arguments:
Scrolls the specified
element into view if necessary, i.e., the parent dialog
and/or any parent GroupBox objects are scrolled as necessary.
eq.Dom.setContent(el, cn, checkAccel)
Arguments:
el | -
DOM element |
cn | - content string |
checkAccel | - boolean true or false |
Sets the specified
element's text or HTML content.
HTML content is assumed if the content string begins with <html>.
The DOMParser API is used to parse the content string.
An optional </html> at the end is ignored.
If checkAccel is true, accelerator keys are recognized.
If text content is specified, a letter or digit prepended with the
& character is recognized as accelerator key.
If HTML content is specified, a single underlined letter or digit is recognized
as accelerator key.
eq.Dom.copyContent(to, from)
Arguments:
Copies text or HTML content from an
element to another
element.
eq.Dom.copyFont(to, from)
Arguments:
Copies the
font family and
font size and
font style and
font weight
inline styles
from an
element to another
element.
eq.Dom.copyColors(to, from)
Arguments:
Copies the
color and
background color
inline styles
from an
element to another
element.
eq.Dom.setFont(el, fn)
Arguments:
Sets the specified
element's font properties.
The font object specifies the
font family and/or the
font size and/or the
italic font style and/or the
bold font weight.
If any is present in the font object, the
DOM element's
inline style is set appropriately
and true is returned, otherwise false is returned.
See also: DlgElement.setFont()
eq.Dom.adjustElementFontSize(el)
Arguments:
If configured, applies the
FontSizeFactor
to the specified
element if its
font size
inline style is set.
See also: Dlg.copyFontToElement()
eq.Dom.zIndex(el)
Arguments:
Returns the numeric
z-index of the specified
element.
eq.Dom.zIndexMax(el)
Arguments:
Returns the maximum numeric
z-index of all direct children of the specified
element.
eq.Dom.eqControl(el)
Arguments:
Returns the specified
element's DLG control element, i.e., the specified
element if it has the eq-control
CSS class name set, or the nearest parent
element having the eq-control
class name set, or null if no DLG control
element is found.
eq.Dom.eqDialog(el)
Arguments:
Returns the specified
element's dialog, i.e., the specified
element if it has the eq-dialog
CSS class name set, or the nearest parent
element having the eq-dialog
class name set, or null if no dialog is found.
eq.Dom.eqOverlay(el)
Arguments:
Returns the specified
element's overlay
element, i.e., the specified
element if it has the eq-overlay
CSS class name set, or the nearest parent
element having the eq-overlay
class name set, or null if no
overlay element is found.
eq.Dom.isRootChild(el)
Arguments:
Returns true if the specified
element is a DLG object
DOM element, i.e., if it is a
dialog root
element or a child of a dialog root
element.
eq.Dom.parentIndex(el)
Arguments:
Returns the numeric index of the specified
element in the
children list of the parent
element.
eq.Dom.firstChildByTagName(el, tagName)
Arguments:
Returns the first direct child of the specified
element which matches the specified
tag name, or null if no such direct child exists.
eq.Dom.inputElement(el)
Arguments:
Returns the specified
element's direct or indirect
INPUT child element.
eq.Dom.consumeEvent(e)
Arguments:
Consumes the specified
event, i.e., invokes
e.preventDefault() and
e.stopImmediatePropagation().
eq.Dom.onNextCycle(cb, arg)
Arguments:
cb | - callback function |
arg | - optional argument |
Invokes the specified callback function on the next event
cycle. The arg argument is passed if specified.
callback function arguments:
this | - internal queue item |
arg | - optional argument or undefined |
eq.Dom.onNextFrame(el, qi)
Arguments:
Schedules an action to execute on the next
animation frame.
The specified qi queue item is an object expected to contain
the cb property referring to a callback function.
The callback function is scheduled to execute once during
the next animation frame, regardless how often
eq.Dom.onNextFrame() is invoked on the same
element and on the same callback function.
callback function arguments:
this | - queue item |
el | -
DOM element |
qi | - queue item, same as this |
Please note: The Editgrid plugin
example demonstrates how to use eq.Dom.onNextFrame() to synchronize
scrolling its column titles.
|