CodeCoupler UI Application
Overview
An application is a class derived from the CodeCoupler base class Application
. An application is a
container that, in addition to a content area, optionally also has a title bar, a footer or other
framing elements. Each component can start an application, even an application itself.
If not maximized the application can be resized and dragged within a certain container. Depending on what component started the application.
An application will trap the focus inside the focusable elements of the application. If there is no focusable element in the application panel, the panel itself gets focusable and receive the focus.
An application provides after initialization a stage in which different widgets can be started. Alternatively, a stage can be subdivided into smaller stages before widgets are started.
Start an Application
Instantiate
You cannot initialize an Application
class directly. An application can be started over different
application factory methods which are available in all components.
Component | Method | Description | Forced Header |
---|---|---|---|
Stageable (System, Application) | app(appStart) | The Application will be started in current stage of the component as soon as the component has finished initializing. In fact this is will call the `app()` method of the current stage instance. | No |
forceApp(appStart) | The Application will be started in current stage of the system like in `app()` but immediatley, not waiting the initialization finishing. This should be used carefully. | No | |
rootApp(appStart) | The Application will be started in the root stage of the component (System: Container, Application: Conten Area). | Yes | |
Stage | app(appStart) | The Application will be started in the *new* stage, provided by the instance. | Only if not the last stage |
stageApp(appStart) | The Application will be started in the container of the instance. In a chain of stages this is in fact the previous stage. | Yes | |
Widget | app(appStart) | The Application will be started in the container of the widget. | Yes |
Applications started with "Forced Header" will started by default normalized and with a titlebar. In all other cases applications will not have explicit any default values for titlebar and start status. With this you can define in the system wide settings to open all stage applications maximized and without a titlebar.
Using the factory method inside the initialization methods init
, boot
or start
is problematic.
Basically you should start an application during initialization inside of in start
. In a stageable
component you should furthermore never use await
. Read below more details:
Component | Possible Problems |
---|---|
Stageable (System, Application) | Calling `await this.app(appStart)` inside the `init`, `boot` or `start` method of a stageable component will not work because the method will wait for the component initialization and you will wait for the application initialization. Everyone is waiting and nothing happens. You should use `this.app(appStart)` (without await) which will start the app after the system initialization. Or you can use `this.forceApp(appStart)` (very careful and only if really needed). |
System | You should avoid starting an application with `this.forceApp(appStart)` inside the `init` or `boot` method of a system. A stage may be started after the `boot` method, which would lead to an error because the current stage is not empty anymore. |
Application | Calling `this.app(appStart)` inside the `init` method of an application instance will throw an exception because the application panel is not ready yet. If needed you should use the method inside the `start` method. |
Stage | Calling `this.app(appStart)` inside the `init` method of an stage instance will throw an exception because the new stage is not ready yet. If needed you should use the method inside the `start` method. Basically you should always pay attention if you start an application inside a stage instance. In case that after this stage an additional stage will be initialized would throw an error because the new stage you created is not empty anymore. |
Error Handling
If any error occurs the initializing process will stop and an error will be thrown. The application panel will be blocked with a message. If the panel was not created yet, an error hint will be showed.
The error message can be modified in the system wide setting messages.APP.ERROR_INIT
.
Note: 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 application start definition object appStart
is optional. If you omit this a generic
appilcation will be started. If specified it have to be an object
or an Application
class.
Setting appStart
to Application
class is just a shortcut for { app: ApplicationClass }
.
If appStart
is an object
it can have the following properties:
id
[ String ] (Default: Random String)-
If you define an id, no other application with the same id can be started. However, this is only valid in relation to the starting component. Each system, widget, stage or application can start and use their own id's.
If you specify an id which already exists, the method
app()
will return the running app.Instead of using the method
app()
to get an already running application instance, you can use the getterapps
which provide each component to access all applications of the component. component
[ CodeCoupler Application ] (Default:undefined
)-
The CodeCoupler application class to start. If you omit this just a generic appilcation will be started.
modal
[ Boolean ] (Default:undefined
)-
If set to
true
, the application will be started modal. options
[ Object ] (Default:undefined
)-
The options for the application.
panel
[ Object ] (Default:undefined
)-
Configuration for the jsPanel creation, norally returned by the
init
method of the application. The values here override most of the values defined in the system wide settings and the values returned by theinit
method of the application. More details will be explained later here. ui
[ Object ] (Default:undefined
)-
Options that should override the application default value defined in the static
ui
property, for representing the app in the UI. splash
[ Object | Boolean ] (Default:undefined
)-
The both splash screen while initializing and while starting the application can be disabled setting the following properties to
false
:1 2 3 4
{ init: false, start: false }
To disable both you can also set
splash
directly tofalse
. settings
[ Object ] (Default:undefined
)-
Override here the system wide settings for this application 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 }
container
[ Internally used ]-
This property cannot be set and will be used and internally.
container
is the parent HTMLElement of the panel.
Implement an Application
Basics
To implement a new application you have to define a which extends the CodeCoupler class
Application
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Initialization and Starting Process
flowchart TB
subgraph S1 [ ]
S1A[Start `init` Splash Screen]
end
S1A --> A
A[Execute `init` Method] --> S2A
style A color:#000,fill:#ffc929,stroke:#333,stroke-width:4px
subgraph S2 [ ]
S2A[Create Panel] --> S2AA
S2AA[Block Panel] --> S2B
S2B[Close `init` Splash Screen] --> S2C
S2C[Start `start` Splash Screen]
end
S2C --> G
G[Execute `start` Method] --> S3A
style G color:#000,fill:#ffc929,stroke:#333,stroke-width:4px
subgraph S3 [ ]
S3A[Close `start` Splash Screen] --> S3B
S3B[Unblock Panel]
end
S3B --> I
I[Application is initialized]
DOM Layout
An application creates an element which is basically structured like this:
┌───────────────────────────────────────────────────────────────────┐
│ Header │
│ Accesible over this.panel.header │
├───────────────────────────────────────────────────────────────────┤
│ │
│ Content │
│ Accesible over this.panel.content │
│ │
│ position: absolute │
│ isolation: isolate │
│ overflow: hidden │
│ │
├───────────────────────────────────────────────────────────────────┤
│ Footer │
│ Accesible over this.panel.footer │
└───────────────────────────────────────────────────────────────────┘
Differences to the original library jsPanel
In contrast to the origin jsPanel library which provide the panel control, some changes were made to the styling:
The content area have stage styles and is not scrollable.
The height of the titlebar will be controlled via font-size
. Set the desired font size
directly on the panel or in the sub-element with the class .jsPanel-headerbar
.
All font sizes in all panel elements will be inherited from the parent DOM settings. Changing the font size in the document should change the font-size in all elements of the panel normally.
What's next
You can acces the panel through the variable this.panel
. But changes to this element should only
be made with great care.
An Application is not intended to provide the user with an interface or to make changes to it. An Application is normally filled via stages and widgets.
Implementation Details
The Panel Configuration Object
The init
method have to return a panel configuration object which will be be used to create the
application panel. Basically you can use almost all
options for creating a jsPanel with some modifications
explained here.
Default Values and Precedence
The default values of all options will be taken from the system wide settings defined in the
property panel
. The return value of the init
method can override these option values, but the
start definition object can in turn overwrite those from the init
function.
This generally rule does not apply to all options. In the case of the array based callback options, the return values of the init function have priority. Specifically, these are the following options:
Array based callback options that can be used
onbeforeminimize
, onbeforemaximize
, onbeforenormalize
, onbeforesmallify
,
onbeforeunsmallify
, onfronted
, onminimized
, onmaximized
, onnormalized
,
onsmallified
, onunsmallified
, onstatuschange
, onclosed
Array based callback options will be merged and their functions executed in the following order:
- Callback defined in the return value of the
init
method. - Callback defined in the start defintion object.
- Callback defined in the system wide settings.
Any of these callbacks can return false
to prevent executing any following callback.
The idea behind of this order, is that an application developer should use these functions to implement relevant logic and leave all other options mostly untouched. All the other options mainly concern the appearance of the application. And this should be left to the user of your application.
Special handled Options
The following options can not be set or will be handled in a special way:
setStatus
-
You can use the shortcut
fullsize
here, which will set thesetStatus
tomaximized
andheader
tofalse
. dragit
-
Will be set to
false
ifsetStatus
is set tomaximized
andheader
tofalse
. resizeit
-
Will be set to
false
ifsetStatus
is set tomaximized
andheader
tofalse
. If this is not the case and the merged value is notfalse
, all callbacksresizeit.resize
will be merged into an array (start definition object, return value of theinit
method and system wide settings). onbeforeclose
-
Cannot be used. Use instead the component method
async destroy()
. callback
,minimizeTo
,container
,syncMargins
,onwindowresize
andid
-
Cannot be used!
headerTitle
-
Will be set to the name of the application unless otherwise defined. The name will be taken from the
ui
property of the application or the starting definition object. footerToolbar
-
If you specify the property
footerToolbar
as a string, or a function that returns a string you can use shortcuts to create predifined buttons. Read more about this below in "The Footer Toolbar Buttons".
The Panel Object
In the start
method you have access to the panel via this.panel
. This is basically a jsPanel
object and you can use all the functions provided by
the library jsPanel.
Over this.panel
you have access to the library methods however, it is also the DOM element at the
same time. With this.$panel
you can get this DOM element as a jQuery object.
In contrast to the origin jsPanel library the panel content area is styled among other with
overflow: hidden
. The content area is not intended to be filled with content. Content should only
be provided via widgets and stages. The most simple way is to initialize one widget in the container
with this.widget()
and implement the interface in the widget.
Splash Screens
The splash screen will be started twice. The first splash screen starts centered in the container of the application (the current stage for example). The second splash screen starts centered in the application panel and at the same time blocks the panel.
If an inline application starts a splash screen for the init
phase while the parent application
shows also a splash screen, the splash screen of the parent application will temporarly hidden. It
will unhidden as soon as the inline application close its splash screen.
You can modify or disable the splash screens with the method async splash(mode, options)
. The
mode
argument can have the values init
and start
and indicates which of the two screens should
be started. The options
argument contain the option with which the application was started.
The method have to return an object which is basically just a config object of jsPanel hint extension. You can set all options from the documentation except the following:
1 2 3 4 5 6 7 |
|
The most simple splash modification is to return an object with one property content
which only
modify the content of the splash screen. The property callback
may also be helpful if you want to
change the content after it has been generated.
1 2 3 4 5 6 7 8 9 10 11 |
|
To disable a splash screen return false
:
1 2 3 |
|
A splash screen works as a "sticky blocking layer". Any other blocking layer will not overlay a splash screen.
If you disable the start
splash screen the application will be blocked using the message from the
system wide setting messages.APP.LOADING
. This blocking works as any other "normal blocking
layer". Any other blocking will be placed over this.
Footer Toolbar & Buttons
Default Buttons
The string in footerToolbar
of the panel configuration returned by the init
method can contain
one of the following placeholders which will be replaced by buttons:
[refresh]
-
Calling
refreshDataUI()
. The defult text of the button is defined as a function and retrieve the value from system wide settingmessages.BUTTONS.REFRESH
. [cancel]
-
Call
cancelDataUI()
and close the application on success. The defult text of the button is defined as a function and retrieve the value from system wide settingmessages.BUTTONS.CANCEL
. [reset]
-
Like [cancel] without closing the application. The defult text of the button is defined as a function and retrieve the value from system wide setting
messages.BUTTONS.RESET
. [saveclose]
-
Call
saveDataUI()
and close the application on success. The defult text of the button is defined as a function and retrieve the value from system wide settingmessages.BUTTONS.SAVECLOSE
. [save]
-
Like [saveclose] without closing the application. The defult text of the button is defined as a function and retrieve the value from system wide setting
messages.BUTTONS.SAVE
. [close]
-
A button which will close the panel. IMPORTANT: Button will just close the panel! There is no check if data is modified!
The defult text of the button is defined as a function and retrieve the value from system wide setting
messages.BUTTONS.CLOSE
. [data]
-
An alias for
[refresh][cancel][reset][save][saveclose]
Button Configuration
You can define own button shortcuts or modify the existing in the system wide setting buttons
.
This is an object with two properties shortcuts
and templates
. Over this.settings
you modify
only the settings which only affect this component.
The buttons that can be used are defined as properties of the object shortcuts
. Use as property
only the name without the bracets. Example: The button that can be used in the footer toolbar as
[refresh]
is defined in the system wide settings under buttons.shortcuts.refresh
.
1 2 3 4 5 6 7 8 9 |
|
If you want to reuse default functions but want to add some functionality to them you can "extend" them by the following way:
1 2 3 4 5 |
|
A button definition have to be an object with the following properties:
class
[ String | Function ] (Default:undefined
)-
Specify here one of the Bootstrap color theme tokens
primary
,success
,warning
,danger
etc. The default button template use this string as suffix tobtn-
for a class name that will be assigned to the button.
The property can be a function that returns the value that have to be used. The function will be executed in the context of the application instance and additionally the instance will be used as first argument.
html
[ String | Function ] (Default:undefined
)-
The inner HTML of the button. The string can contain placeholders like
{0}
,{1}
etc. The string ofhtml
will be merged withtext
like inprintf
functions. If you have defined more than one placeholder you can use an array intext
. You can also omithtml
completely.The property can be a function that returns the value that have to be used. The function will be executed in the context of the application instance and additionally the instance will be used as first argument.
text
[ String | Array | Function ] (Mandatory)-
You have to specify
text
orreplace
to make the shortcut working. If you specify both onlytext
is taken into account.If you have specified
html
this will be the replacement of the placeholders defined inhtml
. In this case it can be an array to define multiple text replacements.If you did not defined
html
you can specify here a simple string that will be used as label for the button.The property can be a function that returns the value that have to be used. The function will be executed in the context of the application instance and additionally the instance will be used as first argument.
click
[ async Function(component) ] (Default:undefined
)-
Specify an async function to call on button click. The function must be async and the application will be blocked while the function is executing. You can disable the blocking with the property
block
.
The function will be executed in the context of the application instance and additionally the instance will be used as first argument.
replace
[ String ] (Default:undefined
)-
You have to specify
text
orreplace
to make the shortcut working. If you specify both onlytext
is taken into account.If you specify this property the button shortcut will just replaced with with string. The string can contain itself button shortcuts that will be interpreted.
This is usefull to define a group of buttons like in the
data
shortcut:1 2 3 4 5 6
{ data: { replace: "[refresh][cancel][reset][save][saveclose]" } }
template
[ String ] (Default: "default")-
You can define multiple templates which produce from a button configuration a button. If you do not specify a template
default
will be used. See next chapter for more details. block
: [ String | False ] (Default:undefined
)-
If you set this to
false
the application will not be blocked while executing the function defined inclick
.Otherwise you can define here the message that will be shown while blocking the application.
If you do not specify
block
the message from the system wide settingsmessages.BUTTONS.BLOCK
will be used.
Button Templates
You can define own templates or modify the existing in the system wide setting buttons.templates
.
The default template that is included is named default
and looks like this:
1 2 3 4 5 6 7 8 9 10 |
|
As you can see a template is a simple string with the placeholders {0}
to {2}
which will be used
as follows:
{0}
-
The string defined in
class
. {1}
-
The name of the button shortcut which have to be used at least in a
data-role
attribute of an element that is clickable. Based on this attribute the click handler will be attached to the element. {2}
-
The content for the button build from
html
andtext
. Thetext
will be HTML escaped, even all elements oftext
if it is an array. {3}
-
HTML escaped
text
. Iftext
is an array all escaped elements joined with a comma.
Some remarks:
- The class
jsPanel-ftr-btn
should be used on a button to avoid acting as drag handle. - The buttons shortcuts will be replaced without any additional spaces around them. Keep this in
mind and define eventual margins (like in the default template with
my-1 mx-2
).
Inline Applications of Stages
If you use inline applications in stages you have to pay attention that minimized panels will be attached to the bottom of the stage element. In some cases this could match with the bottom of the current stage. In the bottom area of the current stage will be attached the minimized system applications. The minimized stage applications would thus overlap the minimized system applications.
To avoid this you could define in your stage an explicit area in where the panels should be minimized and make sure that this area do not overlap the bottom of the current stage.
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 9 10 |
|
This newly defined area must not have an height defined. If no application is minized the area will collapse and will not be visible.
To define this area you have to insert just a <div>
with the following attributes:
1 |
|
Reference
In addition to the common instance members described in the base classes
Component
and Stageable
an application has the
following:
Instance Events
fronted
,unfronted
-
Will be fired if the panel is set in front of other application panels. In contrast to the "onfronted" event of the panel it will only fired once. The "onfronted" event of the panel will be fired everytime you click inside the panel for example, even if it was allready in front.
As argument the event will have the application instance.
The first "fronted" event will be fired inside of the initialization phase. To catch this first event you have to specify your callback in the start definition object in the property
on
.Each component can have only one application which is fronted. If one application gets fronted all the other applications of this component fire the event
unfronted
.
Instance Methods
close()
,closeForce()
-
Calls the destroy method and closes the panel. These methods are in contrast to the
destroy
method not asynchronous.The
close
method will ask the user if the methodhasChanges
do not returnfalse
if he really want to close the application and loose all changes. The message came from the system wide settingmessages.APP.CONFIRM_CLOSE
.The application component provide the following ways to close an application:
app = Instance of an application component app.close() ┌─► app.closeForce() ──► app.panel.close() ┌─► app.destroy() │ │ or click on close │ │ ▼ │ handle in header │ ▼ Confirm │ │ │ Execute app.destroy() Data Loss │ ▼ │ Asynchronous and wait if changes ─┘ Interrupt closing │ │ detected the panel ─┘ ▼ Trigger "destroyed" no matter if destroy() success or fail
To detect if an application have been closed you should watch for the event "destroyed". Another method would be to use the "onclosed" callback of the application panel, but this is not the preffered method.
Instance Getter
panel
-
Returns the current panel of the application.
$panel
-
Returns the current panel of the application as a jsPanel object.
fronted
-
Returns
true
if panel is currently fronted, otherwisefalse
.