Skip to content

Layout

Now let's use another property named widget. Widgets will soon be explained in more detail. But now we will use a built-in widget called "Layout"

apps/testing-buttons.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
import { Application, Layout } from "@codecoupler/cc-ui";
import buttons from "./custom-buttons";
import MyFirstWidget from "../widgets/my-first-widget.js";
export default class extends Application {
  static ui = {
    name: "Testing Buttons",
    iconHtml: '<i class="fas fa-seedling fa-fw"></i>'
  };
  async init() {
    let layout = {
      root: {
        type: "widget",
        widget: MyFirstWidget,
        options: {
          text: "Hallo Everyone"
        }
      }
    };
    await super.init({
      panel: {
        panelSize: "820 600",
        headerTitle: "My First Title",
        footerToolbar:
          '<i class="far fa-hand-point-right mx-1"></i> [blocks][hints][alerts][close]'
      },
      buttons: buttons,
      widget: {
        widget: Layout,
        options: layout
      }
    });
  }
}

You see now a new property widget which loads a widget named Layout into the content area of the application panel. The options have been moved to a separate variable layout.

In the options, starting with a root you can split the main content area of the application into parts. Into this parts you can load widgets. In this example we have only one area defined and load the widget MyFirstWidget. So before you can compile this application we need to create of course the widget:

widgets/my-first-widget.js

1
2
3
4
5
6
7
8
9
import { Widget } from "@codecoupler/cc-ui";
export default class extends Widget {
  async init(env, options) {
    env.$element.html(`
      <h1>My First Widget!</h1>
      <p>Text: ${options.text}</p>
    `);
  }
}

For now it is only important to know, that you have an init method where you receive with env.element (HTMLElement) or env.$element (jQuery Object) the target element what you can fill with live. In options you receive the object you have defined in your application with the property options.

Starting the application you will see your first widget running. Not very spectacular, so lets define a second area:

apps/testing-buttons.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
import { Application, Layout } from "@codecoupler/cc-ui";
import buttons from "./custom-buttons";
import MyFirstWidget from "../widgets/my-first-widget.js";
export default class extends Application {
  static ui = {
    name: "Testing Buttons",
    iconHtml: '<i class="fas fa-seedling fa-fw"></i>'
  };
  async init() {
    let layout = {
      root: {
        type: "row",
        content: [
          {
            type: "widget",
            widget: MyFirstWidget,
            options: {
              text: "Hallo Everyone"
            }
          },
          {
            type: "widget",
            widget: MyFirstWidget,
            options: {
              text: "How are you?"
            }
          }
        ]
      }
    };
    await super.init({
      panel: {
        panelSize: "820 600",
        headerTitle: "My First Title",
        footerToolbar:
          '<i class="far fa-hand-point-right mx-1"></i> [blocks][hints][alerts][close]'
      },
      buttons: buttons,
      widget: {
        widget: Layout,
        options: layout
      }
    });
  }
}

We have used the same widget for a second area just with another parameter value defined in text. Starting you application you see two areas which can be resized.

Now let's go one step further to illustrate how you can use the types row, column and component and how they can be nested:

apps/testing-buttons.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
55
56
57
import { Application, Layout } from "@codecoupler/cc-ui";
import buttons from "./custom-buttons";
import MyFirstWidget from "../widgets/my-first-widget.js";
export default class extends Application {
  static ui = {
    name: "Testing Buttons",
    iconHtml: '<i class="fas fa-seedling fa-fw"></i>'
  };
  async init() {
    let layout = {
      root: {
        type: "row",
        content: [
          {
            type: "widget",
            widget: MyFirstWidget,
            options: {
              text: "Hallo Everyone"
            }
          },
          {
            type: "column",
            content: [
              {
                type: "widget",
                widget: MyFirstWidget,
                options: {
                  text: "How are you?"
                }
              },
              {
                type: "widget",
                widget: MyFirstWidget,
                options: {
                  text: "I'm fine, thanks!"
                }
              }
            ]
          }
        ]
      }
    };
    await super.init({
      panel: {
        panelSize: "820 600",
        headerTitle: "My First Title",
        footerToolbar:
          '<i class="far fa-hand-point-right mx-1"></i> [blocks][hints][alerts][close]'
      },
      buttons: buttons,
      widget: {
        widget: Layout,
        options: layout
      }
    });
  }
}

Resizing the areas is nice, but what about draging them around and rearange them? No problem. You have to insert a new property header into the layout object where you can configure the layout. We use now show and set this to true. Please mention that we have set an attribute title for every widget. You will understand why, soon:

apps/testing-buttons.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
55
56
57
58
59
60
61
62
63
import { Application, Layout } from "@codecoupler/cc-ui";
import buttons from "./custom-buttons";
import MyFirstWidget from "../widgets/my-first-widget.js";
export default class extends Application {
  static ui = {
    name: "Testing Buttons",
    iconHtml: '<i class="fas fa-seedling fa-fw"></i>'
  };
  async init() {
    let layout = {
      header: {
        show: true
      },
      root: {
        type: "row",
        content: [
          {
            type: "widget",
            title: "Number 1",
            widget: MyFirstWidget,
            options: {
              text: "Hallo Everyone"
            }
          },
          {
            type: "column",
            content: [
              {
                type: "widget",
                title: "Number 2",
                widget: MyFirstWidget,
                options: {
                  text: "How are you?"
                }
              },
              {
                type: "widget",
                title: "Number 3",
                widget: MyFirstWidget,
                options: {
                  text: "I'm fine, thanks!"
                }
              }
            ]
          }
        ]
      }
    };
    await super.init({
      panel: {
        panelSize: "820 600",
        headerTitle: "My First Title",
        footerToolbar:
          '<i class="far fa-hand-point-right mx-1"></i> [blocks][hints][alerts][close]'
      },
      buttons: buttons,
      widget: {
        widget: Layout,
        options: layout
      }
    });
  }
}

Now you can drag the areas around, rearange the layout and even maximize single areas. Let's do one more thing with the layout before we go further. Beside row and column you can define a stack:

apps/testing-buttons.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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import { Application, Layout } from "@codecoupler/cc-ui";
import buttons from "./custom-buttons";
import MyFirstWidget from "../widgets/my-first-widget.js";
export default class extends Application {
  static ui = {
    name: "Testing Buttons",
    iconHtml: '<i class="fas fa-seedling fa-fw"></i>'
  };
  async init() {
    let layout = {
      header: {
        show: true
      },
      root: {
        type: "row",
        content: [
          {
            type: "widget",
            title: "Number 1",
            widget: MyFirstWidget,
            options: {
              text: "Hallo Everyone"
            }
          },
          {
            type: "column",
            content: [
              {
                type: "widget",
                title: "Number 2",
                widget: MyFirstWidget,
                options: {
                  text: "How are you?"
                }
              },
              {
                type: "stack",
                content: [
                  {
                    type: "widget",
                    title: "Number 3",
                    widget: MyFirstWidget,
                    options: {
                      text: "I'm fine, thanks!"
                    }
                  },
                  {
                    type: "widget",
                    title: "Number 4",
                    widget: MyFirstWidget,
                    options: {
                      text: "That is amazing!"
                    }
                  }
                ]
              }
            ]
          }
        ]
      }
    };
    await super.init({
      panel: {
        panelSize: "820 600",
        headerTitle: "My First Title",
        footerToolbar:
          '<i class="far fa-hand-point-right mx-1"></i> [blocks][hints][alerts][close]'
      },
      buttons: buttons,
      widget: {
        widget: Layout,
        options: layout
      }
    });
  }
}

Now you can see the tabs "Number 3" and "Number 4" are "stacked".

Info

To build the layout the library GoldenLayout in version 2 will be used. The properties widget and options used in CodeCoupler are just alias names for componentType amd componentState. And type = "widget" is just an alias for type = "component".

The layout will always be loaded into the content area of your application. But what if you need to have a fixed area which cannot be resized?

For this case you have to preload a static HTML structure and define the target container in which a widget have to be loaded. The structure you define in the property panel.content (or panel.contentAjax / panel.contentFetch which will load the content from external sources). The target element in which the layout have to be loaded must have the attribute data-role="widget".

The target container in which the layout widget will be loaded will always emptyed before creating the layout. So if you specify just panel.content and no element with the attribute data-role="widget" it make no sense. The content would be wiped out.

apps/testing-buttons.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
import { Application, Layout } from "@codecoupler/cc-ui";
import buttons from "./custom-buttons";
import MyFirstWidget from "../widgets/my-first-widget.js";
export default class extends Application {
  static ui = {
    name: "Testing Buttons",
    iconHtml: '<i class="fas fa-seedling fa-fw"></i>'
  };
  async init() {
    let layout = {
      header: {
        show: true
      },
      root: {
        /* .... left out for the sake of simplicity .... */
      }
    };
    await super.init({
      panel: {
        panelSize: "820 600",
        headerTitle: "My First Title",
        footerToolbar:
          '<i class="far fa-hand-point-right mx-1"></i> [blocks][hints][alerts][close]',
        content: `
          <div class="d-flex flex-column h-100">
          <div class="bg-info text-center text-white py-3">+++ Banner +++ Banner +++</div>
          <div class="flex-grow-1 position-relative" data-role="widget"></div>
          </div>
        `
      },
      buttons: buttons,
      widget: {
        widget: Layout,
        options: layout
      }
    });
  }
}

Now you see a banner on top of the layout which will always stay fixed in this position.

Update Layout Size

If you start building content after calling await super.init(...) it can be that the layout container gets smaller. In this case the layout will not get notified and you have to do it manually with:

this.layout.updateSize();

Back to top