diff --git a/Projet/src/main/java/projet/Bloc.java b/Projet/src/main/java/projet/Bloc.java
index a633da1..3ef639e 100644
--- a/Projet/src/main/java/projet/Bloc.java
+++ b/Projet/src/main/java/projet/Bloc.java
@@ -197,7 +197,8 @@ public class Bloc extends ParamBD {
}
}
- public static void supprimerBloc(int idBloc, int idU) {
+ public static boolean supprimerBloc(int idBloc, int idU) {
+ boolean reponse = false;
try {
Connection connexion = DriverManager.getConnection(bdURL, bdLogin, bdPassword);
String sql = " DELETE FROM bloc"
@@ -209,8 +210,32 @@ public class Bloc extends ParamBD {
pst.setInt(2, idU);
pst.executeUpdate();
+ pst.close();
+ connexion.close();
+ reponse = true;
} catch (SQLException e) {
e.printStackTrace();
}
+
+ return reponse;
+ }
+
+ public static void miseAJourOrdreBloc(int idBloc, int ordre) {
+ try {
+ Connection connexion = DriverManager.getConnection(bdURL, bdLogin, bdPassword);
+ String sql = " UPDATE bloc"
+ + " SET ordre = ?"
+ + " WHERE id = ?"
+ + ";";
+ PreparedStatement pst = connexion.prepareStatement(sql);
+ pst.setInt(1, ordre);
+ pst.setInt(2, idBloc);
+ pst.executeUpdate();
+
+ pst.close();
+ connexion.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
}
}
diff --git a/Projet/src/main/java/projet/SauvegarderOrdre.java b/Projet/src/main/java/projet/SauvegarderOrdre.java
new file mode 100644
index 0000000..aa0a567
--- /dev/null
+++ b/Projet/src/main/java/projet/SauvegarderOrdre.java
@@ -0,0 +1,86 @@
+package projet;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+
+
+@WebServlet("/SauvegarderOrdre")
+public class SauvegarderOrdre extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+
+
+ public SauvegarderOrdre() {
+ super();
+ }
+
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ HttpSession session = request.getSession();
+ Utilisateur u = (Utilisateur) session.getAttribute("utilisateur");
+
+ if(u != null) {
+ response.sendRedirect("AfficherPage");
+ }else {
+ response.sendRedirect("/Projet/");
+ }
+ }
+
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+
+ HttpSession session = request.getSession();
+ Utilisateur u = (Utilisateur) session.getAttribute("utilisateur");
+
+ if (u == null) {
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.getWriter().write("{\"error\": \"Utilisateur non connecté\"}");
+ return;
+ }
+
+ try (BufferedReader reader = request.getReader()) {
+ StringBuilder json = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ json.append(line);
+ }
+
+ JsonReader jsonReader = Json.createReader(new StringReader(json.toString()));
+ JsonArray jsonArray = jsonReader.readArray();
+
+ for (int i = 0; i < jsonArray.size(); i++) {
+ JsonObject jsonObject = jsonArray.getJsonObject(i);
+
+ if (!jsonObject.containsKey("id") || !jsonObject.containsKey("ordre")) {
+ continue;
+ }
+
+ int id = Integer.parseInt(jsonObject.getString("id"));
+ int ordre = jsonObject.getInt("ordre");
+
+ Bloc.miseAJourOrdreBloc(id, ordre);
+ }
+
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().write("{\"success\": true}");
+ } catch (Exception e) {
+ e.printStackTrace();
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ response.getWriter().write("{\"error\": \"Données invalides ou erreur serveur\"}");
+ }
+ }
+
+}
diff --git a/Projet/src/main/java/projet/SupprimerBloc.java b/Projet/src/main/java/projet/SupprimerBloc.java
index 7cd53e1..d37b486 100644
--- a/Projet/src/main/java/projet/SupprimerBloc.java
+++ b/Projet/src/main/java/projet/SupprimerBloc.java
@@ -29,22 +29,35 @@ public class SupprimerBloc extends HttpServlet {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+
HttpSession session = request.getSession();
Utilisateur u = (Utilisateur) session.getAttribute("utilisateur");
+
+ if (u == null) {
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.getWriter().write("{\"error\": \"Non autorisé\"}");
+ return;
+ }
- if(u != null) {
- String idBlocStr = request.getParameter("blocId");
-
- if(idBlocStr == null || idBlocStr.isEmpty()) {
- response.sendRedirect("AfficherPage");
- } else {
- int idBloc = Integer.parseInt(idBlocStr);
- Bloc.supprimerBloc(idBloc, u.getId());
- response.sendRedirect("AfficherPage");
- }
-
+ String idBlocStr = request.getParameter("blocId");
+
+ if (idBlocStr == null || idBlocStr.isEmpty()) {
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ response.getWriter().write("{\"error\": \"ID manquant\"}");
+ return;
+ }
+
+ int idBloc = Integer.parseInt(idBlocStr);
+ boolean success = Bloc.supprimerBloc(idBloc, u.getId());
+
+ if (success) {
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().write("{\"success\": true}");
} else {
- response.sendRedirect("/Projet/");
+ response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+ response.getWriter().write("{\"error\": \"Suppression interdite\"}");
}
}
}
diff --git a/Projet/src/main/webapp/WEB-INF/Accueil.jsp b/Projet/src/main/webapp/WEB-INF/Accueil.jsp
index a1c1ec2..3ef93e7 100644
--- a/Projet/src/main/webapp/WEB-INF/Accueil.jsp
+++ b/Projet/src/main/webapp/WEB-INF/Accueil.jsp
@@ -6,6 +6,37 @@
+
+
+
+
+
+
+
+ Bienvenue sur notre plateforme de prise de notes collaborative
+
+
+ Ce site vous permet de créer facilement des pages de contenu interactives en utilisant du Markdown, d’organiser vos idées en blocs, et de collaborer en temps réel avec d’autres utilisateurs.
+
+
+ - Éditeur intelligent : avec support des titres, listes, citations, et mise en forme automatique.
+ - Partage de pages : invitez vos collaborateurs avec un accès en lecture ou en édition.
+ - Sauvegarde en temps réel : vos modifications sont automatiquement enregistrées et partagées.
+
+
+ Une fois votre travail terminé, vous pouvez exporter vos pages dans plusieurs formats :
+
+
+ - HTML — pour une intégration facile sur le web
+ - LaTeX — idéal pour des documents scientifiques ou académiques
+ - Markdown — pour garder un format brut et portable
+
+
+
+
+
+
+
diff --git a/Projet/src/main/webapp/WEB-INF/AfficherPage.jsp b/Projet/src/main/webapp/WEB-INF/AfficherPage.jsp
index 9611a3c..1782bbb 100644
--- a/Projet/src/main/webapp/WEB-INF/AfficherPage.jsp
+++ b/Projet/src/main/webapp/WEB-INF/AfficherPage.jsp
@@ -20,6 +20,7 @@
- Pas encore de page choisie.
+
+
+
+
+ Rappel des Instructions
+
+
+
+
+
+ Commandes Slash
+
+
Dans un bloc, tapez une commande commençant par / :
+
+ /h1, /h2, /h3 → transforme le bloc en titre de niveau 1, 2 ou 3
+ /ul → transforme en liste à puces
+ /ol → transforme en liste numérotée
+ /code → transforme en bloc de code (optionnel : nom du langage)
+ /hr → insère une ligne de séparation
+ /page [titre] → crée une nouvelle page liée avec le titre donné
+
+
+
+
+
+
+ Markdown en début de bloc (type de contenu)
+
+
Si le bloc commence par un de ces symboles :
+
+ # Titre → Titre de niveau 1
+ ## Sous-titre → Titre de niveau 2
+ ### Titre 3 → Titre de niveau 3
+ ``` code → Bloc de code avec mise en forme monospaced
+ + Élément → Liste à puces
+ 1. Élément → Liste numérotée
+ > Citation → Citation classique
+ >! Attention → Bloc d'alerte/info
+ >i Note → Bloc d'information
+
+
+
+
+
+
+ Markdown dans un bloc (mise en forme)
+
+
+ `texte` → <code> : monospaced/code
+ **gras** → gras
+ *italique* → italique
+ $$math$$ → active le rendu mathématique (MathJax)
+
+
+
+
+
+
+ Raccourcis Clavier
+
+
+ - Entrée : crée un nouveau bloc (hors liste)
+ - Maj + Entrée : nouvelle ligne dans une liste
+
+
+
+
+
+
+ Fonctionnalités supplémentaires
+
+
+ - Redimensionnement automatique des blocs
+ - Rendu MathJax pour les formules
+ - Collage propre (suppression du style)
+ - Sauvegarde en temps réel via WebSocket
+
+
+
+
+
diff --git a/Projet/src/main/webapp/js/bloc.js b/Projet/src/main/webapp/js/bloc.js
index 2efe270..4715902 100644
--- a/Projet/src/main/webapp/js/bloc.js
+++ b/Projet/src/main/webapp/js/bloc.js
@@ -187,8 +187,13 @@ export function addDeleteBloc(button) {
body: params
}).then(response => {
if (response.ok) {
- blocContainer.remove(); // Supprime visuellement le bloc
+ blocContainer.remove();
ajouterBlocVideSiBesoin();
+
+ window.socketBloc.send(JSON.stringify({
+ action: "deleteBloc",
+ blocId,
+ }));
} else {
console.error("Erreur lors de la suppression du bloc.");
}
@@ -204,7 +209,7 @@ export function ajouterBlocVideSiBesoin() {
const message = document.querySelector('.column.is-half p');
if (message && message.textContent.trim() === "Pas encore de page choisie.") {
- return; // Arrête la fonction ici (se passe après avoir supprimé une page)
+ return;
}
if (allBlocs.length === 0 || allBlocs[allBlocs.length - 1].innerText.trim() !== "") {
diff --git a/Projet/src/main/webapp/js/drag-and-drop.js b/Projet/src/main/webapp/js/drag-and-drop.js
index e69de29..091b868 100644
--- a/Projet/src/main/webapp/js/drag-and-drop.js
+++ b/Projet/src/main/webapp/js/drag-and-drop.js
@@ -0,0 +1,62 @@
+export function initDragAndDrop(containerSelector, itemSelector = '[draggable]') {
+ const container = document.querySelector(containerSelector);
+ let draggedElement = null;
+
+ if (!container) {
+ return;
+ }
+
+ container.addEventListener('dragstart', e => {
+ if (e.target.matches(itemSelector)) {
+ draggedElement = e.target;
+ e.dataTransfer.effectAllowed = 'move';
+ e.target.classList.add('dragging');
+ }
+ });
+
+ container.addEventListener('dragover', e => {
+ e.preventDefault();
+ const target = e.target.closest(itemSelector);
+ if (target && draggedElement && target !== draggedElement) {
+ container.insertBefore(draggedElement, target);
+ }
+ });
+
+ container.addEventListener('drop', (e) => {
+ e.preventDefault();
+ });
+
+ container.addEventListener('dragend', () => {
+ if (draggedElement) {
+ draggedElement.classList.remove('dragging');
+ draggedElement = null;
+ }
+
+ const blocs = Array.from(container.querySelectorAll(itemSelector));
+ const ordre = blocs.map((bloc, index) => {
+ const editor = bloc.querySelector('.editor');
+ return {
+ id: editor.dataset.id,
+ ordre: index + 1
+ };
+ });
+
+ fetch('SauvegarderOrdre', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(ordre)
+ }).then(response => {
+ if (response.ok) {
+ const modifOrdre = {
+ action: "modifierOrdreBloc",
+ order: ordre.map(b => b.id)
+ };
+ window.socketBloc.send(JSON.stringify(modifOrdre));
+ } else {
+ console.error("Erreur lors de la modification de l'ordre des blocs.");
+ }
+ });
+ });
+}
diff --git a/Projet/src/main/webapp/js/functionsBloc.js b/Projet/src/main/webapp/js/functionsBloc.js
index ca12a12..fbe1c90 100644
--- a/Projet/src/main/webapp/js/functionsBloc.js
+++ b/Projet/src/main/webapp/js/functionsBloc.js
@@ -71,6 +71,7 @@ export function renderBlocStyle(bloc) {
break;
case 'PAGE':
+ renderPage(bloc);
bloc.classList.add('is-page-link');
break;
@@ -112,6 +113,18 @@ export function renderListe(bloc) {
bloc.innerHTML = `<${tag}>${items}${tag}>`;
}
+export function renderPage(bloc){
+ const metadata = getBlocDataMetadata(bloc);
+ const pageId = metadata.pageId;
+
+ if (!pageId) return;
+
+ const lien = `AfficherPage?id=${pageId}`;
+ const titre = metadata.title;
+
+ bloc.innerHTML = `${titre}`;
+}
+
export function handleSlashCommand(bloc, texte) {
return new Promise((resolve) => {
const parts = texte.trim().substring(1).split(" ");
@@ -172,7 +185,7 @@ export function handleSlashCommand(bloc, texte) {
applyBlocType(bloc, "SEPARATEUR", {}); // ou un type adapté selon ta logique
bloc.innerText = ' ';
autoResize(bloc);
- resolve(true);
+ resolve();
break;
default:
@@ -189,7 +202,7 @@ export function handleSlashCommand(bloc, texte) {
export async function handleMarkdownSyntax(bloc, texte) {
// Vérifier si c'est un titre
if (texte.startsWith('#')) {
- const level = texte.split(' ')[0].length; // Compter le nombre de # pour le niveau du titre
+ const level = texte.split(' ')[0].length;
if (level >= 1 && level <= 6) {
applyBlocType(bloc, "TITRE", { level: level });
bloc.textContent = texte.replace(/^#+\s*/, '');
@@ -253,9 +266,7 @@ export function setBlocMetadata(bloc, metadata) {
const citationTypes = {
'>!': 'danger',
'>i': 'info',
-/* '>w': 'warning',
- '>s': 'success',*/
- '>': 'normal' // doit rester en dernier
+ '>': 'normal'
};
function detectCitation(texte) {
diff --git a/Projet/src/main/webapp/js/main.js b/Projet/src/main/webapp/js/main.js
index 7aa11ba..07fb2ad 100644
--- a/Projet/src/main/webapp/js/main.js
+++ b/Projet/src/main/webapp/js/main.js
@@ -2,6 +2,7 @@ import { initBlocs, ajouterBlocVideSiBesoin, focusDernierBloc } from './bloc.js'
import { initTchat } from './tchat.js';
import { initPages } from './page.js';
import { initSocketBloc } from './socket-bloc.js';
+import { initDragAndDrop } from './drag-and-drop.js';
window.addEventListener('DOMContentLoaded', () => {
initTchat();
@@ -10,6 +11,7 @@ window.addEventListener('DOMContentLoaded', () => {
initBlocs();
ajouterBlocVideSiBesoin();
focusDernierBloc();
+ initDragAndDrop('#md', '.bloc-container');
document.body.addEventListener('click', function(event) {
// Vérifie si l'élément cliqué est un lien dans un .editor
diff --git a/Projet/src/main/webapp/js/socket-bloc.js b/Projet/src/main/webapp/js/socket-bloc.js
index 6cda2b9..8aca6bb 100644
--- a/Projet/src/main/webapp/js/socket-bloc.js
+++ b/Projet/src/main/webapp/js/socket-bloc.js
@@ -1,5 +1,4 @@
import { autoResize, creerBlocDOM } from './utils.js'
-import { renderBlocStyle, renderListe } from './functionsBloc.js'
export function initSocketBloc() {
const params = new URLSearchParams(window.location.search);
@@ -21,7 +20,7 @@ export function initSocketBloc() {
const data = JSON.parse(event.data);
if (data.action === "update") {
- const blocElement = document.querySelector(`.editor[data-id='${data.blocId}']`);
+ const blocElement = document.querySelector(`[data-id="${data.blocId}"`);
if (blocElement) {
blocElement.innerHTML = data.content;
blocElement.setAttribute('data-metadata', data.metadata);
@@ -46,7 +45,7 @@ export function initSocketBloc() {
ordre: data.ordre
});
} else if (data.action === "actualiserMiseEnPageBloc") {
- const blocElement = document.querySelector(`.editor[data-id='${data.blocId}']`);
+ const blocElement = document.querySelector(`[data-id="${data.blocId}"`);
if (blocElement) {
blocElement.dataset.type = data.type;
blocElement.innerHTML = data.content;
@@ -54,6 +53,28 @@ export function initSocketBloc() {
blocElement.className = data.classBloc;
renderBloc(blocElement, blocElement.dataset.metadata);
}
+ } else if (data.action === "modifierOrdreBloc") {
+ const container = document.getElementById("md");
+ const order = data.order;
+ order.forEach(blocId => {
+
+ const blocElement = document.querySelector(`[data-id="${blocId}"]`);
+ if (blocElement) {
+ const blocContainer = blocElement.closest('.bloc-container');
+ if (blocContainer) {
+ container.appendChild(blocContainer);
+ }
+ }
+ });
+ } else if (data.action === "deleteBloc") {
+ const blocId = data.blocId;
+ const blocElement = document.querySelector(`[data-id="${blocId}"]`);
+ if (blocElement) {
+ const blocContainer = blocElement.closest('.bloc-container');
+ if (blocContainer) {
+ blocContainer.remove();
+ }
+ }
}
};
diff --git a/Projet/src/main/webapp/js/utils.js b/Projet/src/main/webapp/js/utils.js
index c72a554..f7281e1 100644
--- a/Projet/src/main/webapp/js/utils.js
+++ b/Projet/src/main/webapp/js/utils.js
@@ -23,6 +23,7 @@ export function placeCursorAtEnd(element) {
export function creerBlocDOM({ blocId, content = "", type = "TEXTE", metadata = "{}", ordre = null }) {
const container = document.createElement('div');
container.classList.add('field', 'is-grouped', 'is-align-items-flex-start', 'bloc-container');
+ container.setAttribute('draggable', 'true');
const control = document.createElement('div');
control.classList.add('control', 'is-expanded');
diff --git a/Projet/src/main/webapp/styles.css b/Projet/src/main/webapp/styles.css
index 5d8b2f7..edb0c4f 100644
--- a/Projet/src/main/webapp/styles.css
+++ b/Projet/src/main/webapp/styles.css
@@ -89,3 +89,7 @@
background-color: #eaf6fb;
color: #2980b9;
}
+
+.dragging {
+ opacity: 0.5;
+}