Skip to content

Special Levels: Multiple Modal Applications

What are we learning here?

  • Blocking stages will show only the fronted component

The stage block is a, so named blocking stage, like the stage error that we will explore soon. These blocking stages have some special features. The first one is that in these stages only one component will be visible.

As we know stages will already hide unfronted components if their position is not absolute or fixed. But in blocking stages all unfronted components will be hidden, regardless of it's position. Thus also all application components.

Let's add one more button into our HTML structure:

src/demo/components/loading-components/index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  Modal
  <button class="btn btn-xs btn-info" data-role="modalApp">
    <i style="pointer-events: none" class="fas fa-check-circle"></i>
  </button>
  <button class="btn btn-xs btn-info" data-role="modalMultiApp">
    <i style="pointer-events: none" class="fas fa-play-circle"></i>
  </button>
</div>
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  Hint
  <button class="btn btn-xs btn-info" data-role="hintInfo">
    <i style="pointer-events: none" class="fas fa-info-circle"></i>
  </button>
  <button class="btn btn-xs btn-success" data-role="hintSuccess">
    <i style="pointer-events: none" class="fas fa-check-circle"></i>
  </button>
  <button class="btn btn-xs btn-danger" data-role="hintError">
    <i style="pointer-events: none" class="fas fa-exclamation-circle"></i>
  </button>
</div>
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  Note
  <button class="btn btn-xs btn-info" data-role="hintInfoP">
    <i style="pointer-events: none" class="fas fa-info-circle"></i>
  </button>
  <button class="btn btn-xs btn-success" data-role="hintSuccessP">
    <i style="pointer-events: none" class="fas fa-check-circle"></i>
  </button>
  <button class="btn btn-xs btn-danger" data-role="hintErrorP">
    <i style="pointer-events: none" class="fas fa-exclamation-circle"></i>
  </button>
</div>
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  Splash
  <button class="btn btn-xs btn-info" data-role="hintSplash">
    <i style="pointer-events: none" class="fas fa-exclamation-circle"></i>
  </button>
</div>
<div class="border rounded d-inline-block p-1 mr-2 my-1 bg-white text-dark">
  App
  <button class="btn btn-xs btn-info" data-role="appNoId">
    <i style="pointer-events: none" class="fas fa-times-circle"></i>
  </button>
  <button class="btn btn-xs btn-info" data-role="appId">
    <i style="pointer-events: none" class="pe-none fas fa-check-circle"></i>
  </button>
</div>

Before we add the handler we will write the function in a separate file, because it is a little longer:

src/demo/components/loading-components/modal-multi-app.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
25
26
27
28
29
export default async function modalMultiApp(target, Mockup) {
  let firstApp = await target.getStage("root").load({
    component: Mockup,
    id: "first-app",
    level: "block",
    options: {
      "@codecoupler": {
        panel: { position: "left-center left-center 70px" }
      }
    }
  });
  await new Promise((r) => setTimeout(() => r(), 2000));
  let secondApp = await target.getStage("root").load({
    component: Mockup,
    id: "second-app",
    level: "block",
    options: {
      "@codecoupler": {
        panel: { position: "right-center right-center -70px" }
      }
    }
  });
  await new Promise((r) => setTimeout(() => r(), 2000));
  firstApp.front();
  await new Promise((r) => setTimeout(() => r(), 2000));
  firstApp.destroy();
  await new Promise((r) => setTimeout(() => r(), 2000));
  secondApp.destroy();
}

And call the function in a handler:

src/demo/components/loading-components/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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import { Canvas, Hint } from "@codecoupler/cc-ui";
import Mockup from "../../apps/mockup";
import { toRaw } from "vue";
import template from "./index.html";
import modalMultiApp from "./modal-multi-app";
export default class extends Canvas {
  static defaults = { target: null };
  async start() {
    this.element.innerHTML = template;
    this.element.addEventListener("click", (e) => {
      if (e.target.dataset.role) this[e.target.dataset.role]();
    });
    this.target = toRaw(this.options.target) ?? this.env.parent;
  }
  modalMultiApp() {
    modalMultiApp(this.target, Mockup);
  }
  modalApp() {
    this.target.getStage("root").load({ component: Mockup, level: "block" });
  }
  hintInfo() {
    this.target.getStage("root").load(Hint, { type: "info", text: "Hint!" });
  }
  hintSuccess() {
    this.target.hint("success", "Hint!");
  }
  hintError() {
    this.target.hint("error", "Hint!");
  }
  hintInfoP() {
    this.target.hint("info-permanent", "Permanent Hint!");
  }
  hintSuccessP() {
    this.target.hint("success-permanent", "Permanent Hint!");
  }
  hintErrorP() {
    this.target.hint("error-permanent", "Permanent Hint!");
  }
  async hintSplash() {
    let splash = await this.target.hint("splash", "Splash!");
    for (let x = 0; x <= 100; x += 25) {
      await new Promise((r) => setTimeout(() => r(), 750));
      splash.text = `Please Wait\n${x}% Progress`;
    }
    await new Promise((r) => setTimeout(() => r(), 2000));
    splash.destroy();
  }
  appNoId() {
    this.target.stage.load(Mockup);
  }
  appId() {
    this.target.stage.load(Mockup, "fixed-id");
  }
}

Now click on the new button, sit back and enjoy the show:

  • "first-app" will be loaded. As a result, the widget will be blocked.
  • After 2 seconds the "second-app" will be loaded. As a result, "first-app" is hidden.
  • After 2 seconds the "first-app" will be fronted. As a result, "second-app" is hidden.
  • After 2 seconds the "second-app" will be destroyed. As a result, "first-app" appears.
  • After 2 seconds the "first-app" will be destroyed. As a result, the widget will be unblocked.

Furthermore we have placed the application panels to the left and right side. This can be done with the namespaced options located under @codecoupler.panel.