CodeCoupler UI Widget
Overview
A widget is a class derived from the CodeCoupler base class Widget
. A widget will be initialized
by a component within any element of the component. The content of the widget can be freely defined.
Start a Widget
Instantiate
You cannot initialize a Widget
class directly. A widget can be started over the widget factory
method widget(appStart)
which is available in all components.
1 |
|
Error Handling
If any error occurs the initializing process will stop and an error will be thrown. The widget will be blocked with a message.
The error message can be modified in the system wide setting messages.WIDGET.ERROR_INIT
.
In case that the error occurs during the system initialization, the parent system will catch the and
handle this error. Please read the chapter
"Error Handling" in the documentation of System
for furher
informations.
Start Definition Object
The widget start definition object widgetStart
is not optional. It have to be an object
or an
Widget
class.
Alternative signatures:
-
this.widget(WidgetClass)
: SettingwidgetStart
toWidget
class is just a shortcut for{ widget: WidgetClass }
. -
this.widget(WidgetClass, WidgetOptions)
: SettingwidgetStart
toWidget
class with a second argument is just a shortcut for{ widget: WidgetClass, options: WidgetOptions }
.
The widgetStart
object it can have the following properties:
container
[ String | HTMLElement | jQuery Object ] (Default: Current Stage)-
This is the container where the widget structure will be build. The container itself will be not touched. All additional elements will be created inside of this container.
This is optional in a stageable component (like an
Application
orSystem
). In other components this is mandantory. id
[ String ] (Default: Random String)-
An unique id that represents the widget instance. You cannot create two widgets with the same id on the same parent instance. If you do not specify an id a random id will be used. You should always use an id if you need to access the widget instance over the property
widgets
which is avaliable in all parent instances. type
[ String ] (Default: "widget")-
Can be
widget
,vue
,vue-sr
orvue-mr
. It specify the type of the widget class which can be a plain JavaScriptWidget
class or aVue
application. component
[ Class | Vue ] (Mandatory)-
The widget class or widget vue application to instantiate.
options
[ Object ] (Default:undefined
)-
Options which should be passed on to the widget.
settings
[ Object ] (Default:undefined
)-
Override here the system wide settings for this widget and all child components.
on
[ Object ] (Default:undefined
)-
Early bind callbacks to events. In some cases the application fires events within the initialization phase. Instead of using
instance.on("eventname",callback)
after initialization (what would be too late) you can define here callbacks which will be early binded to be able to react to this events.Define just an object with the eventnames as properties and callback functions as values:
1 2 3
on: { eventname: callback }
Implement a Widget
Basics
You can write a new widget as plain JavaScript class or as a Vue application.
To write a new widget class you have to extend the CodeCoupler class Widget
:
1 2 3 4 5 6 |
|
The only method you have to provide is async init()
.
To write a Vue based widget, just write an Vue application which receives the following props
:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
The property component
is a pointer to a base instance of a Widget
class. From there you can
access all methods and properties of a component like you were writing a plain JavaScript class and
would access over this
.
Initialization and Starting Process
flowchart TB
subgraph S1 [ ]
S1A[Init Container<br>See 'DOM Layout'] --> S1C
S1C[Block Widget]
end
S1C --> A
A[Execute `init` Method] --> S2A
style A color:#000,fill:#ffc929,stroke:#333,stroke-width:4px
subgraph S2 [ ]
S2A[Unblock Widget]
end
S2A --> I
I[Widget is initialized]
DOM Layout
After launching a widget, the container element itself is not modified, except for the fact that a few styles are set. Instead, one or two more elements are created within the container.
The most important thing to note is that the container defines the dimensions of the visible area of the widget. These dimensions remain fixed and do not grow with the content of a widget. The container gets the same styles as a stage.
By default two elements will be created inside of the container. The first one will provide a custom
scroller and the second is just a plain div
. This inner div
is the element which can be used to
implement the widget interface.
The scroll functionality guarantees the widget to use the entire width and height of the inner div and the container to keep its dimensions.
Default Structure:
┌──────────────────────────────────────────────────────────────────────────┐
│ │
│ This is the container defined in the widgetStart argument. │
│ Accessible over this.env.start.stage.element or $element │
│ │
│ This is always a stage element which have the following styles set |
| directly: |
│ │
│ position: absolute | relative | fixed (Default: relative) │
│ isolation: isolate │
│ overflow: hidden │
│ flex-basis: 0 (Will only be set if flex-grow is "1") │
│ │
│ Furthermore the element have the class "codecoupler__stage". │
│ │
│ ┌─Widget─────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ div │ │
│ │ Container in where the PerfectScrollbar will be initialized. │ │
│ │ Accessible over this.env.scroll or this.env.$scroll │ │
│ │ │ │
│ │ height: 100%; │ │
│ │ width: 100%; │ │
│ │ position: relative; │ │
│ │ │ │
│ | Furthermore the element have the class "codecoupler__widget" which | |
| | stretch all the widget elements below to "min-height:100%; | |
| | min-width:100%". │ |
│ │ │ │
│ │ ┌──────────────────────────────────────────────────────────────┐ │ │
│ │ │ div │ │ │
│ │ │ Here is the place where the widget will be initialized. │ │ │
│ │ │ Accessible over this.env.element or this.env.$element │ │ │
│ │ │ │ │ │
│ │ │ min-height: 100%; (Set by codecoupler__widget) │ │ │
│ │ │ min-width: 100%; (Set by codecoupler__widget) │ │ │
│ │ └──────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌──────────────────────────────────────────────────────────────┐ │ │
│ │ │ Technically needed divs for the scroller │ │ │
│ │ └──────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─Canvas─────────────────────────────────────────────────────────────┐ |
│ │ │ |
│ │ div │ |
│ │ Here is the place where the widget will be initialized. │ |
│ │ Accessible over this.env.element or this.env.$element │ |
│ │ │ |
│ │ height: 100%; (Set by codecoupler__stage) │ |
│ │ width: 100%; (Set by codecoupler__stage) │ |
│ │ │ |
│ └────────────────────────────────────────────────────────────────────┘ |
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ Other divs of applications and needed for blocking │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────┘
The property this.env
contains the properties container
, scroll
and element
to access the
single elements. The properties $container
, $scroll
and $element
are the jQuery counterparts.
Normally you should not manipulate the container
and the scroll
element. The scroll
element
can be used to scroll your widget. You can use here plain JavaScript DOM methods scrollTop
and
scrollLeft
.
If the scroll container is actually not needed, the widget can announce this via overriding the
prepare
method (read below). In this case the inner div
will get the style
overflow: "hidden"; height: "100%"; width: "100%"
. This guarantees the container to keep its
dimensions.
Structure without Scroller:
┌────────────────────────────────────────────────────────────────────────┐
│ This is the container defined in the definition argument. │
│ Accessible over env.start.stage.element or $element │
│ │
│ position: absolute | relative | fixed (Default: relative) │
│ isolation: isolate │
│ overflow: hidden │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ div │ │
│ │ Here is the place where the widget will be initialized. │ │
│ │ Accessible over env.element or env.$element │ │
│ │ │ │
│ │ min-height: 100%; │ │
│ │ min-width: 100%; │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ Other divs of applications and needed for blocking │ │
│ └──────────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────┘
In addition to the JavaScript-based widget, you can also create a Vue-based widget. In this case you have to provide a Vue application which will be instantiated.
You have to specify if the Vue application use a single root template or not. Depending on this the
inner div
described above is the root element (this.$el) of your vue application or just a parent
container:
Single root Vue application:
┌────────────────────────────────────────────────────────────────────────┐
│ The parent containers and all styles will be │
│ constructed like with JavaScript-based widgets │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ div │ │
│ │ │ │
│ │ Root element of your Vue template │ │
│ │ Accessible over this.component.env.element or ...$element │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ Other divs of applications and needed for blocking │ │
│ └──────────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────┘
Vue with single root template
The variable this.component.env.element
where you get normally the root element will not be available
while mounting (and thus in the methods beforeCreate
, created
, beforeMount
and mounted
).
Multiple root Vue application:
┌────────────────────────────────────────────────────────────────────────┐
│ The parent containers and all styles will be │
│ constructed like with JavaScript-based widgets │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ div │ │
│ │ Accessible over this.component.env.element or ...$element │ │
│ │ │ │
│ │ Multiple root elements of your Vue template: │ │
│ │ ┌────────────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ └────────────────────────────────────────────────────────────┘ │ │
│ │ ┌────────────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ └────────────────────────────────────────────────────────────┘ │ │
│ │ ┌────────────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ └────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ Other divs of applications and needed for blocking │ │
│ └──────────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────┘
What's next
Do whatever you want and build amazing interfaces within this.element
!
Replacing Root Element
Some components aloow you to replace this.element
with your own.
In this case you should never use this.env.$element.replaceWith()
. Use instead this.replaceElement()`!
Implementation Details
Controlling the DOM Structure and Initialization Phase
A Widget build the previous DOM structure and block the widget while initializing. Sometimes this is not needed. To control these features you have implement the following method:
1 2 3 4 5 6 7 |
|
Reference
In addition to the common instance members described in the base classe
Component
a widget has the following:
Instance Properties
vue
andvueApp
-
This properties will be accessible if the widget is Vue based.
vue
points to the Vue instance andvueApp
to the Vue application object.
Instance Methods
replaceElement(newElement)
-
This will replace the root element of the widget with the given
newElement
. The argument can be a HTMLElement, a jQuery object or a selector string.The variables
this.env.$element
andthis.env.element
will be redefined.