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.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@WebServlet("/AfficherPage")
|
@WebServlet("/AfficherPage")
|
||||||
|
|
@ -35,6 +36,10 @@ public class AfficherPage extends HttpServlet {
|
||||||
request.setAttribute("listeMessages", listeMessages);
|
request.setAttribute("listeMessages", listeMessages);
|
||||||
request.setAttribute("listeUtilisateurs", listeUtilisateurs);
|
request.setAttribute("listeUtilisateurs", listeUtilisateurs);
|
||||||
|
|
||||||
|
String menuHtml = genererMenuHTML(u.getId());
|
||||||
|
request.setAttribute("menuHtml", menuHtml);
|
||||||
|
|
||||||
|
|
||||||
if (idStr != null ) {
|
if (idStr != null ) {
|
||||||
try {
|
try {
|
||||||
int id = Integer.parseInt(idStr);
|
int id = Integer.parseInt(idStr);
|
||||||
|
|
@ -67,4 +72,41 @@ public class AfficherPage extends HttpServlet {
|
||||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
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.time.LocalDate;
|
||||||
import java.sql.Date;
|
import java.sql.Date;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import projet.Bloc.Type;
|
import projet.Bloc.Type;
|
||||||
|
|
||||||
|
|
@ -283,4 +285,57 @@ public class Page extends ParamBD {
|
||||||
e.printStackTrace();
|
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>
|
</jsp:include>
|
||||||
|
|
||||||
|
|
||||||
<div class="columns">
|
<div class="columns is-flex" style="transition: all 0.3s ease;">
|
||||||
|
|
||||||
<!-- La colonne pour le menu des pages -->
|
<!-- 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" />
|
<jsp:include page="MenuPages.jsp" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- La colonne pour la page choisie -->
|
<!-- La colonne pour la page choisie -->
|
||||||
<div class="column is-half">
|
<div class="column flex-main" id="mainColumn">
|
||||||
<c:choose>
|
<c:choose>
|
||||||
<c:when test="${not empty page.titre}">
|
<c:when test="${not empty page.titre}">
|
||||||
<div class="is-flex is-justify-content-space-between is-align-items mb-4">
|
<div class="is-flex is-justify-content-space-between is-align-items mb-4">
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown-menu" id="dropdown-menu3" role="menu">
|
<div class="dropdown-menu" id="dropdown-menu4" role="menu">
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<c:forEach var="u" items="${listeUtilisateurs}">
|
<c:forEach var="u" items="${listeUtilisateurs}">
|
||||||
<c:if test="${u.id != utilisateur.id}">
|
<c:if test="${u.id != utilisateur.id}">
|
||||||
|
|
@ -67,7 +67,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="block" id="md">
|
<div class="block" id="md">
|
||||||
<c:forEach var="bloc" items="${page.listeBlocs}">
|
<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="control is-expanded">
|
||||||
<div
|
<div
|
||||||
class="is-primary editor"
|
class="is-primary editor"
|
||||||
|
|
@ -139,6 +139,7 @@
|
||||||
<li><code>`texte`</code> → <code><code></code> : monospaced/code</li>
|
<li><code>`texte`</code> → <code><code></code> : monospaced/code</li>
|
||||||
<li><code>**gras**</code> → <strong>gras</strong></li>
|
<li><code>**gras**</code> → <strong>gras</strong></li>
|
||||||
<li><code>*italique*</code> → <em>italique</em></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>
|
<li><code>$$math$$ </code> → active le rendu mathématique (MathJax)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -174,10 +175,10 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- La colonne pour le Tchat -->
|
<!-- 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" />
|
<jsp:include page="Tchat.jsp" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="button is-small is-info vertical-toggle" id="toggleTchatBtn">Afficher / Cacher le Tchat</button>
|
||||||
<jsp:include page="Footer.jsp" />
|
<jsp:include page="Footer.jsp" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,23 @@
|
||||||
<link href="bulma.css" rel="stylesheet">
|
<link href="bulma.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
<script src="https://kit.fontawesome.com/39474be7e2.js" crossorigin="anonymous"></script>
|
<script src="https://kit.fontawesome.com/39474be7e2.js" crossorigin="anonymous"></script>
|
||||||
<script type="text/javascript" async
|
<script>
|
||||||
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
|
window.MathJax = {
|
||||||
|
tex: {
|
||||||
|
inlineMath: [['$', '$'], ['\\(', '\\)']]
|
||||||
|
},
|
||||||
|
svg: {
|
||||||
|
fontCache: 'global'
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar has-shadow is-white" aria-label="main navigation">
|
<nav class="navbar has-shadow is-white" aria-label="main navigation">
|
||||||
<div class="navbar-brand">
|
<div class="navbar-brand">
|
||||||
<a class="navbar-item" href="/Projet/">
|
<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>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="navbar-menu">
|
<div class="navbar-menu">
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,9 @@
|
||||||
|
|
||||||
<h2 class="block">Menu des pages</h2>
|
<h2 class="block">Menu des pages</h2>
|
||||||
<aside class="menu">
|
<aside class="menu">
|
||||||
<ul class="menu-list" id="menuPages">
|
<div>
|
||||||
<c:forEach var="page" items="${listePages}">
|
${menuHtml}
|
||||||
<li>
|
</div>
|
||||||
<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>
|
|
||||||
<hr>
|
<hr>
|
||||||
<ul class="menu-list">
|
<ul class="menu-list">
|
||||||
<c:forEach var="pagePartagees" items="${listePagesPartagees}">
|
<c:forEach var="pagePartagees" items="${listePagesPartagees}">
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,19 @@ export function initBlocs() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll('.delete-bloc-btn').forEach(t => {
|
document.querySelectorAll('.delete-bloc-btn').forEach(btn => {
|
||||||
addDeleteBloc(t);
|
addDeleteBloc(btn);
|
||||||
|
btn.addEventListener('mouseenter', () => {
|
||||||
|
btn.closest('.hover-bloc').classList.add('hovered');
|
||||||
|
});
|
||||||
|
btn.addEventListener('mouseleave', () => {
|
||||||
|
btn.closest('.hover-bloc').classList.remove('hovered');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
formatEditorContent();
|
formatEditorContent();
|
||||||
|
|
||||||
document.querySelectorAll('#md [contenteditable="true"]').forEach(bloc => {
|
document.querySelectorAll('#md ').forEach(bloc => {
|
||||||
autoResize(bloc);
|
autoResize(bloc);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -169,9 +175,9 @@ export function addDeleteBloc(button) {
|
||||||
button.addEventListener('click', function() {
|
button.addEventListener('click', function() {
|
||||||
const blocId = button.dataset.id;
|
const blocId = button.dataset.id;
|
||||||
const blocContainer = button.closest('.bloc-container');
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,7 +209,10 @@ export function addDeleteBloc(button) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ajouterBlocVideSiBesoin() {
|
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");
|
const pageId = new URLSearchParams(window.location.search).get("id");
|
||||||
if (pageId === null) return;
|
if (pageId === null) return;
|
||||||
|
|
||||||
|
|
@ -212,7 +221,7 @@ export function ajouterBlocVideSiBesoin() {
|
||||||
return;
|
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();
|
const params = new URLSearchParams();
|
||||||
params.append("contenu", ""); // Bloc vide
|
params.append("contenu", ""); // Bloc vide
|
||||||
params.append("type", "TEXTE"); // Type par défaut : TEXTE
|
params.append("type", "TEXTE"); // Type par défaut : TEXTE
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ export function renderBlocStyle(bloc) {
|
||||||
case 'PAGE':
|
case 'PAGE':
|
||||||
renderPage(bloc);
|
renderPage(bloc);
|
||||||
bloc.classList.add('is-page-link');
|
bloc.classList.add('is-page-link');
|
||||||
|
bloc.contentEditable = "false";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'SEPARATEUR':
|
case 'SEPARATEUR':
|
||||||
|
|
@ -183,7 +184,7 @@ export function handleSlashCommand(bloc, texte) {
|
||||||
|
|
||||||
case "hr":
|
case "hr":
|
||||||
applyBlocType(bloc, "SEPARATEUR", {}); // ou un type adapté selon ta logique
|
applyBlocType(bloc, "SEPARATEUR", {}); // ou un type adapté selon ta logique
|
||||||
bloc.innerText = ' ';
|
bloc.textContent = '';
|
||||||
autoResize(bloc);
|
autoResize(bloc);
|
||||||
resolve();
|
resolve();
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { initBlocs, ajouterBlocVideSiBesoin, focusDernierBloc } from './bloc.js';
|
import { initBlocs, ajouterBlocVideSiBesoin, focusDernierBloc } from './bloc.js';
|
||||||
import { initTchat } from './tchat.js';
|
import { initTchat, toggleTchat } from './tchat.js';
|
||||||
import { initPages } from './page.js';
|
import { initPages } from './page.js';
|
||||||
import { initSocketBloc } from './socket-bloc.js';
|
import { initSocketBloc } from './socket-bloc.js';
|
||||||
import { initDragAndDrop } from './drag-and-drop.js';
|
import { initDragAndDrop } from './drag-and-drop.js';
|
||||||
|
|
@ -22,4 +22,23 @@ window.addEventListener('DOMContentLoaded', () => {
|
||||||
window.location.href = url; // Rediriger manuellement
|
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 {
|
.dragging {
|
||||||
opacity: 0.5;
|
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