Widget
Common features of the WebStudio widgets.
Every widget needs to have a unique id
. If the id
is not set, WebStudio will generate one automatically. The assigned value can be
adjusted as long it is unique.
Model
{
"type": "widget type",
"id": "yLtC", // Unique identification of the widget.
"name": "NAME", // Will be shown in the caption bar.
"description": "",
"captionBar": true,
"options": {
"refreshInterval": 0
},
"dataSource" : {}, // Optional data source from which to load data and model settings
"dragSource": {}, // Optional configuration to enable dragging from this widget
"dropTarget": {}, // Optional configuration to handle drop from dragSource,
"layout": {}
}
Caption bar
All widgets have a caption bar, which is shown by default, but can be hidden by setting the captionBar
property to false:
{
"captionBar": false
}
If more control over the appearance of the caption bar is required, the composite version of the property can be used.
{
"captionBar": {
"hidden": false,
"title": "Widget Title",
"showModelEditorButton": false
}
}
Field | Description | ||
---|---|---|---|
|
Set to false by default. The value can be changed at runtime, using a modify action for example, to show or hide caption bar. The same can be achieved by setting the |
||
|
Optional title string. If omitted, the title will be |
||
|
When set to false, the editor for the widget model is no longer accessible.
|
To hide the caption bar drag handle (=), set the layout.static property to true
Drag-Drop
Widgets can be configured to serve as drag-sources and/or drop-targets, allowing data to be exchanged between them and pipeline actions to be triggered. The drag-drop functionality is internal to the WebStudio compilation and does not support dragging data from outside the view onto a widget or vice versa.
While all widgets support drag-drop some, like the tree
widget, in addition support dragging data elements. Refer to the widget-type specific documentation for the details.
Configuring a drag source.
A widget can be made into a drag source by adding the following element to its model at root level:
{
"dragSource": {
"topic": "DragDropTopic-1",
"enabled": true,
"onDrag": {
"action": {} // Action pipeline to initialize the message passed to the drop target
},
"dragPreview": {}
}
}
Field | Description | ||
---|---|---|---|
|
The drag source is enabled by default, but can be disabled by setting this property to false. |
||
|
Optional property used to provide visual feedback of the content being dragged. If the value is not provided, the widget
|
||
|
Used, when the drag starts to initialize the message object that will be passed to the drop-target. This might involve collecting the widget data or extracting properties from the source widget’s model using a modify action, etc. |
||
|
Used to link the drag-source with one or more drop-targets. Widgets that have their |
Configuring a drop target
A widget can can be configured as a drop-target by providing the following settings:
{
"dropTarget": {
"topic": "DragDropTopic-1",
"canDrop": {
"style": {}
},
"hover": {
"style": {}
},
"enabled": true,
"onDrop": {
"action": {} // Action used to apply the provided data
}
}
}
Field | Description |
---|---|
|
Optional property containing a |
|
The drop target is enabled by default, but can be disabled by setting this property to false. |
|
Optional property containing a |
|
|
|
The widget accepts drop actions from drag-sources with the same |
Drag drop example
The first step when configuring drag-drop, is usually to decide:
-
From where to where the drag should be supported.
-
What data will be transported.
-
What visual feedback to provide to the users of the compilation.
To illustrate the point, let’s consider a very basic implementation in which we:
-
Drag from one text widget to another.
-
The data being exchanged is the text and the background color.
-
On drop, we want to apply the text from the source, and set the text color to the background color of the source.
The drag source for this example might be something like:
{
"type": "text",
"text": "Hello",
"dragSource": { // Source widget from which we are dragging
"topic": "TextDragDrop", // Topic name to link the source and target
"dragPreview": { // Use a box emoji and label for the preview
"type": "icon-label",
"icon": {
"icon": "📦"
},
"label": {
"text": "DRAG TEXT"
}
},
"onDrag": { // When the drag starts
"action": {
{
"type": "modify",
"id": "self",
"set": [
{ //Copy the background color
"name": "payload.bg",
"value": "$model.options.style.backgroundColor"
},
{ // and text to the message payload
"name": "payload.text",
"value": "$model.text"
}
]
}
}
}
},
"options": {
"style": {
"backgroundColor": "aquamarine"
}
}
}
The target widget config could be:
{
"type": "text",
"text": "Target",
"captionBar": true,
"dropTarget": {
"topic": "TextDragDrop", // Match the topic with the source
"canDrop": { // Set the border to indicate we accept this drop
"style": {
"border": "1px solid green",
"backgroundColor": "transparent"
}
},
"hover": { // Set the border to another color when we are over the widget
"style": {
"border": "1px solid yellow",
"backgroundColor": "transparent"
}
},
"onDrop": {
"action": { // Apply the data from the message
"type": "modify",
"id": "self",
"set": [
{ // to set the text color
"name": "model.options.style.color",
"value": "$payload.bg"
},
{ // and the text property
"name": "model.text",
"value": "$payload.text"
}
]
}
}
},
"options": {
"style": {
"color": "grey"
}
}
}
Also refer to the tree widget for details on how to use drag-drop from tree nodes. An example compilation can be found in the getting started section.
Layout
The layout
property is used to specify where the widget appears in the compilation and how large it is. If layout
is not provided, WebStudio will try to auto layout the widget.
{
"layout": {
"x": 0,
"w": 18,
"h": 10,
"y": 0,
"static": false
}
}
Field | Description |
---|---|
|
Set the column and row position of the widget. (0, 0) denotes the top-left cell . Refer to the compilation |
|
Set the widget size expressed in the number of columns wide and number of rows heigh. |
|
Bounds the size of the widget to the supplied numbers. |
|
Setting the |
Icons
While not all widgets make use of icons a number of them, such as the tree, table and tabs widgets, do. Where they can be configure, the model is common and supports simple emoji characters as well as bit-mapped and vector based graphics resources.
The icon
model is shown below:
{
"icon" : {
"icon" : {},
"dark" : {},
"light": {},
"alignment" : "leading",
"style": {},
"styleByTheme": {}
},
}
Field | Description | |
---|---|---|
|
Icons are typically used together with a text label of some sort. The
|
|
|
At first glance, it seems confusion to have an The inner
or a custom graphics element using the fields shown below: |
|
|
Base64 encoded image resource. If you are starting from a source image file, there are various online sites which can help to encode them. |
|
|
Provide a mime type consistent with the image specified in the |
|
|
Url to an online icon resource. For example:
|
|
|
Icon to use with the light and dark themes. |
|
|
These properties are not always present where icons can be defined. Where present they are typically used to set the borders, background and size of the icon. |
The following points should be considered when using graphics resources:
-
Icon width and height: Icons often appear along side accompanying text or labels. Where this is the case, the font-size of the text is used for the icon width and height. Where specific widget models permit the icon style to be configured, its size can be overridden using either css
width
andheight
properties or by specifying afontSize
. -
Image data size: While the data size of images is not the big concern it once was, working with long base64 encoded strings in the compilations can be a hassle. It is therefor recommended that binary images be "compressed" before encoding them.
-
SVG Fill: When using monochrome SVG resources, fill styling can be omitted to allow the Widget to apply the current theme’s fill-colour, which alleviates the need to explicitly provide
light
anddark
themed iconsConsider the following sample SVG images which defines a rectangle. If this source is encoded to base64 and used as an icon, the image will always be drawn in black and will be incapable of adjusting to the selected theme.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg version="1.1" x="0px" y="0px" viewBox="0 0 350 350" style="enable-background:new 0 0 350 350;" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> <rect style="fill:#000000" width="257" height="246" x="44" y="46" /> </svg>
By simply removing the
style="fill:#000000"
attribute, the hosting widget can provide its own settings, allowing the same image to adjust automatically to both light and dark themes.
Options
{
"options": {
"refreshInterval": 10,
"style": {
"backgroundColor": "transparent",
"border": "1px solid blue"
},
"styleByTheme" : {
"light" : {},
"dark" : {}
}
}
}
-
refreshInterval
: Lets the widget automatically refresh. Value is given in seconds. Minimum value is 0.5 seconds. The value 0 means that the refresh interval is disabled. -
style
: Every widget can be styled by setting thestyle
object. Thestyle
object accepts a wide range of CSS styles. The CSS properties are only accepted in camelCase as can be seen from the example above.Some other
border
examples:-
none
-
1px dashed red
-
1px dotted white
-
4px double grey
-
5px ridge white
-
3px solid blue
See more over here CSS Borders.
-
-
styleByTheme
: Anywhere astyle
option is available in the widget model there will also be astyleByTheme
property which, as the name suggests, provides a means to define theme specific styling. This is particularly useful for color settings, which often need to be matched to the theme.It is not mandatory to specify a style for both themes.
The
style
andstyleByTheme
settings can be used together, the latter taking precedence when both define the same style attributes.
Action Pipeline
The widgets can perform logic in the form of actions. This can be a single action or a sequence of actions which we call an action pipeline. The data which is passed to and from one action to the other is called a message.
Actions can be defined within the actions field and in specific parts in the model. This is documented per widget type.
Performing multiple pipelines in parallel can be achieved by defining multiple arrays on the pipeline field.
Message Flow
The input message of a pipeline action contains:
{
"topic": "", // Could be provided by the widget.
"payload": {} // Typically an object.
}
The payload
can be any type. Keep in mind that in order to be able merged with the input message it needs to be an
object. The topic
tells the executing / receiving widget what to do with the payload
.
In case the output of an action doesn’t return an object with topic
or a payload
the output will be set to the input
message payload
of the next action.
With the next example only the payload is provided to the action.
{
"type": "ACTION_TYPE"
}
In order to merge additional fields into the payload
a pipeline action can be defined like:
{
"type": "ACTION_TYPE",
"message": {
"payload": {
"additionalValue": 42
}
}
}
In order to merge additional fields into the message a pipeline action can be defined like:
{
"type": "ACTION_TYPE",
"message": {
"payload": {
"additionalValue": 42
},
"additionalField": "Hello"
}
}
DataSource
Data sources can be defined in the widget model to fetch data from and write data to the system. It can also be an action pipeline. The data returned from a dataSource is typically applied to the data field of the widget.
The dataSource
can also be used to retrieve model elements from the backend allowing widgets to be dynamically customized at runtime. Depending on the type and content, data returned from a dataSource
is interpreted by widgets as follows:
-
Array: The array is assumed to be data and is applied to the widget’s data property (if it has one)
-
Object: The object is inspected, looking for a property called
type
.-
type matches the widget’s type: each top-level property in the returned data-set is applied to the corresponding widget property. For example, suppose the
dataSource
on a table widget returned the JSON shown below. Thedata
,schema
andoptions
settings are overwritten in the work-model. There are however some important exceptions:{ "type": "table", "data": [ { "name": "Inside Temperature", "value": 26, }, // ... ], "schema": [ { "name": "name", "title": "Name-NEW" }, // ... ], "options": { "multi": true, }, "actions": { "onSubmit": { // ... Submit action } } }
-
actions
: The property is merged with the current model, which is to say, existing matching named actions are overwritten and new ones are added. Actions present in the model but not in the returned data are retained. If the table widget in our example already contained saysonSubmit
anddidUpdate
, then theonSubmit
action would get overwritten, but thedidUpdate
will remain unchanged. By contrast any existing option settings not is the returned data-set are effectively lost. -
id
: The widgetid
cannot be changed by thedataSource
and is ignored. -
captionBar
andlayout
: At present changes to thecaptionBar
andlayout
in the work-model has no effect on the widget’s appearance, so these are also ignored. -
Other: There may be further merge behavior specific to individual widgets. Refer the relevant pages for these.
-
-
type
not provided, or does not match the widget’stype
: In this scenario, the update logic looks for adata
field in the returned data-set and applies it to the work-model’sdata
field. All other fields are ignored… with the exception of theschema
property. The rule for theschema
is that it gets applied to the model, provided there is not already one present. If adata
field could not be found, the object as a whole is assigned to the widget’s data property.
-
Common actions:
-
function
: Invokes an Advanced Endpoint. -
read
: Reads the dynamic value or a property value of an object. -
read-write
: Reads and writes the dynamic value or a property value of an object. -
subscribe
: Subscribes to theOnDataChanged
event of a dynamic value. -
write
: Writes the dynamic value or a property value of an object.
Typically a dataSource
has a single action.
{
"dataSource": {
"type": "read",
"path": "/System/Core/Examples/Variable"
}
}
In order to transform
the output message of the read
action, an action pipeline can be defined.
{
"dataSource": [
{
"type": "read",
"path": "/System/Core/Examples/Variable"
},
{
"type": "transform",
"aggregateOne": [] // See transform docs.
}
]
}
Function
To invoke an Advanced Endpoint. The payload
in the output contains the data returned by the Advanced Endpoint.
{
"dataSource": {
"type": "function",
"lib": "LIBRARY NAME",
"func": "FUNCTION NAME", // Optional function name in case library is Lua table.
"farg": {}, // Optional function argument.
"ctx": "" // Optional system object path.
}
}
Read
Reads the dynamic value of an object or the value of an object property. The payload
in the output contains the
dynamic or property value.
{
"dataSource": {
"type": "read",
"path": "/System/Core/Examples/Demo Data/Process Data/FC4711"
}
}
Actions
The actions
is an object, the fields for which are known hooks, like the Life Cycle Hooks, or custom
action names. Each element’s value can be a single action object or an array with actions in a pipeline.
{
"actions": {}
}
Life Cycle Hooks
Widgets supports life cycle hooks. During loading, updating and refreshing many hooks are invoked. Hooks can contain any number of pipeline actions.
Overview of all the general hooks:
-
didLoad
: Widget loaded on screen. -
willUpdate
: Widget will update view. -
didUpdate
: Widget did update view. -
willRefresh
: Widget will perform a refresh. -
didRefresh
: Widget did perform a refresh. -
willFetch
: Widget will perform a fetch. -
didFetch
: Widget did perform a fetch.
The hooks`willFetch` and didFetch
are only invoked if the widget has a data source defined. Note that some widgets
have root properties, like path
on a Faceplate widget, which are considered as a data source.
Load Life Cycle Hooks
The load life cycle flow is:
-
didLoad
-
willFetch
Execution of the data source action (pipeline) -
didFetch
-
willUpdate
Screen updated -
didUpdate