Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions src/main/java/ui/PreviewPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,18 @@ public PreviewPanel() {
if (newState == Worker.State.SCHEDULED) {
String location = webView.getEngine().getLocation();
if (location != null && !location.isEmpty() && !location.equals("about:blank")) {
// Ancre interne (#fragment) : défiler vers l'élément sans recharger la page
if (location.contains("#")) {
String fragment = location.substring(location.indexOf('#') + 1);
if (!fragment.isEmpty()) {
webView.getEngine().getLoadWorker().cancel();
webView.getEngine().executeScript(
"var el = document.getElementById('" + fragment.replace("'", "\\'") + "');" +
"if (el) el.scrollIntoView({behavior: 'smooth', block: 'start'});"
);
}
return;
}
// Vérifier si c'est un lien vers un fichier .md
if (location.toLowerCase().endsWith(".md") || location.toLowerCase().endsWith(".markdown")) {
// Annuler la navigation
Expand Down Expand Up @@ -267,6 +279,9 @@ private void updatePreview(String markdown, boolean addToHistory) {

String html = htmlRenderer.render(markdownParser.parse(body));

// ── IDs sur les titres : nécessaires pour la navigation par ancres (#fragment)
html = processHeadingIds(html);

// ── Checkboxes : convertir [ ] et [x] en éléments checkbox HTML
html = processCheckboxes(html);

Expand Down Expand Up @@ -527,6 +542,40 @@ private String loadResourceAsString(String resourcePath) {
});
}

/**
* Injecte un attribut {@code id} GitHub-compatible sur chaque titre HTML ({@code <h1>}–{@code <h6>})
* qui n'en possède pas encore. Requis pour que la navigation par ancres (#fragment) fonctionne.
*/
private String processHeadingIds(String html) {
Pattern p = Pattern.compile(
"<(h[1-6])(\\s[^>]*)?>(.+?)</h[1-6]>",
Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
Matcher m = p.matcher(html);
StringBuffer sb = new StringBuffer();
java.util.Map<String, Integer> seen = new java.util.HashMap<>();
while (m.find()) {
String tag = m.group(1);
String attrs = m.group(2) != null ? m.group(2) : "";
String content = m.group(3);
if (attrs.contains("id=")) {
m.appendReplacement(sb, Matcher.quoteReplacement(m.group(0)));
continue;
}
String text = content.replaceAll("<[^>]+>", "").trim();
String id = text.toLowerCase()
.replaceAll("[^\\w\\s-]", "")
.trim()
.replaceAll("\\s+", "-");
int count = seen.getOrDefault(id, 0);
seen.put(id, count + 1);
String uid = count == 0 ? id : id + "-" + count;
m.appendReplacement(sb, Matcher.quoteReplacement(
"<" + tag + attrs + " id=\"" + uid + "\">" + content + "</" + tag + ">"));
}
m.appendTail(sb);
return sb.toString();
}

/**
* Convertit les marqueurs de checkbox Markdown ([ ] et [x]) en éléments HTML checkbox.
*
Expand Down
Loading