Click on badges to get to the code...
$ git clone http://learn.zone01dakar.sn/git/jefaye/bomberman-dom
$ cd bomberman-dom/.
├── public
│ ├── assets
│ │ ├── avatar
│ │ │ ├── actor.png
│ │ │ ├── ennemi.png
│ │ │ └── money.png
│ │ ├── bomb
│ │ │ └── bomb.png
│ │ ├── map
│ │ │ ├── bloc.png
│ │ │ └── mur.png
│ │ ├── soundEffect
│ │ │ ├── sound_bomb.mp3
│ │ │ └── title-screen.mp3
│ │ ├── bumberman.png
│ │ ├── images-removebg-preview.png
│ │ └── mainbg.jpeg
│ ├── src
│ │ ├── components
│ │ │ ├── avatar.js
│ │ │ ├── bomb.js
│ │ │ ├── grid.js
│ │ │ └── powerUp.js
│ │ ├── core
│ │ │ ├── node.js
│ │ │ ├── router.js
│ │ │ └── state.js
│ │ ├── interface
│ │ │ ├── barreScore.js
│ │ │ ├── menuPause.js
│ │ │ └── sound.js
│ │ ├── utils
│ │ │ └── viewport.js
│ │ └── app.js
│ ├── index.css
│ └── index.html
├── audit.todo
├── gitify.sh
├── go.mod
├── LICENSE
├── main.go
└── README.md
11 directories, 31 files
GEDOM is a framework-like tool that is meant to be used in any web application to simplify DOM Manipulation. It uses the concept of DOM Abstraction to create web components without having to use all those DOM methods. As an example, GEDOM will be use to create a basic TodoMVC web application.
The Virtual Node is a class that generates a component, given a 'properties' object as arguments.
Basically, the properties object would be in this configuration:
const properties = {
tag: /* HTML tag name (default: 'div') */ ,
attrs: {
// attribute: value
// ...
},
listeners: {
// event: callback function
// ...
},
children: [
// VirtualNode || Object || String
// ...
]
}Calling the render() method on an instance of a Virtual Node will create the element through the tag field value, then set attributes and listeners, then add all given children of one of these types:
virtual node
const TodoApp = new VirtualNode({
tag: "section",
attrs: {
class: "todoapp",
},
children: [todoHeader, todoMain, todoFooter],
});object
class TodoHeader extends VirtualNode {
constructor() {
super({
tag: "header",
attrs: {
class: "header",
},
children: [
{
tag: "h1",
children: ["todos"],
},
{
tag: "input",
attrs: {
class: "new-todo",
placeholder: "What needs to be done?",
autofocus: "",
},
listeners: {
onchange: (event) => {
if (event.target.value.trim() !== "") {
todoList.addTodo(event.target.value);
event.target.value = "";
}
},
},
},
],
});
}
}string
export default new VirtualNode({
tag: "footer",
attrs: {
class: "info",
},
children: [
{
tag: "p",
children: ["Double-click to edit a todo"],
},
{
tag: "p",
children: ["Created by the Todo01 team"],
},
{
tag: "p",
children: ["Part of ", new Link("https://todomvc.com/", "TodoMVC")],
},
],
});Finally, the VirtualNode class will returns the created element that can now be append to any element of the DOM.
The State of the application is set using an object that can contain any sort of data. The power of the state manager resides in the facts that it is the ONE source of truth for the entire application.
First, an instance of the State class is initialized with all data of the application that can be changed by the components logic.
const todoState = new State({
todos: [],
filter: "all",
counter: {
active: 0,
completed: 0,
},
});The subscribe() method will basically add any funtion, method or callback that needs to update one or more elements of the application.
todoState.subscribe(todoMain.toggleDisplay.bind(todoMain));
todoState.subscribe(todoFooter.toggleDisplay.bind(todoFooter));
todoState.subscribe(todoList.display.bind(todoList));
todoState.subscribe(clearCompleted.toggleDisplay.bind(clearCompleted));
todoState.subscribe(todoCount.refresh.bind(todoCount));Instead of changing the element directly, the modifications will be done in the State using the set() method.
The method contains a private method (#notify()) that will call all the subscribed functions, which will update all elements without needing to refresh the entire page/template.
todoState.set({
todos: todoState.current.todos.filter((todo) => !todo.state.completed),
counter: {
...todoState.current.counter,
completed: 0,
},
});Optionally, the set() method can take a callback as an argument for more complex operations.
The Router as the name implies is supposed to in conjunction with the State manager in order to determine which components will be rendered given the current URI of the address.
Once the router instance is created, the routes are registered using the add() method that takes the endpoint of the URL and the handler that basically apply the rendering of the allowed components.
const router = new Router();
router.add("/", () => {
todoState.set({ filter: "all" });
});
router.add("/active", () => {
todoState.set({ filter: "active" });
});
router.add("/completed", () => {
todoState.set({ filter: "completed" });
});Whenever the address changes, the router get the resulting URL and change the state of the application so it can take care of the rest.
The URL is supposed to be a hash link so it won't redirect to a different page while avoiding page reload.
classDiagram
class Avatar {
# nickname: String
+ lives: Integer
- speed: Integer
+ move(string direction) void
+ drop() void
+ struck() void
+ die() void
+ collect(PowerUp) void
# accelerate() void
# dualBomb() void
# hyperBomb() void
}
class Bomb {
+ bomber: String
# range: Integer
# countdown() void
- explode() void
+ amplify() void
}
class Brick {
+ destroyed() void
+ reveal() void
}
class PowerUp {
- type: String
+ boost() void
}
Avatar "1" --* "0..*" Bomb: drops
Avatar "1" --* "0..*" PowerUp: collects
Bomb "0..*" --* "0..*" Avatar: blows up
Bomb "1" --* "0..*" Brick: destroys
Brick "1" -- "1" PowerUp: reveals
PowerUp "0..*" --* "1" Avatar: boosts

