Initial commit: DNS Things - Comprehensive DNS utility website

Features implemented:
- Modular JavaScript architecture (theme.js, dns-tools.js, whois.js, punycode.js, ip-tools.js, main.js)
- Responsive design with dark/light theme toggle
- DNS Lookup and Reverse DNS Lookup tools
- Whois Lookup functionality
- IDN Punycode Converter with full Unicode support
- Comprehensive IP Address Tools (validation, IPv4-to-IPv6 mapping, IPv6 compression/expansion)
- Dynamic tab descriptions that change based on active tool
- Mobile-responsive horizontal scrollable tabs
- Copy-to-clipboard functionality for all results
- Clean footer with dynamic year
- IPv4-mapped IPv6 address explanation with clear warnings

Technical improvements:
- Separated concerns with modular JS files
- Fixed browser compatibility issues with punycode library
- Implemented proper error handling and user feedback
- Added comprehensive input validation
- Optimized for mobile devices with touch-friendly UI
This commit is contained in:
dwindown
2025-08-01 23:13:52 +07:00
commit e5195ba1f1
9 changed files with 1824 additions and 0 deletions

176
assets/js/punycode.js Normal file
View File

@@ -0,0 +1,176 @@
// DNS Things - Punycode Module
// Real Punycode conversion functions using punycode.js library
function toPunycode(domain) {
try {
// Check if punycode library is available
if (typeof punycode === 'undefined') {
throw new Error('Punycode library not loaded');
}
// Split domain into parts and convert each part
const parts = domain.split('.');
const convertedParts = parts.map(part => {
// Check if part contains non-ASCII characters
if (/[^\x00-\x7F]/.test(part)) {
return punycode.toASCII(part);
}
return part;
});
return convertedParts.join('.');
} catch (error) {
// Fallback to URL API if punycode library fails
try {
const url = new URL(`http://${domain}`);
return url.hostname;
} catch {
throw new Error('Invalid domain format');
}
}
}
function fromPunycode(domain) {
try {
// Check if domain contains punycode
if (!domain.includes('xn--')) {
return domain; // No punycode to convert
}
// Check if punycode library is available
if (typeof punycode === 'undefined') {
throw new Error('Punycode library not loaded');
}
// Split domain into parts and convert each part
const parts = domain.split('.');
const convertedParts = parts.map(part => {
if (part.startsWith('xn--')) {
try {
return punycode.toUnicode(part);
} catch {
return part; // Return original if conversion fails
}
}
return part;
});
return convertedParts.join('.');
} catch (error) {
throw new Error('Invalid punycode format');
}
}
// Initialize IDN Punycode Converter
function initPunycodeConverter() {
const unicodeInput = document.getElementById('unicode-input');
const punycodeInput = document.getElementById('punycode-input');
const unicodeToPunycodeBtn = document.getElementById('unicode-to-punycode-btn');
const punycodeToUnicodeBtn = document.getElementById('punycode-to-unicode-btn');
const punycodeResult = document.getElementById('punycode-result');
const unicodeResult = document.getElementById('unicode-result');
if (!unicodeInput || !punycodeInput) return;
// Unicode to Punycode conversion
const convertUnicodeToPunycode = () => {
const input = unicodeInput.value.trim();
if (!input) {
punycodeResult.innerHTML = '';
return;
}
try {
const converted = toPunycode(input);
const isConverted = converted !== input;
punycodeResult.innerHTML = `
<div class="p-4 bg-green-50 dark:bg-green-900/30 rounded-lg">
<div class="flex justify-between items-start">
<div class="flex-1">
<h5 class="font-medium text-green-800 dark:text-green-200 mb-2">Punycode Result:</h5>
<div class="font-mono text-sm break-all p-2 bg-white dark:bg-gray-800 rounded border">${converted}</div>
${isConverted ? '<p class="text-xs text-green-600 dark:text-green-400 mt-2">✅ Conversion applied</p>' : '<p class="text-xs text-gray-500 dark:text-gray-400 mt-2"> No conversion needed (ASCII only)</p>'}
</div>
<button onclick="copyToClipboard('${converted}', this)" class="ml-2 p-2 text-green-600 dark:text-green-400 hover:bg-green-100 dark:hover:bg-green-800 rounded" title="Copy to clipboard">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
</svg>
</button>
</div>
</div>
`;
} catch (error) {
punycodeResult.innerHTML = `
<div class="p-4 bg-red-50 dark:bg-red-900/30 text-red-700 dark:text-red-300 rounded-lg">
<h5 class="font-medium mb-1">Error:</h5>
<p class="text-sm">${error.message}</p>
</div>
`;
}
};
// Punycode to Unicode conversion
const convertPunycodeToUnicode = () => {
const input = punycodeInput.value.trim();
if (!input) {
unicodeResult.innerHTML = '';
return;
}
try {
const converted = fromPunycode(input);
const isConverted = converted !== input;
unicodeResult.innerHTML = `
<div class="p-4 bg-green-50 dark:bg-green-900/30 rounded-lg">
<div class="flex justify-between items-start">
<div class="flex-1">
<h5 class="font-medium text-green-800 dark:text-green-200 mb-2">Unicode Result:</h5>
<div class="font-mono text-sm break-all p-2 bg-white dark:bg-gray-800 rounded border">${converted}</div>
${isConverted ? '<p class="text-xs text-green-600 dark:text-green-400 mt-2">✅ Conversion applied</p>' : '<p class="text-xs text-gray-500 dark:text-gray-400 mt-2"> No conversion needed (no punycode found)</p>'}
</div>
<button onclick="copyToClipboard('${converted}', this)" class="ml-2 p-2 text-green-600 dark:text-green-400 hover:bg-green-100 dark:hover:bg-green-800 rounded" title="Copy to clipboard">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
</svg>
</button>
</div>
</div>
`;
} catch (error) {
unicodeResult.innerHTML = `
<div class="p-4 bg-red-50 dark:bg-red-900/30 text-red-700 dark:text-red-300 rounded-lg">
<h5 class="font-medium mb-1">Error:</h5>
<p class="text-sm">${error.message}</p>
</div>
`;
}
};
// Event listeners
unicodeToPunycodeBtn.addEventListener('click', convertUnicodeToPunycode);
punycodeToUnicodeBtn.addEventListener('click', convertPunycodeToUnicode);
// Auto-convert on input (with debounce)
let unicodeTimeout, punycodeTimeout;
unicodeInput.addEventListener('input', () => {
clearTimeout(unicodeTimeout);
unicodeTimeout = setTimeout(convertUnicodeToPunycode, 500);
});
punycodeInput.addEventListener('input', () => {
clearTimeout(punycodeTimeout);
punycodeTimeout = setTimeout(convertPunycodeToUnicode, 500);
});
// Paste support
unicodeInput.addEventListener('paste', () => {
setTimeout(convertUnicodeToPunycode, 100);
});
punycodeInput.addEventListener('paste', () => {
setTimeout(convertPunycodeToUnicode, 100);
});
}