Leonel FOFOU
2026-07-28 32450e295200b2bc7896518ff74161ff26772e2d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package com.megatim.manuel.core.generate;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.megatim.manuel.core.convert.ConversionResult;
import com.megatim.manuel.core.convert.FrontMatter;
import com.megatim.manuel.core.convert.Heading;
 
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
 
/**
 * Écrit le sommaire de l'aide sous forme de {@code toc.json} dans le dossier de sortie,
 * rendant le dossier HTML autonome et lisible par le viewer JavaFX (remplace le .chm).
 */
public class HelpExporter {
 
    public static final String TOC_JSON = "toc.json";
 
    public void writeToc(Path dir, String title, List<ConversionResult> results, String homePage) throws IOException {
        writeToc(dir, title, results, homePage, null, null);
    }
 
    public void writeToc(Path dir, String title, List<ConversionResult> results, String homePage,
                         String project, String version) throws IOException {
        HelpManifest m = new HelpManifest();
        m.project = project;
        m.version = version;
        m.title = title;
        // Page d'accueil = page de garde du 1er document
        m.home = results.isEmpty() ? homePage : results.get(0).htmlFileName;
 
        for (ConversionResult r : results) {
            HelpToc doc = new HelpToc(r.title, r.htmlFileName);
 
            // 1. Accueil -> page de garde du document
            doc.children.add(new HelpToc("Accueil (page de garde)", r.htmlFileName));
 
            // 2. Préambule : regroupe Résumé, Mots clés, Historique, Diffusion (ordre canonique)
            HelpToc preambule = new HelpToc("Préambule", null);
            for (String key : FrontMatter.ENTRY_ORDER) {
                String wanted = FrontMatter.label(key);
                for (Heading lm : r.landmarks) {
                    if (wanted.equals(lm.text)) {
                        preambule.children.add(new HelpToc(lm.text, r.htmlFileName + "#" + lm.anchor));
                        break;
                    }
                }
            }
            if (!preambule.children.isEmpty()) doc.children.add(preambule);
 
            // 3. Sommaire (chapitres), numéroté hiérarchiquement (1, 1.1, 1.1.1, 2…)
            List<HelpToc> tree = buildHeadingTree(r);
            if (!tree.isEmpty()) {
                numberTree(tree, "");
                HelpToc som = new HelpToc("Sommaire", null);
                som.children.addAll(tree);
                doc.children.add(som);
            }
 
            // 4. Illustrations (légendes)
            if (!r.figures.isEmpty()) {
                HelpToc figs = new HelpToc("Illustrations", null);
                for (Heading f : r.figures) {
                    figs.children.add(new HelpToc(f.text, r.htmlFileName + "#" + f.anchor));
                }
                doc.children.add(figs);
            }
 
            m.nodes.add(doc);
        }
 
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(m);
        Files.write(dir.resolve(TOC_JSON), json.getBytes(StandardCharsets.UTF_8));
    }
 
    /** Préfixe chaque titre du sommaire par sa numérotation hiérarchique (1, 1.1, 1.1.1, 2…). */
    private void numberTree(List<HelpToc> nodes, String prefix) {
        int i = 1;
        for (HelpToc n : nodes) {
            String num = prefix.isEmpty() ? String.valueOf(i) : prefix + "." + i;
            n.title = num + ". " + n.title;
            numberTree(n.children, num);
            i++;
        }
    }
 
    /** Convertit la liste plate de titres (avec niveaux) en arbre imbriqué. */
    private List<HelpToc> buildHeadingTree(ConversionResult r) {
        List<HelpToc> roots = new ArrayList<>();
        if (r.headings.isEmpty()) return roots;
 
        int min = Integer.MAX_VALUE;
        for (Heading h : r.headings) min = Math.min(min, Math.max(1, h.level));
 
        Deque<HelpToc> nodes = new ArrayDeque<>();
        Deque<Integer> levels = new ArrayDeque<>();
        for (Heading h : r.headings) {
            int lvl = Math.max(1, h.level) - min + 1;
            HelpToc node = new HelpToc(h.text, r.htmlFileName + "#" + h.anchor);
            while (!levels.isEmpty() && levels.peek() >= lvl) { levels.pop(); nodes.pop(); }
            if (nodes.isEmpty()) roots.add(node); else nodes.peek().children.add(node);
            nodes.push(node);
            levels.push(lvl);
        }
        return roots;
    }
}