# -*- coding: utf-8 -*- """Insère le nouveau contenu guide #105 dans frontend/index.html. - 8 nouvelles sections + entrées de TOC (guide_content.py) - compléments h3 dans 5 sections existantes - BUG-067 : le bloc « Édition mobile » de help-edition devient la section dédiée help-mobile-editor (ancre morte → ancre vivante) - retire l'attribut data-i18n-placeholder dupliqué sur #help-nav-search Idempotent : refuse de tourner deux fois (détecte guide105.* déjà présent). Préserve les fins de ligne CRLF de index.html. """ import re import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) from guide_content import ( # noqa: E402 CONTENT, EXTRA_BLOCKS, NEW_SECTIONS, TOC_INSERT_BEFORE, ) HTML = Path("C:/dev/git/python/ObsiGate/frontend/index.html") _CRLF = False def to_crlf(s: str) -> str: return s.replace("\n", "\r\n") if _CRLF else s def main() -> int: with open(HTML, encoding="utf-8", newline="") as f: raw = f.read() global _CRLF _CRLF = "\r\n" in raw if _CRLF: raw = raw.replace("\r\n", "\n") # normaliser ; régénéré à l'écriture if "guide105." in raw: print("already inserted — abort") return 1 # Localise le guide (après la modale de config) : on opère uniquement dans # la fenêtre help-modal pour ne pas toucher le TOC #cfg-* de la config. guide_start = raw.index('
') head, guide = raw[:guide_start], raw[guide_start:] # ── Fix BUG-067 : section mobile dédiée ──────────────────────────────── m_h3 = guide.index('

') # le bloc va jusqu'à la fin de la section help-edition m_sec_end = guide.index("", m_h3) mobile_block = guide[m_h3:m_sec_end] guide = guide[:m_h3] + guide[m_sec_end:] # h3 -> h2, et on emballe en section dédiée mobile_h2 = mobile_block.replace('

', '

', 1) mobile_h2 = mobile_h2.replace("

", "", 1) mobile_section = ( '
\n' + mobile_h2.rstrip() + "\n
\n\n" ) # insérer après help-edition (donc avant help-graphe) anchor = guide.index('
') guide = guide[:anchor] + mobile_section + guide[anchor:] # ── Compléments h3 dans sections existantes ──────────────────────────── for sec_id, block in EXTRA_BLOCKS: pat = 'id="%s"' % sec_id a = guide.index(pat) b = guide.index("
", a) guide = guide[:b] + to_crlf(block) + guide[b:] # ── Nouvelles sections ───────────────────────────────────────────────── for sec_id, html, before_id in NEW_SECTIONS: anchor = guide.index('
' % before_id) guide = guide[:anchor] + to_crlf(html) + guide[anchor:] # ── Entrées TOC ──────────────────────────────────────────────────────── for key, href, before_href in TOC_INSERT_BEFORE: label = CONTENT[key][0] entry = to_crlf( "
  • \n" ' %s\n' "
  • \n" % (href, key, label) ) needle = 'href="%s"' % before_href # l'entrée
  • qui contient ce href i = guide.index(needle) li_start = guide.rindex("
  • ", 0, i) guide = guide[:li_start] + entry + guide[li_start:] # ── Anchor #help-ia mort (nav) → #help-ai (id de section réel) ───────── guide = guide.replace('href="#help-ia"', 'href="#help-ai"') # ── Attribut dupliqué sur #help-nav-search ───────────────────────────── guide = guide.replace( ' data-i18n-placeholder="help.search_placeholder" data-i18n-placeholder="help.search_placeholder"', ' data-i18n-placeholder="help.search_placeholder"', 1, ) out = head + guide if _CRLF: out = out.replace("\n", "\r\n") with open(HTML, "w", encoding="utf-8", newline="") as f: f.write(out) # ── Vérifications structurelles ──────────────────────────────────────── d = HTML.read_text(encoding="utf-8") opens, closes = len(re.findall(r"]", d)), d.count("
  • ") print("section balance:", opens, closes) hrefs = set(re.findall(r'href="#(help-[a-z-]+)"', d)) ids = set(re.findall(r'id="(help-[a-z-]+)"', d)) missing = sorted(hrefs - ids) print("dead anchors:", missing or "none") return 0 if not missing else 2 if __name__ == "__main__": raise SystemExit(main())