Herzlich willkommen zum SELF-Treffen 2026
vom 24.04. – 26.04.2026
in Halle (Saale)
Beispiel:URL-Decoder.html
<!DOCTYPE html> <html lang="de"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SVG URL-Decoder</title>
<style>
textarea {
width: 100%;
height: 15em;
font-family: monospace;
font-size: 1em;
margin-bottom: 1rem;
}
body {
max-width: 60em;
margin: 2rem auto;
padding: 0 1rem;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1em;
}
h1 {
grid-column: 1 / -1;
}
div {
display: grid;
gap: 1em;
grid-template-columns: 1fr 2em;
}
body > div label {
font: bold 1.25em sans-serif;
}
textarea, #preview {
grid-column: 1 / -1;
aspect-ratio: 2 / 1;
border: thin solid;
}
#preview {
background-repeat: no-repeat;
background-size: contain;
background-position: center;
display: block;
}
</style> </head>
<body>
<label for="encoded">Input URL-encoded</label> <textarea id="encoded" placeholder="Füge hier den URL-kodierten SVG-Code ein..."></textarea>
<label for="css">Input background-image CSS</label>
<textarea id="css" placeholder="background-image: url("data:image/svg+xml,...");"></textarea>
<label for="decoded">Dekodiertes SVG</label> <button data-copy="decoded">📋</button> <textarea id="decoded" placeholder="Hier erscheint der dekodierte SVG-Code..."></textarea>
<label for="preview">So sieht's aus</label>
<script> document.addEventListener('DOMContentLoaded', function () { const encoded = document.getElementById('encoded'); const css = document.getElementById('css'); const decoded = document.getElementById('decoded'); const preview = document.getElementById('preview');
let lock = false;
// --- Hilfsfunktionen ---
function clearAll() {
lock = true; encoded.value = ; css.value = ; decoded.value = ; preview.style.backgroundImage = ; lock = false;
}
function extractEncodedFromCSS(cssText) {
const match = cssText.match(/url\s*\(\s*["']?data:image\/svg\+xml,([^"')]+)["']?\s*\)/); return match ? match[1] : null;
}
function ensureXmlns(svg) {
if (svg.includes('<svg') && !svg.includes('xmlns=')) {
return svg.replace(/<svg/, '<svg xmlns="http://www.w3.org/2000/svg"');
}
return svg;
}
function compactSVG(svg) {
return svg
.trim()
.replace(/\r?\n|\r/g, )
.replace(/\t+/g, ' ')
.replace(/\s{2,}/g, ' ')
.replace(/>\s+</g, '><');
}
function encodeSVG(svg) {
return encodeURIComponent(svg) .replace(/%0A/g, ) .replace(/%20/g, ' ') .replace(/%3D/g, '=') .replace(/%3A/g, ':') .replace(/%2F/g, '/');
}
function formatSVG(svg) {
svg = ensureXmlns(svg);
let formatted = svg
.replace(/></g, '>\n<')
.replace(/(<svg[^>]*>)/g, '$1\n')
.replace(/(<\/svg>)/g, '\n$1');
let lines = formatted.split('\n');
let indent = 0;
let result = [];
lines.forEach(line => {
line = line.trim();
if (!line) return;
if (line.startsWith('</')) {
indent = Math.max(0, indent - 2);
}
result.push(' '.repeat(indent) + line);
if (line.startsWith('<') && !line.startsWith('</') && !line.endsWith('/>')) {
if (!line.match(/<[^>]+>.*<\/[^>]+>/)) {
indent += 2;
}
}
});
return result.join('\n');
}
// --- Update-Funktionen ---
function updateFromEncoded(enc) {
try {
const svg = decodeURIComponent(enc);
const svgWithXmlns = ensureXmlns(svg);
const formatted = formatSVG(svg);
const compact = compactSVG(svgWithXmlns);
const encWithXmlns = encodeSVG(compact);
const cssText = `background-image: url("data:image/svg+xml,${encWithXmlns}");`;
decoded.value = formatted;
css.value = cssText;
preview.style.backgroundImage = `url("data:image/svg+xml,${encWithXmlns}")`;
} catch (e) {
decoded.value = 'Fehler beim Dekodieren: ' + e.message;
preview.style.backgroundImage = ;
}
}
function updateFromCSS(cssText) {
try {
const enc = extractEncodedFromCSS(cssText);
if (!enc) {
throw new Error('Kein gültiger data:image/svg+xml URL gefunden');
}
const svg = decodeURIComponent(enc);
const svgWithXmlns = ensureXmlns(svg);
const formatted = formatSVG(svg);
const compact = compactSVG(svgWithXmlns);
const encWithXmlns = encodeSVG(compact);
encoded.value = encWithXmlns;
decoded.value = formatted;
preview.style.backgroundImage = `url("data:image/svg+xml,${encWithXmlns}")`;
} catch (e) {
decoded.value = 'Fehler beim Dekodieren: ' + e.message;
preview.style.backgroundImage = ;
}
}
function updateFromDecoded(svg) {
try {
svg = ensureXmlns(svg);
const compact = compactSVG(svg);
const enc = encodeSVG(compact);
const cssText = `background-image: url("data:image/svg+xml,${enc}");`;
encoded.value = enc;
css.value = cssText;
preview.style.backgroundImage = `url("data:image/svg+xml,${enc}")`;
} catch (e) {
encoded.value = 'Fehler beim Kodieren: ' + e.message;
preview.style.backgroundImage = ;
}
}
// --- Event Listeners ---
encoded.addEventListener('input', () => {
if (lock) return;
if (!encoded.value.trim()) {
clearAll();
return;
}
lock = true;
updateFromEncoded(encoded.value);
lock = false;
});
css.addEventListener('input', () => {
if (lock) return;
if (!css.value.trim()) {
clearAll();
return;
}
lock = true;
updateFromCSS(css.value);
lock = false;
});
decoded.addEventListener('input', () => {
if (lock) return;
if (!decoded.value.trim()) {
clearAll();
return;
}
lock = true;
updateFromDecoded(decoded.value);
lock = false;
});
document.querySelectorAll('[data-copy]').forEach(btn => {
btn.addEventListener('click', () => {
const id = btn.dataset.copy;
const el = document.getElementById(id);
if (!el) return;
const textToCopy = el.value || ;
if (!textToCopy) return;
navigator.clipboard.writeText(textToCopy).then(() => {
const old = btn.textContent;
btn.textContent = '✓';
setTimeout(() => btn.textContent = old, 800);
}).catch(err => {
console.error('Copy failed:', err);
});
});
}); }); </script>
</body> </html>