The last one before the soutenance
This commit is contained in:
parent
8d07c38d32
commit
25e19ec12e
|
|
@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpSession;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@WebServlet("/AfficherPage")
|
||||
|
|
@ -35,6 +36,10 @@ public class AfficherPage extends HttpServlet {
|
|||
request.setAttribute("listeMessages", listeMessages);
|
||||
request.setAttribute("listeUtilisateurs", listeUtilisateurs);
|
||||
|
||||
String menuHtml = genererMenuHTML(u.getId());
|
||||
request.setAttribute("menuHtml", menuHtml);
|
||||
|
||||
|
||||
if (idStr != null ) {
|
||||
try {
|
||||
int id = Integer.parseInt(idStr);
|
||||
|
|
@ -67,4 +72,41 @@ public class AfficherPage extends HttpServlet {
|
|||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
}
|
||||
|
||||
public static String genererMenuHTML(int idU) {
|
||||
Map<Integer, List<Page>> arbre = Page.getArbreDesPages(idU);
|
||||
StringBuilder html = new StringBuilder();
|
||||
html.append("<ul>\n");
|
||||
construireHTMLRecursif(arbre, -1, html, 6);
|
||||
html.append(" </ul>\n");
|
||||
return html.toString();
|
||||
}
|
||||
|
||||
private static void construireHTMLRecursif(Map<Integer, List<Page>> arbre, int parentId, StringBuilder html, int indentLevel) {
|
||||
List<Page> enfants = arbre.get(parentId);
|
||||
if (enfants == null || enfants.isEmpty()) return;
|
||||
|
||||
String indent = "\t".repeat(indentLevel);
|
||||
|
||||
for (Page p : enfants) {
|
||||
List<Page> sousPages = arbre.get(p.getId());
|
||||
boolean aSousPages = sousPages != null && !sousPages.isEmpty();
|
||||
|
||||
html.append(indent).append("<li>\n");
|
||||
|
||||
html.append(indent).append("\t<div class='is-flex is-align-items-center is-justify-content-space-between'>\n");
|
||||
html.append(indent).append("\t\t<a href='AfficherPage?id=").append(p.getId()).append("'>")
|
||||
.append(p.getTitre()).append("</a>\n");
|
||||
html.append(indent).append("\t\t<button class='delete delete-page-btn has-background-danger ml-2' data-id='")
|
||||
.append(p.getId()).append("'></button>\n");
|
||||
html.append(indent).append("\t</div>\n");
|
||||
|
||||
if (aSousPages) {
|
||||
html.append(indent).append("\t<ul class='ml-4'>\n");
|
||||
construireHTMLRecursif(arbre, p.getId(), html, indentLevel + 1);
|
||||
html.append(indent).append("\t</ul>\n");
|
||||
}
|
||||
|
||||
html.append(indent).append("</li>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ import java.sql.Statement;
|
|||
import java.time.LocalDate;
|
||||
import java.sql.Date;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import projet.Bloc.Type;
|
||||
|
||||
|
|
@ -283,4 +285,57 @@ public class Page extends ParamBD {
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<Integer, List<Page>> getArbreDesPages(int idU) {
|
||||
Map<Integer, List<Page>> arbre = new HashMap<>();
|
||||
chargerSousPagesRecursivement(idU, arbre, null);
|
||||
return arbre;
|
||||
}
|
||||
|
||||
public static void chargerSousPagesRecursivement(int idU, Map<Integer, List<Page>> arbre, Integer idParent) {
|
||||
List<Page> enfants = new ArrayList<>();
|
||||
|
||||
try {
|
||||
Connection connexion = DriverManager.getConnection(bdURL, bdLogin, bdPassword);
|
||||
String sql;
|
||||
PreparedStatement pst;
|
||||
|
||||
if(idParent == null) {
|
||||
sql = " SELECT id, titre"
|
||||
+ " FROM page "
|
||||
+ "WHERE auteur_id = ? AND page_parent_id IS NULL"
|
||||
+ ";";
|
||||
pst = connexion.prepareStatement(sql);
|
||||
pst.setInt(1, idU);
|
||||
} else {
|
||||
sql = " SELECT id, titre"
|
||||
+ " FROM page "
|
||||
+ "WHERE auteur_id = ? AND page_parent_id = ?"
|
||||
+ ";";
|
||||
pst = connexion.prepareStatement(sql);
|
||||
pst.setInt(1, idU);
|
||||
pst.setInt(2, idParent);
|
||||
}
|
||||
|
||||
ResultSet rs = pst.executeQuery();
|
||||
while (rs.next()) {
|
||||
int id = rs.getInt("id");
|
||||
String titre = rs.getString("titre");
|
||||
Page page = new Page(id, idU, titre);
|
||||
enfants.add(page);
|
||||
}
|
||||
|
||||
rs.close();
|
||||
connexion.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int key = (idParent == null) ? -1 : idParent;
|
||||
arbre.put(key, enfants);
|
||||
|
||||
for (Page enfant : enfants) {
|
||||
chargerSousPagesRecursivement(idU, arbre, enfant.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,15 +7,15 @@
|
|||
</jsp:include>
|
||||
|
||||
|
||||
<div class="columns">
|
||||
<div class="columns is-flex" style="transition: all 0.3s ease;">
|
||||
|
||||
<!-- La colonne pour le menu des pages -->
|
||||
<div class="column is-one-fifth">
|
||||
<div class="column is-one-fifth" id="menuColumn">
|
||||
<jsp:include page="MenuPages.jsp" />
|
||||
</div>
|
||||
|
||||
<!-- La colonne pour la page choisie -->
|
||||
<div class="column is-half">
|
||||
<div class="column flex-main" id="mainColumn">
|
||||
<c:choose>
|
||||
<c:when test="${not empty page.titre}">
|
||||
<div class="is-flex is-justify-content-space-between is-align-items mb-4">
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="dropdown-menu" id="dropdown-menu3" role="menu">
|
||||
<div class="dropdown-menu" id="dropdown-menu4" role="menu">
|
||||
<div class="dropdown-content">
|
||||
<c:forEach var="u" items="${listeUtilisateurs}">
|
||||
<c:if test="${u.id != utilisateur.id}">
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
</div>
|
||||
<div class="block" id="md">
|
||||
<c:forEach var="bloc" items="${page.listeBlocs}">
|
||||
<div class="field is-grouped is-align-items-flex-start bloc-container" draggable="true">
|
||||
<div class="field is-grouped is-align-items-flex-start bloc-container hover-bloc" draggable="true">
|
||||
<div class="control is-expanded">
|
||||
<div
|
||||
class="is-primary editor"
|
||||
|
|
@ -139,6 +139,7 @@
|
|||
<li><code>`texte`</code> → <code><code></code> : monospaced/code</li>
|
||||
<li><code>**gras**</code> → <strong>gras</strong></li>
|
||||
<li><code>*italique*</code> → <em>italique</em></li>
|
||||
<li><code>$math$</code> → active le rendu mathématique en ligne (MathJax)</li>
|
||||
<li><code>$$math$$ </code> → active le rendu mathématique (MathJax)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -174,10 +175,10 @@
|
|||
</div>
|
||||
|
||||
<!-- La colonne pour le Tchat -->
|
||||
<div class="column is-one-quarter">
|
||||
<div class="column flex-tchat slide-out" id="tchatColumn">
|
||||
<jsp:include page="Tchat.jsp" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="button is-small is-info vertical-toggle" id="toggleTchatBtn">Afficher / Cacher le Tchat</button>
|
||||
<jsp:include page="Footer.jsp" />
|
||||
|
||||
|
|
|
|||
|
|
@ -8,15 +8,23 @@
|
|||
<link href="bulma.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<script src="https://kit.fontawesome.com/39474be7e2.js" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" async
|
||||
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
|
||||
<script>
|
||||
window.MathJax = {
|
||||
tex: {
|
||||
inlineMath: [['$', '$'], ['\\(', '\\)']]
|
||||
},
|
||||
svg: {
|
||||
fontCache: 'global'
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar has-shadow is-white" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item" href="/Projet/">
|
||||
<h1 class="title is-2">Prise de notes collaborative</h1>
|
||||
<h1 class="title is-2 has-text-success">Prise de notes collaborative</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="navbar-menu">
|
||||
|
|
|
|||
|
|
@ -4,15 +4,9 @@
|
|||
|
||||
<h2 class="block">Menu des pages</h2>
|
||||
<aside class="menu">
|
||||
<ul class="menu-list" id="menuPages">
|
||||
<c:forEach var="page" items="${listePages}">
|
||||
<li>
|
||||
<button class="delete delete-page-btn is-pulled-right has-background-danger" data-id="${page.id}"></button>
|
||||
<a href="AfficherPage?id=${page.id}">${page.titre}</a>
|
||||
|
||||
</li>
|
||||
</c:forEach>
|
||||
</ul>
|
||||
<div>
|
||||
${menuHtml}
|
||||
</div>
|
||||
<hr>
|
||||
<ul class="menu-list">
|
||||
<c:forEach var="pagePartagees" items="${listePagesPartagees}">
|
||||
|
|
|
|||
|
|
@ -20,13 +20,19 @@ export function initBlocs() {
|
|||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.delete-bloc-btn').forEach(t => {
|
||||
addDeleteBloc(t);
|
||||
document.querySelectorAll('.delete-bloc-btn').forEach(btn => {
|
||||
addDeleteBloc(btn);
|
||||
btn.addEventListener('mouseenter', () => {
|
||||
btn.closest('.hover-bloc').classList.add('hovered');
|
||||
});
|
||||
btn.addEventListener('mouseleave', () => {
|
||||
btn.closest('.hover-bloc').classList.remove('hovered');
|
||||
});
|
||||
});
|
||||
|
||||
formatEditorContent();
|
||||
|
||||
document.querySelectorAll('#md [contenteditable="true"]').forEach(bloc => {
|
||||
document.querySelectorAll('#md ').forEach(bloc => {
|
||||
autoResize(bloc);
|
||||
});
|
||||
|
||||
|
|
@ -169,9 +175,9 @@ export function addDeleteBloc(button) {
|
|||
button.addEventListener('click', function() {
|
||||
const blocId = button.dataset.id;
|
||||
const blocContainer = button.closest('.bloc-container');
|
||||
const bloc = blocContainer.querySelector('[contenteditable="true"]');
|
||||
const bloc = blocContainer.querySelector('.editor');
|
||||
|
||||
if (bloc.dataset.type != "SEPARATEUR" && bloc.innerText === "") {
|
||||
if (bloc.dataset.type != "SEPARATEUR" && bloc.innerText.trim() === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +209,10 @@ export function addDeleteBloc(button) {
|
|||
}
|
||||
|
||||
export function ajouterBlocVideSiBesoin() {
|
||||
const allBlocs = document.querySelectorAll('#md [contenteditable="true"]');
|
||||
const container = document.querySelector('#md');
|
||||
if (!container) return;
|
||||
const allBlocs = container.querySelectorAll('.editor');
|
||||
|
||||
const pageId = new URLSearchParams(window.location.search).get("id");
|
||||
if (pageId === null) return;
|
||||
|
||||
|
|
@ -212,7 +221,7 @@ export function ajouterBlocVideSiBesoin() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (allBlocs.length === 0 || allBlocs[allBlocs.length - 1].innerText.trim() !== "") {
|
||||
if (allBlocs.length === 0 || allBlocs[allBlocs.length - 1].innerText.trim() !== "" || allBlocs[allBlocs.length - 1].dataset.type === "SEPARATEUR") {
|
||||
const params = new URLSearchParams();
|
||||
params.append("contenu", ""); // Bloc vide
|
||||
params.append("type", "TEXTE"); // Type par défaut : TEXTE
|
||||
|
|
@ -227,30 +236,30 @@ export function ajouterBlocVideSiBesoin() {
|
|||
},
|
||||
body: params.toString()
|
||||
}).then(response => response.json())
|
||||
.then(data => {
|
||||
if (data && data.idGenere) {
|
||||
const idGenere = data.idGenere;
|
||||
const newBloc = creerBlocDOM({
|
||||
blocId: idGenere,
|
||||
content: "",
|
||||
type: "TEXTE",
|
||||
metadata: "{}",
|
||||
ordre: allBlocs.length
|
||||
});
|
||||
.then(data => {
|
||||
if (data && data.idGenere) {
|
||||
const idGenere = data.idGenere;
|
||||
const newBloc = creerBlocDOM({
|
||||
blocId: idGenere,
|
||||
content: "",
|
||||
type: "TEXTE",
|
||||
metadata: "{}",
|
||||
ordre: allBlocs.length
|
||||
});
|
||||
|
||||
newBloc.focus();
|
||||
newBloc.focus();
|
||||
|
||||
// Envoi d'une notification d'un nouveau bloc créé via websocket
|
||||
window.socketBloc.send(JSON.stringify({
|
||||
action: "newBloc",
|
||||
blocId: idGenere,
|
||||
content: "",
|
||||
type: "TEXTE",
|
||||
metadata: "{}",
|
||||
ordre: allBlocs.length
|
||||
}));
|
||||
}
|
||||
});
|
||||
// Envoi d'une notification d'un nouveau bloc créé via websocket
|
||||
window.socketBloc.send(JSON.stringify({
|
||||
action: "newBloc",
|
||||
blocId: idGenere,
|
||||
content: "",
|
||||
type: "TEXTE",
|
||||
metadata: "{}",
|
||||
ordre: allBlocs.length
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ export function renderBlocStyle(bloc) {
|
|||
case 'PAGE':
|
||||
renderPage(bloc);
|
||||
bloc.classList.add('is-page-link');
|
||||
bloc.contentEditable = "false";
|
||||
break;
|
||||
|
||||
case 'SEPARATEUR':
|
||||
|
|
@ -183,7 +184,7 @@ export function handleSlashCommand(bloc, texte) {
|
|||
|
||||
case "hr":
|
||||
applyBlocType(bloc, "SEPARATEUR", {}); // ou un type adapté selon ta logique
|
||||
bloc.innerText = ' ';
|
||||
bloc.textContent = '';
|
||||
autoResize(bloc);
|
||||
resolve();
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { initBlocs, ajouterBlocVideSiBesoin, focusDernierBloc } from './bloc.js';
|
||||
import { initTchat } from './tchat.js';
|
||||
import { initTchat, toggleTchat } from './tchat.js';
|
||||
import { initPages } from './page.js';
|
||||
import { initSocketBloc } from './socket-bloc.js';
|
||||
import { initDragAndDrop } from './drag-and-drop.js';
|
||||
|
|
@ -22,4 +22,23 @@ window.addEventListener('DOMContentLoaded', () => {
|
|||
window.location.href = url; // Rediriger manuellement
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll('.item-header .toggle').forEach(toggle => {
|
||||
toggle.addEventListener('click', function (e) {
|
||||
// Empêche le lien de se propager si cliqué
|
||||
e.stopPropagation();
|
||||
|
||||
const li = this.closest('li');
|
||||
const sublist = li.querySelector('ul');
|
||||
|
||||
if (sublist) {
|
||||
sublist.classList.toggle('hidden');
|
||||
this.classList.toggle('rotated');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('toggleTchatBtn').addEventListener('click', toggleTchat);
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,3 +22,22 @@ export function initTchat() {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function toggleTchat() {
|
||||
const tchat = document.getElementById('tchatColumn');
|
||||
const main = document.getElementById('mainColumn');
|
||||
|
||||
if (tchat.classList.contains('slide-in')) {
|
||||
tchat.classList.remove('slide-in');
|
||||
tchat.classList.add('slide-out');
|
||||
|
||||
main.classList.remove('collapsed');
|
||||
main.classList.add('expanded');
|
||||
} else {
|
||||
tchat.classList.remove('slide-out');
|
||||
tchat.classList.add('slide-in');
|
||||
|
||||
main.classList.remove('expanded');
|
||||
main.classList.add('collapsed');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,3 +93,45 @@
|
|||
.dragging {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* Animation pour glisser la colonne vers la droite */
|
||||
.slide-out {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
transition: transform 0.3s ease, opacity 0.3s ease;
|
||||
}
|
||||
|
||||
/* Animation pour la faire apparaître */
|
||||
.slide-in {
|
||||
transform: translateX(0%);
|
||||
opacity: 1;
|
||||
transition: transform 0.3s ease, opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.flex-main {
|
||||
flex-grow: 4;
|
||||
transition: flex-grow 0.3s ease;
|
||||
}
|
||||
|
||||
.expanded {
|
||||
flex-grow: 4;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
flex-grow: 2;
|
||||
}
|
||||
|
||||
.vertical-toggle {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: rotate(-90deg) translateY(-50%);
|
||||
transform-origin: right center;
|
||||
z-index: 999;
|
||||
border-radius: 6px 6px 0 0;
|
||||
}
|
||||
|
||||
.hover-bloc.hovered {
|
||||
background-color: #ffe6e6;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
Loading…
Reference in New Issue