Skip to content

CodeCoupler UI System

Overview

With System a CodeCoupler UI container will be initialized. The origin of all existence.

A System provides after initialization a stage in which different applications can be started. Alternatively, a stage can be subdivided into smaller stages before applications are started.

Start a System

Instantiate

You can instatiate a generic system using the class System (simplified way):

import { System } from "@codecoupler/cc-ui";
new System(systemStart);

Or implement your own extended system class and use this (standard way). This way offers many more possibilities to intervene in the initialization process later on:

// File my-system.js
import { System } from "@codecoupler/cc-ui";
export default class extends System {
  async init() {}
  async start() {}
  async boot() {}
}
// File index.js
import { MySystem } from "./my-system.js";
new MySystem(systemStart);

The system initialization takes place asynchronously. To wait for a initialized system you can request the promise provided by the property initialized:

then/catch syntax without "await":

1
2
3
4
5
6
7
8
const system = new System(systemStart).initialized
  .then((system) => {
    // Do something
    // Access the system instance with argument "system"
  })
  .catch((e) => {
    // Catch an error
  });

As one-liner with "await" (only usable within async functions):

const system = await new System(systemStart).initialized;

Separate lines with try/catch Syntax (only usable within async functions):

1
2
3
4
5
6
const system = new System(systemStart);
try {
  await system.initialized;
} catch (e) {
  // Catch an error
}

Error Handling

If any error occurs (for example DataSources errors, required fonts cannot be loaded, stage loading errors, application loading errors etc.) the initializing process will stop and an error will be thrown. The system will be blocked with a message.

The error message can be modified in the system wide setting messages.SYSTEM.ERROR_INIT.

The promise initialized will be rejected always with a custom error type of ComponentInitError. The origin error that causes the failure is saved in the property cause. The property component of this error type points to the system instance.

You have to keep in mind that some errors maybe cannot not be catched by the system initialization and the element will not blocked with an error message. For this case you can query the property e.component.blocked in the catch function. If this property is error, the system was blocked already with an error message.

Use the following pattern to ensure displaying something to the user in case of an error:

1
2
3
4
5
6
7
8
9
new System(systemStart).initialized.catch((e) => {
  if (e instanceof ComponentInitError) {
    console.error(e);
    if (e.component.blocked !== "error" && e.component.env.$box)
      e.component.env.$box.html("Oops, Something went wrong!");
  } else {
    throw e;
  }
});

Start Definition Object

The system start definition object systemStart is optional. If you omit this a system will be started in the body element. If specified it have to be an object and can have the following properties:

container [ String | HTMLElement | jQuery Object ] (Default: body)

Define here where to initialize the system. The container can be defined as HTMLElement, jQuery object or selector string.

The container will be emptied!

id [ String ] (Default: Random String)

Id of the CodeCoupler System. If another system with the same id already exists an error will be thrown.

The DOM id will be set to the id (prefixed with id_).

The id will be used among other things to control the navigation or automatic starting the last application after a reload.

If you do not specify id a random id will be used which will be created on each page load. Therefore the automatic starting the last application will not work.

apps [ Function(system) | Array ] (Default: undefined)

Application registry. If specified as a function the system instance will be used as argument.

options [ Object ] (Default: undefined)

These options are passed as an argument in the init method and can be used there. Useful for customized System classes which can be parameterized.

preload [ Object ] (Default: undefined)

Assets to preload within the initialization phase. You can use any defined preload handler in three different objects (custom, auth and core), each belonging to a specific initialization phase.

The preload handlers defined by default are: dataSources, fonts and fontsRequired.

► Read more about preloading assets

This option is useful if you start a system with the simplified way. Starting the system with the standard way by extending the class System, you can use the method this.preload() within the methods init, boot and start to preload assets.

Example:

1
2
3
4
5
preload: {
  auth: {
    dataSources: [{}, {}, {}]
  }
},
preload.custom [ Object ]

The ressources in preload.custom will be loaded before the user authentication.

preload.auth [ Object ]

The ressources in preload.auth will be loaded after the user authentication.

preload.core [ Object ]

In preload.core are some assets predefined that will be used by the CodeCoupler system and all the external libraries. These assets will be loaded at last.

All the fonts used by the exetrnal libraries included in CodeCoupler System ("Font Awesome 5 Brands", "Font Awesome 5 Free:n4,n9", "context-menu-icons", "WebComponentsIcons", "DejaVu Sans:n4,n7,i4,i7", "DejaVu Serif:n4,n7,i4,i7", "DejaVu Mono:n4,n7,i4,i7") are defined here and should always preloaded.

stages [ Object[] | Object ] (Default: undefined)

Array of stage start definition objects or a single one to create sequencially within the initialization phase.

This option is useful if you start a system with the simplified way. Starting the system with the standard way by extending the class System, you can use the method this.stage() within the methods boot or start to load stages.

auth [ Object ] (Default: undefined)

Authentication Module and options to use. The default values are read from system wide settings auth.

► Read more about authentication

module [ CodeCoupler Authentication Module Instance ] (Default: new AuthModBase())

The authentication module to use. If none is given the default module will be used which do provide only anonymous access.

app [ CodeCoupler Authentication Application ] (Default: AuthAppBasic)

The authentication application to use. If none is given the basic application will be used which do provide an input screen for username and password.

options [ Object ]

The options to use when starting the authentication application.

requiredPermission [ String ]

The permissions the user must have to initialize the CodeCoupler System. Can be set to $autorized to allow any authorized user to initialize the CodeCoupler System.

settings [ Object ] (Default: undefined)

System wide settings which will be used by all components in this systems.

► Read more about system wide settings

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 System

Basics

To write a new system class you have to extend the CodeCoupler class System:

1
2
3
4
5
6
7
import { System } from "@codecoupler/cc-ui";
export default class extends System {
  //All members here are optional
  async init() {}
  async boot() {}
  async start() {}
}

Initialization and Starting Process

flowchart TB

  subgraph S1 [ ]
    S1A["Init Container<br>See 'DOM Layout'"] --> S1C
    S1C[Block System] --> S1D
    S1D[Initialize Application Registry]
  end

  S1D --> A
  A[Execute `init` Method] --> S2AA
  style A color:#000,fill:#ffc929,stroke:#333,stroke-width:4px

  subgraph S2 [ ]
    S2AA["Set Language (experimential)"] --> S2A
    S2A[Preload `custom` Assets] --> S2B
    S2B[Authenticate User] --> S2C
    S2C[Preload `auth` Assets] --> S2D
    S2D[Preload `core` Assets] --> S2E
    S2E[Unblock System]
  end

  S2E --> G
  G[Execute `boot` Method] --> S3A
  style G color:#000,fill:#ffc929,stroke:#333,stroke-width:4px

  subgraph S3 [ ]
    S3A[Load Stages] --> S3B
    S3B[Start Last Application or from Url]
  end

  S3B --> H
  H[Execute `start` Method] --> I
  style H color:#000,fill:#ffc929,stroke:#333,stroke-width:4px

  I[System is initialized]

Keep the following in mind

  • Do not load stages in the init method. Because of the blocking layer of the system this will not work.
  • Predefined stages will be loaded after the boot method. So do not load applications in the boot method. s The user authentication has its own lifecycle:

TODO

The following section is not yet complete

The Authentication have its own workflow:

  1. Get current user from authentication module
  2. Request login if permissions are required and if no current user authenticated.
  3. Request login and show message if permissions are required and if current user do not have sufficient permission.
  4. Loop this steps until all requirements are met.

DOM Layout

After starting a system the container will be emptied and the container will be set as root and current stage. To the container all stage styles are set.

┌─────────────────────────────────────────────────────────────┐
│  container                                                  │
│  Accessible over this.env.start.stage.element or $element   │
│                                                             │
│  position: absolute | relative | fixed (Default: relative)  │
│  isolation: isolate                                         │
│  overflow: hidden                                           │
└─────────────────────────────────────────────────────────────┘

In the case that the container is the body or the html element a new div will be added to the body, and all elements gets the style height:100%. This div will become the new container.

This additional div is needed, because the container is the root stage. And some of the stage styles do not work if they will be set for the body element. As a result, e.g. the position of the bootstrap tooltips cannot be calculated correctly.

┌───────────────────────────────────────────────────────────────────┐
│  body                                                             │
│  ┌─────────────────────────────────────────────────────────────┐  │
│  │  div (new container)                                        │  │
│  |  Accessible over this.env.start.stage.element or $element   │  |
│  │                                                             │  │
│  │  position: absolute | relative | fixed (Default: relative)  │  │
│  │  isolation: isolate                                         │  │
│  │  overflow: hidden                                           │  │
│  └─────────────────────────────────────────────────────────────┘  │
└───────────────────────────────────────────────────────────────────┘

What's next

You can acces the container among other environment variables through the variable this.env. But changes to this element should only be made with great care.

The system is not intended to provide the user with an interface or to make changes to it. A system is normally filled via stages and applications.

Reference

In addition to the common instance members described in the base classes Component and Stageable a system has the following:

Instance Getter

auth

Access the authentication module to login, logout and retrieve user informations.

login(message)

Call the authentication application which blocks the system and wait for entering credentials.