Our first widget does not do too much. Let's start writing a second widget explaining some details
and best practices.
We start writing three files:
widgets/testing-sizing.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 | import { Widget } from "@codecoupler/cc-ui";
import $ from "jquery";
//Write your stylesheet and your HTML code in separate files
import "./testing-sizing.css";
import widgetTemplate from "./testing-sizing.html";
export default class extends Widget {
#env;
#settings;
//Defaults which will applied on all instances
static defaults = {
text: "Default Text"
};
async init(env, options) {
//Some Best Practices
this.#env = env;
this.#settings = $.extend(true, {}, this.constructor.defaults, options);
this.#env.$element.addClass("testing-sizing");
this.#env.$element.html(widgetTemplate);
//Implement events if needed
// this.on("resize", () => {
// //Do something
// });
// this.on("destroy", () => {
// //Do something
// });
//Now write your code
this.#env.$element
.find("[data-role=more-text]")
.append(`<p>${this.#settings.text}</p>`);
this.#env.$element.find("[data-role=add-text]").on("click", () => {
this.#env.$element
.find("[data-role=more-text]")
.append(
"<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy<p>"
);
});
this.#env.$element.find("[data-role=block-info]").on("click", () => {
this.tryBlock("info", "Block the Widget for 2 seconds");
});
this.#env.$element.find("[data-role=block-error]").on("click", () => {
this.tryBlock("error", "Block the Widget for 2 seconds");
});
this.#env.$element.find("[data-role=hint-error]").on("click", () => {
this.hint("error", "Error");
});
this.#env.$element.find("[data-role=hint-info]").on("click", () => {
this.hint("info", "Info");
});
this.#env.$element.find("[data-role=hint-success]").on("click", () => {
this.hint("success", "Success");
});
}
//Helper
tryBlock(type, text) {
this.block(type, text);
setTimeout(() => {
this.unblock();
}, 2000);
}
}
|
widgets/testing-sizing.css
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 | .testing-sizing {
padding: 20px;
position: relative;
& .arrow {
opacity: 0.5;
position: absolute;
}
& .left {
left: 0;
top: 40px;
}
& .right {
right: 0;
top: 40px;
}
& .up {
left: 50%;
transform: translate(-50%, 0);
top: 0;
}
& .down {
left: 50%;
transform: translate(-50%, 0);
bottom: 0;
}
}
|
widgets/testing-sizing.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | <div class="arrow left"><i class="fas fa-chevron-circle-left"></i></div>
<div class="arrow right"><i class="fas fa-chevron-circle-right"></i></div>
<div class="arrow up"><i class="fas fa-chevron-circle-up"></i></div>
<div class="arrow down"><i class="fas fa-chevron-circle-down"></i></div>
<div class="container">
<h1>My Second Widget!</h1>
<p>
Let's write some text:
<button data-role="add-text" class="btn btn-primary">Write!</button>
</p>
<p>
Let's try blocking:
<button data-role="block-info" class="btn btn-info">Info</button>
<button data-role="block-error" class="btn btn-danger">Error</button>
</p>
<p>
Let's try hints:
<button data-role="hint-info" class="btn btn-info">Info</button>
<button data-role="hint-error" class="btn btn-danger">Error</button>
<button data-role="hint-success" class="btn btn-success">Success</button>
</p>
<div data-role="more-text"></div>
</div>
|
Some of the best practices explained:
- We have separated code, layout and style as it should be.
- We added a unique classname to the widget container so we have a scope in which we can define our
styles.
- We have defined a static member
defaults
which will always used to merge the options with. The
end user can manipulate this static member and define his own default values which will used for
all new instances. The widget implementation will use the merged options from the private variable
this.#settings
.
- The argument
env
will be saved into the private variable this.#env
.
Let's replace in our application one of the widgets with our new one:
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
77 | import { Application, Layout } from "@codecoupler/cc-ui";
import buttons from "./custom-buttons";
import MyFirstWidget from "../widgets/my-first-widget.js";
import TestingSizingWidget from "../widgets/testing-sizing";
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: TestingSizingWidget,
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 start the application to examine the following features.
Resizing
If you run the application you will see four arrows. They point to the border of your widget
container.
The first thing you will notice is that the container of the widget is always stretched to 100% of
width and height, even when you resize the application.
Now click on the button "Write!" multiple times. You will see the down arrow will disapear because
your widget is now bigger as it's container. You can now scroll down and a scrollbar will appear.
All this logic will be done automatically. Because of not using the browser scrollbar you can use
always the full area of the container for your widget.
Block and Hints
The other buttons shows other built in functionality. You can block the widget or show hints in
different themes.