457 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			457 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <!DOCTYPE html>
 | |
| <html lang="de">
 | |
| <head>
 | |
|     <meta charset="UTF-8">
 | |
|     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | |
|     <title>Text Decoder - Kodieren und Dekodieren von Text</title>
 | |
|     <meta name="description" content="Einfaches Tool zum Kodieren und Dekodieren von Text in verschiedene Formate wie Base64, URL, HTML und mehr.">
 | |
|     <meta property="og:title" content="Text Decoder - Kodieren und Dekodieren von Text">
 | |
|     <meta property="og:description" content="Einfaches Tool zum Kodieren und Dekodieren von Text in verschiedene Formate wie Base64, URL, HTML und mehr.">
 | |
|     <meta property="og:type" content="website">
 | |
|     <meta property="og:url" content="https://ponywave.de/text_decoder/">
 | |
|     <link rel="icon" href="../favicon.png" type="image/png">
 | |
|     <script defer src="https://stats.ponywave.de/script" data-website-id="9ef713d2-adb9-4906-9df5-708d8a8b9131" data-tag="text_decoder"></script>
 | |
|     <style>
 | |
|         :root {
 | |
|             --bg-color: #f5f5f5;
 | |
|             --text-color: #333;
 | |
|             --primary-color: #4a6fa5;
 | |
|             --secondary-color: #6c757d;
 | |
|             --border-color: #dee2e6;
 | |
|             --card-bg: #ffffff;
 | |
|             --button-bg: #4a6fa5;
 | |
|             --button-text: #ffffff;
 | |
|             --button-hover: #3a5a8f;
 | |
|             --input-bg: #ffffff;
 | |
|             --input-border: #ced4da;
 | |
|         }
 | |
| 
 | |
|         [data-theme="dark"] {
 | |
|             --bg-color: #121212;
 | |
|             --text-color: #e0e0e0;
 | |
|             --primary-color: #6d9eeb;
 | |
|             --secondary-color: #adb5bd;
 | |
|             --border-color: #495057;
 | |
|             --card-bg: #1e1e1e;
 | |
|             --button-bg: #6d9eeb;
 | |
|             --button-text: #121212;
 | |
|             --button-hover: #5a8ad8;
 | |
|             --input-bg: #2d2d2d;
 | |
|             --input-border: #495057;
 | |
|         }
 | |
| 
 | |
|         * {
 | |
|             box-sizing: border-box;
 | |
|             margin: 0;
 | |
|             padding: 0;
 | |
|             transition: background-color 0.3s, color 0.3s;
 | |
|         }
 | |
| 
 | |
|         body {
 | |
|             font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 | |
|             background-color: var(--bg-color);
 | |
|             color: var(--text-color);
 | |
|             line-height: 1.6;
 | |
|             padding: 20px;
 | |
|             max-width: 1200px;
 | |
|             margin: 0 auto;
 | |
|         }
 | |
| 
 | |
|         header {
 | |
|             text-align: center;
 | |
|             margin-bottom: 30px;
 | |
|             position: relative;
 | |
|         }
 | |
| 
 | |
|         h1 {
 | |
|             color: var(--primary-color);
 | |
|             margin-bottom: 10px;
 | |
|         }
 | |
| 
 | |
|         .theme-toggle {
 | |
|             position: absolute;
 | |
|             top: 0;
 | |
|             right: 0;
 | |
|             background: none;
 | |
|             border: none;
 | |
|             font-size: 1.5rem;
 | |
|             cursor: pointer;
 | |
|             color: var(--text-color);
 | |
|             padding: 5px;
 | |
|         }
 | |
| 
 | |
|         .container {
 | |
|             display: grid;
 | |
|             grid-template-columns: 1fr;
 | |
|             gap: 20px;
 | |
|         }
 | |
| 
 | |
|         @media (min-width: 768px) {
 | |
|             .container {
 | |
|                 grid-template-columns: 1fr 1fr;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         .card {
 | |
|             background-color: var(--card-bg);
 | |
|             border-radius: 8px;
 | |
|             padding: 20px;
 | |
|             box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
 | |
|         }
 | |
| 
 | |
|         .input-group {
 | |
|             margin-bottom: 15px;
 | |
|         }
 | |
| 
 | |
|         label {
 | |
|             display: block;
 | |
|             margin-bottom: 5px;
 | |
|             font-weight: 600;
 | |
|         }
 | |
| 
 | |
|         textarea, select {
 | |
|             width: 100%;
 | |
|             padding: 10px;
 | |
|             border: 1px solid var(--input-border);
 | |
|             border-radius: 4px;
 | |
|             background-color: var(--input-bg);
 | |
|             color: var(--text-color);
 | |
|             font-family: 'Consolas', monospace;
 | |
|             resize: vertical;
 | |
|             min-height: 150px;
 | |
|         }
 | |
| 
 | |
|         select {
 | |
|             min-height: auto;
 | |
|             cursor: pointer;
 | |
|         }
 | |
| 
 | |
|         button {
 | |
|             background-color: var(--button-bg);
 | |
|             color: var(--button-text);
 | |
|             border: none;
 | |
|             border-radius: 4px;
 | |
|             padding: 10px 15px;
 | |
|             cursor: pointer;
 | |
|             font-weight: 600;
 | |
|             margin-right: 10px;
 | |
|             margin-bottom: 10px;
 | |
|         }
 | |
| 
 | |
|         button:hover {
 | |
|             background-color: var(--button-hover);
 | |
|         }
 | |
| 
 | |
|         .button-group {
 | |
|             display: flex;
 | |
|             flex-wrap: wrap;
 | |
|             margin-bottom: 15px;
 | |
|         }
 | |
| 
 | |
|         footer {
 | |
|             text-align: center;
 | |
|             margin-top: 30px;
 | |
|             color: var(--secondary-color);
 | |
|             font-size: 0.9rem;
 | |
|         }
 | |
| 
 | |
|         a {
 | |
|             color: var(--primary-color);
 | |
|             text-decoration: none;
 | |
|         }
 | |
| 
 | |
|         a:hover {
 | |
|             text-decoration: underline;
 | |
|         }
 | |
|     </style>
 | |
| </head>
 | |
| <body>
 | |
|     <header>
 | |
|         <h1>Text Decoder</h1>
 | |
|         <p>Kodieren und Dekodieren von Text in verschiedene Formate</p>
 | |
|         <button class="theme-toggle" id="themeToggle" aria-label="Farbschema wechseln">☀️</button>
 | |
|     </header>
 | |
| 
 | |
|     <div class="container">
 | |
|         <div class="card">
 | |
|             <div class="input-group">
 | |
|                 <label for="inputText">Eingabetext:</label>
 | |
|                 <textarea id="inputText" placeholder="Text zum Kodieren/Dekodieren hier eingeben..."></textarea>
 | |
|             </div>
 | |
|             
 | |
|             <div class="input-group">
 | |
|                 <label for="formatSelect">Format auswählen:</label>
 | |
|                 <select id="formatSelect">
 | |
|                     <option value="base64">Base64</option>
 | |
|                     <option value="url">URL</option>
 | |
|                     <option value="html">HTML</option>
 | |
|                     <option value="hex">Hexadezimal</option>
 | |
|                     <option value="binary">Binär</option>
 | |
|                     <option value="morse">Morse-Code</option>
 | |
|                     <option value="rot13">ROT13</option>
 | |
|                     <option value="caesar">Caesar-Verschlüsselung</option>
 | |
|                 </select>
 | |
|             </div>
 | |
| 
 | |
|             <div class="button-group">
 | |
|                 <button id="encodeBtn">Kodieren</button>
 | |
|                 <button id="decodeBtn">Dekodieren</button>
 | |
|                 <button id="clearBtn">Löschen</button>
 | |
|             </div>
 | |
| 
 | |
|             <div id="caesarOptions" style="display: none;" class="input-group">
 | |
|                 <label for="shiftAmount">Verschiebung (1-25):</label>
 | |
|                 <input type="number" id="shiftAmount" min="1" max="25" value="3" style="width: 100%; padding: 10px; border: 1px solid var(--input-border); border-radius: 4px; background-color: var(--input-bg); color: var(--text-color);">
 | |
|             </div>
 | |
|         </div>
 | |
| 
 | |
|         <div class="card">
 | |
|             <div class="input-group">
 | |
|                 <label for="outputText">Ergebnis:</label>
 | |
|                 <textarea id="outputText" readonly></textarea>
 | |
|             </div>
 | |
|             
 | |
|             <div class="button-group">
 | |
|                 <button id="copyBtn">In Zwischenablage kopieren</button>
 | |
|                 <button id="swapBtn">Mit Eingabe tauschen</button>
 | |
|             </div>
 | |
|         </div>
 | |
|     </div>
 | |
| 
 | |
|     <footer>
 | |
|         <p><a href="https://tools.ponywave.de/">Zurück zur Startseite</a> | © <span id="current-year"></span> Akamaru | Made with <span class="heart">❤️</span> by Claude</p>
 | |
|     </footer>
 | |
| 
 | |
|     <script>
 | |
|         // Set current year in footer
 | |
|         document.getElementById('current-year').textContent = new Date().getFullYear();
 | |
|         
 | |
|         // Theme Toggle Functionality
 | |
|         const themeToggle = document.getElementById('themeToggle');
 | |
|         const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
 | |
|         
 | |
|         // Set initial theme based on user preference
 | |
|         if (localStorage.getItem('theme')) {
 | |
|             document.documentElement.setAttribute('data-theme', localStorage.getItem('theme'));
 | |
|             themeToggle.textContent = localStorage.getItem('theme') === 'dark' ? '🌙' : '☀️';
 | |
|         } else if (prefersDarkScheme.matches) {
 | |
|             document.documentElement.setAttribute('data-theme', 'dark');
 | |
|             themeToggle.textContent = '🌙';
 | |
|         }
 | |
|         
 | |
|         themeToggle.addEventListener('click', () => {
 | |
|             const currentTheme = document.documentElement.getAttribute('data-theme');
 | |
|             const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
 | |
|             
 | |
|             document.documentElement.setAttribute('data-theme', newTheme);
 | |
|             localStorage.setItem('theme', newTheme);
 | |
|             themeToggle.textContent = newTheme === 'dark' ? '🌙' : '☀️';
 | |
|         });
 | |
| 
 | |
|         // DOM Elements
 | |
|         const inputText = document.getElementById('inputText');
 | |
|         const outputText = document.getElementById('outputText');
 | |
|         const formatSelect = document.getElementById('formatSelect');
 | |
|         const encodeBtn = document.getElementById('encodeBtn');
 | |
|         const decodeBtn = document.getElementById('decodeBtn');
 | |
|         const clearBtn = document.getElementById('clearBtn');
 | |
|         const copyBtn = document.getElementById('copyBtn');
 | |
|         const swapBtn = document.getElementById('swapBtn');
 | |
|         const caesarOptions = document.getElementById('caesarOptions');
 | |
|         const shiftAmount = document.getElementById('shiftAmount');
 | |
| 
 | |
|         // Show/hide Caesar options based on format selection
 | |
|         formatSelect.addEventListener('change', () => {
 | |
|             caesarOptions.style.display = formatSelect.value === 'caesar' ? 'block' : 'none';
 | |
|         });
 | |
| 
 | |
|         // Encode function
 | |
|         encodeBtn.addEventListener('click', () => {
 | |
|             const text = inputText.value;
 | |
|             const format = formatSelect.value;
 | |
|             
 | |
|             if (!text) {
 | |
|                 alert('Bitte gib einen Text ein!');
 | |
|                 return;
 | |
|             }
 | |
|             
 | |
|             try {
 | |
|                 let result;
 | |
|                 switch (format) {
 | |
|                     case 'base64':
 | |
|                         result = btoa(unescape(encodeURIComponent(text)));
 | |
|                         break;
 | |
|                     case 'url':
 | |
|                         result = encodeURIComponent(text);
 | |
|                         break;
 | |
|                     case 'html':
 | |
|                         result = text.replace(/&/g, '&')
 | |
|                                     .replace(/</g, '<')
 | |
|                                     .replace(/>/g, '>')
 | |
|                                     .replace(/"/g, '"')
 | |
|                                     .replace(/'/g, ''');
 | |
|                         break;
 | |
|                     case 'hex':
 | |
|                         result = Array.from(text).map(c => 
 | |
|                             c.charCodeAt(0).toString(16).padStart(2, '0')
 | |
|                         ).join('');
 | |
|                         break;
 | |
|                     case 'binary':
 | |
|                         result = Array.from(text).map(c => 
 | |
|                             c.charCodeAt(0).toString(2).padStart(8, '0')
 | |
|                         ).join(' ');
 | |
|                         break;
 | |
|                     case 'morse':
 | |
|                         const morseDict = {
 | |
|                             'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.', 'H': '....', 'I': '..', 'J': '.---',
 | |
|                             'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-',
 | |
|                             'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-', 'Y': '-.--', 'Z': '--..', '0': '-----', '1': '.----', '2': '..---',
 | |
|                             '3': '...--', '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.', '.': '.-.-.-',
 | |
|                             ',': '--..--', '?': '..--..', "'": '.----.', '!': '-.-.--', '/': '-..-.', '(': '-.--.', ')': '-.--.-', '&': '.-...',
 | |
|                             ':': '---...', ';': '-.-.-.', '=': '-...-', '+': '.-.-.', '-': '-....-', '_': '..--.-', '"': '.-..-.', '$': '...-..-',
 | |
|                             '@': '.--.-.'
 | |
|                         };
 | |
|                         result = text.toUpperCase().split('').map(c => {
 | |
|                             if (c === ' ') return '/';
 | |
|                             return morseDict[c] || c;
 | |
|                         }).join(' ');
 | |
|                         break;
 | |
|                     case 'rot13':
 | |
|                         result = text.replace(/[a-zA-Z]/g, c => {
 | |
|                             const code = c.charCodeAt(0);
 | |
|                             return String.fromCharCode(
 | |
|                                 ((code >= 65 && code <= 90) ? ((code - 65 + 13) % 26 + 65) : 
 | |
|                                 (code >= 97 && code <= 122) ? ((code - 97 + 13) % 26 + 97) : code)
 | |
|                             );
 | |
|                         });
 | |
|                         break;
 | |
|                     case 'caesar':
 | |
|                         const shift = parseInt(shiftAmount.value) || 3;
 | |
|                         result = text.replace(/[a-zA-Z]/g, c => {
 | |
|                             const code = c.charCodeAt(0);
 | |
|                             if (code >= 65 && code <= 90) { // Uppercase
 | |
|                                 return String.fromCharCode(((code - 65 + shift) % 26) + 65);
 | |
|                             } else if (code >= 97 && code <= 122) { // Lowercase
 | |
|                                 return String.fromCharCode(((code - 97 + shift) % 26) + 97);
 | |
|                             }
 | |
|                             return c;
 | |
|                         });
 | |
|                         break;
 | |
|                     default:
 | |
|                         result = 'Nicht unterstütztes Format';
 | |
|                 }
 | |
|                 outputText.value = result;
 | |
|             } catch (error) {
 | |
|                 outputText.value = `Fehler: ${error.message}`;
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         // Decode function
 | |
|         decodeBtn.addEventListener('click', () => {
 | |
|             const text = inputText.value;
 | |
|             const format = formatSelect.value;
 | |
|             
 | |
|             if (!text) {
 | |
|                 alert('Bitte gib einen Text ein!');
 | |
|                 return;
 | |
|             }
 | |
|             
 | |
|             try {
 | |
|                 let result;
 | |
|                 switch (format) {
 | |
|                     case 'base64':
 | |
|                         result = decodeURIComponent(escape(atob(text)));
 | |
|                         break;
 | |
|                     case 'url':
 | |
|                         result = decodeURIComponent(text);
 | |
|                         break;
 | |
|                     case 'html':
 | |
|                         result = text.replace(/&/g, '&')
 | |
|                                     .replace(/</g, '<')
 | |
|                                     .replace(/>/g, '>')
 | |
|                                     .replace(/"/g, '"')
 | |
|                                     .replace(/'/g, "'");
 | |
|                         break;
 | |
|                     case 'hex':
 | |
|                         result = text.match(/.{1,2}/g)?.map(byte => 
 | |
|                             String.fromCharCode(parseInt(byte, 16))
 | |
|                         ).join('') || '';
 | |
|                         break;
 | |
|                     case 'binary':
 | |
|                         result = text.split(' ').map(bin => 
 | |
|                             String.fromCharCode(parseInt(bin, 2))
 | |
|                         ).join('');
 | |
|                         break;
 | |
|                     case 'morse':
 | |
|                         const morseDict = {
 | |
|                             '.-': 'A', '-...': 'B', '-.-.': 'C', '-..': 'D', '.': 'E', '..-.': 'F', '--.': 'G', '....': 'H', '..': 'I', '.---': 'J',
 | |
|                             '-.-': 'K', '.-..': 'L', '--': 'M', '-.': 'N', '---': 'O', '.--.': 'P', '--.-': 'Q', '.-.': 'R', '...': 'S', '-': 'T',
 | |
|                             '..-': 'U', '...-': 'V', '.--': 'W', '-..-': 'X', '-.--': 'Y', '--..': 'Z', '-----': '0', '.----': '1', '..---': '2',
 | |
|                             '...--': '3', '....-': '4', '.....': '5', '-....': '6', '--...': '7', '---..': '8', '----.': '9', '.-.-.-': '.',
 | |
|                             '--..--': ',', '..--..': '?', '.----.': "'", '-.-.--': '!', '-..-.': '/', '-.--.': '(', '-.--.-': ')', '.-...': '&',
 | |
|                             '---...': ':', '-.-.-.': ';', '-...-': '=', '.-.-.': '+', '-....-': '-', '..--.-': '_', '.-..-.': '"', '...-..-': '$',
 | |
|                             '.--.-.': '@'
 | |
|                         };
 | |
|                         result = text.split(' ').map(m => {
 | |
|                             if (m === '/') return ' ';
 | |
|                             return morseDict[m] || m;
 | |
|                         }).join('');
 | |
|                         break;
 | |
|                     case 'rot13':
 | |
|                         result = text.replace(/[a-zA-Z]/g, c => {
 | |
|                             const code = c.charCodeAt(0);
 | |
|                             return String.fromCharCode(
 | |
|                                 ((code >= 65 && code <= 90) ? ((code - 65 + 13) % 26 + 65) : 
 | |
|                                 (code >= 97 && code <= 122) ? ((code - 97 + 13) % 26 + 97) : code)
 | |
|                             );
 | |
|                         });
 | |
|                         break;
 | |
|                     case 'caesar':
 | |
|                         const shift = parseInt(shiftAmount.value) || 3;
 | |
|                         result = text.replace(/[a-zA-Z]/g, c => {
 | |
|                             const code = c.charCodeAt(0);
 | |
|                             if (code >= 65 && code <= 90) { // Uppercase
 | |
|                                 return String.fromCharCode(((code - 65 - shift + 26) % 26) + 65);
 | |
|                             } else if (code >= 97 && code <= 122) { // Lowercase
 | |
|                                 return String.fromCharCode(((code - 97 - shift + 26) % 26) + 97);
 | |
|                             }
 | |
|                             return c;
 | |
|                         });
 | |
|                         break;
 | |
|                     default:
 | |
|                         result = 'Nicht unterstütztes Format';
 | |
|                 }
 | |
|                 outputText.value = result;
 | |
|             } catch (error) {
 | |
|                 outputText.value = `Fehler: ${error.message}`;
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         // Clear button
 | |
|         clearBtn.addEventListener('click', () => {
 | |
|             inputText.value = '';
 | |
|             outputText.value = '';
 | |
|         });
 | |
| 
 | |
|         // Copy button
 | |
|         copyBtn.addEventListener('click', () => {
 | |
|             outputText.select();
 | |
|             document.execCommand('copy');
 | |
|             
 | |
|             // Visual feedback
 | |
|             const originalText = copyBtn.textContent;
 | |
|             copyBtn.textContent = 'Kopiert!';
 | |
|             setTimeout(() => {
 | |
|                 copyBtn.textContent = originalText;
 | |
|             }, 1500);
 | |
|         });
 | |
| 
 | |
|         // Swap button
 | |
|         swapBtn.addEventListener('click', () => {
 | |
|             const temp = inputText.value;
 | |
|             inputText.value = outputText.value;
 | |
|             outputText.value = temp;
 | |
|         });
 | |
|     </script>
 | |
| </body>
 | |
| </html>  |