(() => { const each = (selector, handler) => document.querySelectorAll(selector).forEach(handler); const siteHeader = document.querySelector('.site-header'); const mobileMenu = document.querySelector('[data-mobile-menu]'); const mobileMenuOpen = document.querySelector('[data-mobile-menu-open]'); if (siteHeader && mobileMenu && mobileMenuOpen) { const setMobileMenuState = (isOpen) => { mobileMenu.classList.toggle('is-open', isOpen); siteHeader.classList.toggle('is-mobile-menu-open', isOpen); mobileMenuOpen.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); }; mobileMenuOpen.addEventListener('click', () => { setMobileMenuState(true); }); each('[data-mobile-menu-close]', (button) => { button.addEventListener('click', () => { setMobileMenuState(false); }); }); document.addEventListener('keydown', (event) => { if (event.key === 'Escape' && mobileMenu.classList.contains('is-open')) { setMobileMenuState(false); mobileMenuOpen.focus(); } }); const mediaQuery = window.matchMedia('(min-width: 721px)'); const handleViewportChange = (event) => { if (event.matches) { setMobileMenuState(false); } }; if (typeof mediaQuery.addEventListener === 'function') { mediaQuery.addEventListener('change', handleViewportChange); } else if (typeof mediaQuery.addListener === 'function') { mediaQuery.addListener(handleViewportChange); } } each('[data-copy-text]', (button) => { button.addEventListener('click', async () => { const text = button.getAttribute('data-copy-text') || ''; if (!text) { return; } try { await navigator.clipboard.writeText(text); const previous = button.textContent; button.textContent = 'Copié'; window.setTimeout(() => { button.textContent = previous; }, 1200); } catch { window.prompt('Copie ce texte :', text); } }); }); each('[data-confirm]', (form) => { form.addEventListener('submit', (event) => { const message = form.getAttribute('data-confirm') || 'Confirmer cette action ?'; if (!window.confirm(message)) { event.preventDefault(); } }); }); each('[data-char-count]', (field) => { const counter = field.parentElement?.querySelector('[data-char-count-value]'); if (!counter) { return; } const update = () => { counter.textContent = String(field.value.length); }; field.addEventListener('input', update); update(); }); const editor = document.querySelector('[data-markdown-editor]'); if (editor) { const focusEditor = () => editor.focus(); const replaceSelection = (before, after = '', placeholder = '') => { const start = editor.selectionStart; const end = editor.selectionEnd; const selection = editor.value.slice(start, end); const content = selection || placeholder; const insertion = before + content + after; editor.setRangeText(insertion, start, end, 'end'); if (!selection && placeholder) { const cursorStart = start + before.length; editor.setSelectionRange(cursorStart, cursorStart + placeholder.length); } focusEditor(); }; const prefixLines = (prefix, placeholder) => { const start = editor.selectionStart; const end = editor.selectionEnd; const selection = editor.value.slice(start, end) || placeholder; const value = selection .split('\n') .map((line) => (line ? prefix + line : prefix.trimEnd())) .join('\n'); editor.setRangeText(value, start, end, 'end'); focusEditor(); }; each('[data-md-action]', (button) => { button.addEventListener('click', () => { switch (button.getAttribute('data-md-action')) { case 'bold': replaceSelection('**', '**', 'texte'); break; case 'italic': replaceSelection('*', '*', 'texte'); break; case 'heading': prefixLines('## ', 'Titre'); break; case 'list': prefixLines('- ', 'Élément'); break; case 'quote': prefixLines('> ', 'Citation'); break; case 'link': replaceSelection('[', '](https://)', 'texte'); break; case 'code': { const selection = editor.value.slice(editor.selectionStart, editor.selectionEnd); replaceSelection(selection.includes('\n') ? '```\n' : '`', selection.includes('\n') ? '\n```' : '`', 'code'); break; } } }); }); } each('[data-alt-input]', (input) => { const card = input.closest('.card'); const button = card?.querySelector('[data-markdown-template]'); if (!button) { return; } const update = () => { const template = button.getAttribute('data-markdown-template') || ''; button.setAttribute('data-copy-text', template.replace('![](', '![' + input.value + '](')); }; input.addEventListener('input', update); update(); }); })();