AdminTools.fr — Développement

Formatteur HTML / XML / SQL

Indente proprement ou compacte du code HTML, XML ou SQL. Tout est traité localement dans ton navigateur.

', xml: 'ExempleQuelqu\'unAutre', sql: "SELECT u.id, u.nom, COUNT(o.id) AS total FROM utilisateurs u LEFT JOIN commandes o ON o.user_id = u.id WHERE u.actif = 1 GROUP BY u.id, u.nom ORDER BY total DESC LIMIT 10;", }; function setMode(m){ mode = m; [btnModeHtml, btnModeXml, btnModeSql].forEach(b => b.classList.remove('active')); ({html: btnModeHtml, xml: btnModeXml, sql: btnModeSql})[m].classList.add('active'); inputLabel.textContent = 'Entrée ' + m.toUpperCase(); statusBanner.innerHTML = ''; outputArea.value = ''; } btnModeHtml.addEventListener('click', () => setMode('html')); btnModeXml.addEventListener('click', () => setMode('xml')); btnModeSql.addEventListener('click', () => setMode('sql')); function showError(msg){ statusBanner.innerHTML = `
${msg}
`; } function showOk(msg){ statusBanner.innerHTML = `
${msg}
`; } // ---------- HTML / XML : indentation par balises ---------- const VOID_TAGS = new Set(['area','base','br','col','embed','hr','img','input','link','meta','param','source','track','wbr']); function formatMarkup(src, isXml){ let s = src.replace(/>\s+<').trim(); // sépare chaque tag sur sa propre "frontière" sans casser le contenu textuel const tokens = s.split(/(<[^>]+>)/g).filter(t => t.length); let indent = 0; const lines = []; const tab = ' '; for(let i = 0; i < tokens.length; i++){ let tok = tokens[i]; if(tok.startsWith('<')){ const isComment = /^/g, '').replace(/>\s+<').replace(/\s+/g, ' ').trim(); } // ---------- SQL : indentation par mots-clés ---------- const SQL_MAIN_KEYWORDS = ['SELECT','FROM','WHERE','GROUP BY','ORDER BY','HAVING','LIMIT','OFFSET','INSERT INTO','VALUES','UPDATE','SET','DELETE FROM','UNION ALL','UNION']; const SQL_JOIN_KEYWORDS = ['LEFT JOIN','RIGHT JOIN','INNER JOIN','FULL JOIN','LEFT OUTER JOIN','RIGHT OUTER JOIN','JOIN']; function formatSql(src){ let s = src.replace(/\s+/g, ' ').trim(); const allKeywords = [...SQL_JOIN_KEYWORDS, ...SQL_MAIN_KEYWORDS].sort((a,b) => b.length - a.length); for(const kw of allKeywords){ const re = new RegExp('\\s+(' + kw.replace(/ /g, '\\s+') + ')\\s+', 'gi'); s = s.replace(re, '\n' + kw.toUpperCase() + ' '); } s = s.replace(/\s+(AND|OR)\s+/gi, (m, p1) => '\n ' + p1.toUpperCase() + ' '); s = s.replace(/,\s*/g, ',\n '); return s.split('\n').map(l => l.trim()).filter(l => l).join('\n'); } function minifySql(src){ return src.replace(/\s+/g, ' ').replace(/\s*,\s*/g, ', ').trim(); } function doFormat(){ const src = inputArea.value; if(!src.trim()){ showError('Le champ d\'entrée est vide.'); outputArea.value=''; return; } try { let result; if(mode === 'html') result = formatMarkup(src, false); else if(mode === 'xml') result = formatMarkup(src, true); else result = formatSql(src); outputArea.value = result; showOk('Code formaté.'); } catch(e){ showError('Erreur lors du formatage : ' + e.message); outputArea.value = ''; } } function doMinify(){ const src = inputArea.value; if(!src.trim()){ showError('Le champ d\'entrée est vide.'); outputArea.value=''; return; } try { let result; if(mode === 'html' || mode === 'xml') result = minifyMarkup(src); else result = minifySql(src); outputArea.value = result; showOk('Code minifié.'); } catch(e){ showError('Erreur lors de la minification : ' + e.message); outputArea.value = ''; } } btnFormat.addEventListener('click', doFormat); btnMinify.addEventListener('click', doMinify); btnClear.addEventListener('click', function(){ inputArea.value = ''; outputArea.value = ''; statusBanner.innerHTML = ''; }); btnSample.addEventListener('click', function(){ inputArea.value = samples[mode]; statusBanner.innerHTML = ''; outputArea.value = ''; }); btnCopyOutput.addEventListener('click', function(){ if(!outputArea.value) return; navigator.clipboard.writeText(outputArea.value).then(() => { btnCopyOutput.classList.add('copied'); const original = btnCopyOutput.textContent; btnCopyOutput.textContent = 'Copié !'; setTimeout(() => { btnCopyOutput.classList.remove('copied'); btnCopyOutput.textContent = original; }, 1500); }); }); inputArea.value = samples.html; })();