Skip to content

System and Stages

System

Everything starts by initializing a container as a CodeCoupler System. Without any arguments the body will be used as container. Let's start with our main entry point index.js:

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { System } from "@codecoupler/cc-ui";
let system = new System();
system.initialized
  .then((system) => {
    console.info("System is Ready!", system.id);
  })
  .catch((e) => {
    console.error(e);
    if (!e.systemBlocked)
      document.body.innerHTML = "Oops, Something went wrong!";
  });

You can specify your own container with the argument property element, which value can be any HTMLElement, jQuery Object or Selector String:

Initialize in specific element

1
let system = new System(element);

Stages

The container is now the current stage where different applications can be started. If you would start an application it will always maximize to the whole stage. If you start the application with a classic window container, you can move them only within the limits of the current stage.

Before you start an application you can divide the current stage into different areas and define a new stage which is just a part of the container:

After initialization:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
+---------------------------+
|                           |
|    Your container         |
|    at beginning           |
|                           |
|    This is the main       |
|    stage where all apps   |
|    will be started        |
|                           |
|                           |
+---------------------------+

After adding a new stage object:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
+---+-----------------------+
|   |                       |
|   |  <- Define here a     |
|   |     sidebar container |
|   |                       |
|   |  The remaining space  |
|   |  is your new main     |
|   |  stage where all apps |
|   |  will be started      |
|   |                       |
+---+-----------------------+

Stages can be nested. It means that after you add your first stage, you can add another one which will divide the main stage again.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
+---+-----------------------+
|   |                       |
|   |-----------------------|
|   |  ^ Define a new header|
|   |                       |
|   |  The remaining space  |
|   |  is your new main     |
|   |  stage where all apps |
|   |  will be started      |
|   |                       |
+---+-----------------------+

And so on.

To define a stage, you have to write a class which derives from the CodeCoupler class Stage. You have to proivide a method async init which get the current stage and can modify that as requested.

The resulting structure only has to meet two requirements:

  1. The new stage container element must have set the attribute data-role="cc-stage".
  2. The new stage container element must have the style attribute position set to absolute, relative or fixed.

Writing own Stage

Here is an absolut minimalistic approach adding a header using Bootstrap utility classes. Put this into an own file in a subfolder stages:

stages/header.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import { Stage } from "@codecoupler/cc-ui";
export default class extends Stage {
  async init(env, options) {
    env.$element.replaceWith(`
      <div class="d-flex flex-column h-100">
        <div class="bg-secondary text-white">
          Header with option: ${options.header}
        </div>
        <div class="flex-grow-1 position-relative" data-role="cc-stage">
        </div>
      </div>
    `);
  }
}

The only important things you have to know for now is that in env.$element you can access the current stage element as a jQuery object and with options you will get an object with all the options provided by the caller. In this case we expect a property named header.

Let's start writing our initial file index.js. You can add a stage right after the initialization finished:

Initialze Stage after System Initialization

1
2
3
4
5
6
7
8
system.initialized.then(() => {
  system.stage({
    stage: HeaderStage,
    options: { header: "Test" }
  }).initialized.then(() => {
    //Here we go
  });
});

But it is better to integrate the staging into the initialization process as an configuration option:

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import { System } from "@codecoupler/cc-ui";
import HeaderStage from "./stages/header.js";
let system = new System({
  stages: [
    {
      stage: HeaderStage,
      options: { header: "Test" }
    }
  ]
});
system.initialized
  .then((system) => {
    console.info("System is Ready!", system.id);
  })
  .catch((e) => {
    console.error(e);
    if (!e.systemBlocked)
      document.body.innerHTML = "Oops, Something went wrong!";
  });

The advantage integrating into the initializing process is that the system is blocked until the initialization finishes. This blocking will then continue until each stage is ready.

Using built-in Stage Sidebar

Our example is of course not very beautiful. For an easy start CodeCoupler provides a stage named Sidebar which have many options and display a sidebar with icons on the left side.

Let's load the sidebar right before our header in our index.js. As you see the property stages is an array. So you can set multiple stages in there:

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { System, Sidebar } from "@codecoupler/cc-ui";
import HeaderStage from "./stages/header.js";
import apps from "./apps.js";
let system = new System({
  apps: apps,
  stages: [
    {
      stage: Sidebar
    },
    {
      stage: HeaderStage,
      options: { header: "Test" }
    }
  ]
});
system.initialized
  .then((system) => {
    console.info("System is Ready!", system.id);
  })
  .catch((e) => {
    console.error(e);
    if (!e.systemBlocked)
      document.body.innerHTML = "Oops, Something went wrong!";
  });

And create this file which is also needed:

apps.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
export default function() {
  return [
    {
      ui: {
        iconHtml: '<i class="far fa-smile fa-fw"></i>',
        name: "Just an Alert"
      },
      app: () => {
        alert("Hello World");
      }
    }
  ];
}

As you can see we have created a file named apps.js where we can define so named "applications". As this array can get very long and in many cases need to be dynamically defined, you will understand later that this is a good choice. These applications will be registered in the system via the property apps.

The Sidebar read all available applications from the system and display icons of each one.

If you run the code you should see a sidebar with an smiley icon and if you click on that you get an Hello World alert. Not really an application yet but a good starting point.