First commit
This commit is contained in:
69
static/css/main.css
Executable file
69
static/css/main.css
Executable file
@ -0,0 +1,69 @@
|
||||
|
||||
|
||||
/* Global styles */
|
||||
:root {
|
||||
--color__background: #f6f4f3;
|
||||
--color__gray: #ccc;
|
||||
--color__black: #000;
|
||||
--color__active: #00a0ff;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: var(--color__background);
|
||||
}
|
||||
|
||||
/* General classes for small components */
|
||||
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
padding: 1rem 0;
|
||||
max-width: 40rem;
|
||||
}
|
||||
|
||||
.nav__ul {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav__link.active {
|
||||
color: var(--color__active);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: var(--color__gray);
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
filter: brightness(90%);
|
||||
}
|
||||
|
||||
.input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
padding: .5rem;
|
||||
resize: none;
|
||||
border: 1px solid var(--color__gray);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 1rem;
|
||||
text-align: center;
|
||||
}
|
28
static/js/controllers/add_form_controller.js
Normal file
28
static/js/controllers/add_form_controller.js
Normal file
@ -0,0 +1,28 @@
|
||||
import { Controller } from "../vendors/stimulus.js"
|
||||
import { sendData } from "../webSocketsCli.js"
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
static targets = [ "author", "text" ]
|
||||
|
||||
/**
|
||||
* Send new message
|
||||
* @param {Event} event
|
||||
* @return {void}
|
||||
*/
|
||||
add(event) {
|
||||
event.preventDefault();
|
||||
// Prepare the information we will send
|
||||
const newData = {
|
||||
"action": "add message",
|
||||
"data": {
|
||||
"author": this.authorTarget.value,
|
||||
"text": this.textTarget.value
|
||||
}
|
||||
};
|
||||
// Send the data to the server
|
||||
sendData(newData, window.myWebSocket);
|
||||
// Clear message form
|
||||
this.textTarget.value = "";
|
||||
}
|
||||
}
|
116
static/js/controllers/message_controller.js
Normal file
116
static/js/controllers/message_controller.js
Normal file
@ -0,0 +1,116 @@
|
||||
import { Controller } from "../vendors/stimulus.js"
|
||||
import { sendData } from "../webSocketsCli.js"
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
static targets = [ "item", "paginator" ]
|
||||
|
||||
connect() {
|
||||
this.enableInfiniteScroll();
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTIONS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Switches to the next page when the last message is displayed.
|
||||
*/
|
||||
enableInfiniteScroll() {
|
||||
const lastMessage = this.itemTargets.at(-1);
|
||||
// Turn the page when the last message is displayed.
|
||||
const observerLastMessage = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
if (!this.isLastPage()) this.goToNextPage();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
observerLastMessage.observe(lastMessage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get current page stored in #paginator as dataset
|
||||
* @returns {number}
|
||||
*/
|
||||
getCurrentPage() {
|
||||
return parseInt(this.paginatorTarget.dataset.page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are on the last page
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isLastPage() {
|
||||
return parseInt(this.paginatorTarget.dataset.totalPages) === this.getCurrentPage();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Switch to the next page
|
||||
* @param {Event} event
|
||||
* @return {void}
|
||||
*/
|
||||
goToNextPage(event) {
|
||||
// Prepare the information we will send
|
||||
const newData = {
|
||||
"action": "list messages",
|
||||
"data": {
|
||||
"page": this.getCurrentPage() + 1,
|
||||
}
|
||||
};
|
||||
// Send the data to the server
|
||||
sendData(newData, myWebSocket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the update form
|
||||
* @param {Event} event
|
||||
* @return {void}
|
||||
*/
|
||||
displayUpdateForm(event) {
|
||||
const message = {
|
||||
"action": "open edit page",
|
||||
"data": {
|
||||
"id": event.target.dataset.id
|
||||
}
|
||||
};
|
||||
sendData(message, window.myWebSocket);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update message
|
||||
* @param {Event} event
|
||||
* @return {void}
|
||||
*/
|
||||
updateMessage(event) {
|
||||
event.preventDefault();
|
||||
const message = {
|
||||
"action": "update message",
|
||||
"data": {
|
||||
"id": event.target.dataset.id,
|
||||
"author": event.target.querySelector("#message-form__author--update").value,
|
||||
"text": event.target.querySelector("#message-form__text--update").value
|
||||
}
|
||||
};
|
||||
sendData(message, myWebSocket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete message
|
||||
* @param {Event} event
|
||||
* @return {void}
|
||||
*/
|
||||
deleteMessage(event) {
|
||||
const message = {
|
||||
"action": "delete message",
|
||||
"data": {
|
||||
"id": event.target.dataset.id
|
||||
}
|
||||
};
|
||||
sendData(message, window.myWebSocket);
|
||||
}
|
||||
}
|
28
static/js/controllers/navbarController.js
Normal file
28
static/js/controllers/navbarController.js
Normal file
@ -0,0 +1,28 @@
|
||||
import { Controller } from "../vendors/stimulus.js"
|
||||
import { sendData } from "../webSocketsCli.js"
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
static targets = [ "page" ]
|
||||
|
||||
/**
|
||||
* Send new message
|
||||
* @param {Event} event
|
||||
* @return {void}
|
||||
*/
|
||||
add(event) {
|
||||
event.preventDefault();
|
||||
// Prepare the information we will send
|
||||
const newData = {
|
||||
"action": "add message",
|
||||
"data": {
|
||||
"author": this.authorTarget.value,
|
||||
"text": this.textTarget.value
|
||||
}
|
||||
};
|
||||
// Send the data to the server
|
||||
sendData(newData, window.myWebSocket);
|
||||
// Clear message form
|
||||
this.textTarget.value = "";
|
||||
}
|
||||
}
|
25
static/js/controllers/update_form_controller.js
Normal file
25
static/js/controllers/update_form_controller.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { Controller } from "../vendors/stimulus.js"
|
||||
import { sendData } from "../webSocketsCli.js"
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
static targets = [ "author", "text" ]
|
||||
|
||||
/**
|
||||
* Update message
|
||||
* @param {Event} event
|
||||
* @return {void}
|
||||
*/
|
||||
update(event) {
|
||||
event.preventDefault();
|
||||
const message = {
|
||||
"action": "update message",
|
||||
"data": {
|
||||
"id": event.target.dataset.id,
|
||||
"author": this.authorTarget.value,
|
||||
"text": this.textTarget.value
|
||||
}
|
||||
};
|
||||
sendData(message, myWebSocket);
|
||||
}
|
||||
}
|
15
static/js/main.js
Executable file
15
static/js/main.js
Executable file
@ -0,0 +1,15 @@
|
||||
import {connect, startEvents} from './webSocketsCli.js';
|
||||
import { Application } from "./vendors/stimulus.js"
|
||||
import navbarController from "./controllers/navbar.js"
|
||||
/*
|
||||
INITIALIZATION
|
||||
*/
|
||||
|
||||
// WebSocket connection
|
||||
connect();
|
||||
startEvents();
|
||||
|
||||
// Stimulus
|
||||
window.Stimulus = Application.start();
|
||||
// Register all controllers
|
||||
Stimulus.register("navbar", navbarController);
|
1944
static/js/vendors/stimulus.js
vendored
Normal file
1944
static/js/vendors/stimulus.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
50
static/js/webSocketsCli.js
Normal file
50
static/js/webSocketsCli.js
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
FUNCTIONS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Connect to WebSockets server (SocialNetworkConsumer)
|
||||
* @param {string} url - WebSockets server url
|
||||
* @return {WebSocket}
|
||||
*/
|
||||
export function connect(url=`${document.body.dataset.scheme === 'http' ? 'ws' : 'wss'}://${ document.body.dataset.host }/ws/social-network/`) {
|
||||
window.myWebSocket = new WebSocket(url);
|
||||
return window.myWebSocket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data to WebSockets server
|
||||
* @param {string} message
|
||||
* @param {WebSocket} webSocket
|
||||
* @return {void}
|
||||
*/
|
||||
export function sendData(message, webSocket) {
|
||||
webSocket.send(JSON.stringify(message));
|
||||
}
|
||||
|
||||
/*
|
||||
EVENTS
|
||||
*/
|
||||
|
||||
/**
|
||||
* On WebSockets server connection
|
||||
* @param {WebSocket} webSocket
|
||||
* @return {void}
|
||||
*/
|
||||
export function startEvents(webSocket=window.myWebSocket) {
|
||||
// Event when a new message is received by WebSockets
|
||||
webSocket.addEventListener("message", (event) => {
|
||||
// Parse the data received
|
||||
const data = JSON.parse(event.data);
|
||||
// Renders the HTML received from the Consumer
|
||||
const newFragment = document.createRange().createContextualFragment(data.html);
|
||||
const target = document.querySelector(data.selector);
|
||||
if (data.append) {
|
||||
target.appendChild(newFragment);
|
||||
} else {
|
||||
target.replaceChildren(newFragment);
|
||||
}
|
||||
// Update URL
|
||||
history.pushState({}, '', data.url)
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user