/**
* Simple Litecoin Paper Wallet Generator
* Interface Module - Updated with QR code fix and Async BIP38 Handling
*/
// Function to create the artistic wallet HTML (Keep as is)
function createArtisticWalletHtmlString(address, key, imageData, index = 1) {
// ... (your existing function content) ...
const keyElementClass = 'ltcprivwif'; // Or determine if encrypted
const keyElementId = keyElementClass + index;
// Now create the HTML using the template literal
const walletHtml = `
<div class='artwallet1' id='artwallet1${index}'>
<img id='paperpng1${index}' class='paperpng1' src='${imageData}' alt='Wallet Background' />
<div id='qrcode_public${index}' class='qrcode_public'></div>
<div id='qrcode_private${index}' class='qrcode_private'></div>
<div class='ltcaddress' id='ltcaddress${index}'>${address}</div>
<div class='${keyElementClass}' id='${keyElementId}'>${key}</div>
</div>
`;
return walletHtml;
}
document.addEventListener('DOMContentLoaded', function() {
// Check if critical libraries are loaded
console.log('QRCode available:', typeof QRCode === 'function');
console.log('SecureRandom available:', typeof SecureRandom === 'function');
console.log('Crypto available:', typeof Crypto !== 'undefined');
// Initialize the application
initApp();
console.log('Application initialized');
});
// Initialize the application
function initApp() {
// Set up event listeners
setupEventListeners();
// Initialize entropy collector - Assuming EntropyCollector object exists globally
if (typeof EntropyCollector !== 'undefined') {
EntropyCollector.init();
} else {
console.error("EntropyCollector not defined!");
}
}
// Set up event listeners for user interactions
function setupEventListeners() {
// Start button
const startBtn = document.getElementById('start-btn');
if (startBtn) {
startBtn.addEventListener('click', startWalletGeneration);
console.log('Start button listener added');
}
// Advanced options toggle
const showAdvancedBtn = document.getElementById('show-advanced');
if (showAdvancedBtn) {
showAdvancedBtn.addEventListener('click', function(e) {
e.preventDefault();
toggleAdvancedOptions();
});
}
// BIP38 encryption checkbox
const bip38Checkbox = document.getElementById('bip38-checkbox');
if (bip38Checkbox) {
bip38Checkbox.addEventListener('change', function() {
toggleBip38PasswordFields();
});
}
// Entropy continue button
const entropyContinueBtn = document.getElementById('entropy-continue');
if (entropyContinueBtn) {
entropyContinueBtn.addEventListener('click', function() {
console.log('Continue button clicked');
generateWallet(); // Call the async function directly
});
console.log('Continue button listener added');
}
// Print button
const printBtn = document.getElementById('print-btn');
if (printBtn) {
printBtn.addEventListener('click', printWallet);
}
// New wallet button
const newWalletBtn = document.getElementById('new-wallet-btn');
if (newWalletBtn) {
newWalletBtn.addEventListener('click', resetAndStartOver);
}
}
// Start the wallet generation process
function startWalletGeneration() {
console.log('Starting wallet generation process');
// Hide intro section and show entropy section
showSection('entropy');
// Start entropy collection - Assuming EntropyCollector.start exists
if (typeof EntropyCollector !== 'undefined') {
EntropyCollector.start(function(seed) {
// This callback will be called when entropy collection is complete
// The seed will be used to generate the wallet
console.log('Entropy collection complete, seed generated');
document.getElementById('entropy-continue').disabled = false;
});
} else {
console.error("EntropyCollector not defined, cannot start collection.");
// Maybe enable continue button anyway or show error
document.getElementById('entropy-continue').disabled = false;
}
}
// Toggle advanced options visibility
function toggleAdvancedOptions() {
const advancedOptions = document.getElementById('advanced-options');
const showAdvancedLink = document.getElementById('show-advanced');
if (advancedOptions && showAdvancedLink) {
if (advancedOptions.style.display === 'none' || advancedOptions.style.display === '') {
advancedOptions.style.display = 'block';
showAdvancedLink.textContent = 'Hide Advanced Options';
} else {
advancedOptions.style.display = 'none';
showAdvancedLink.textContent = 'Advanced Options';
}
}
}
// Toggle BIP38 password fields visibility
function toggleBip38PasswordFields() {
const passwordContainer = document.getElementById('bip38-password-container');
const isChecked = document.getElementById('bip38-checkbox').checked;
if (passwordContainer) {
passwordContainer.style.display = isChecked ? 'block' : 'none';
}
}
// ****************************************************************
// Generate wallet using collected entropy - MODIFIED FOR ASYNC
// ****************************************************************
async function generateWallet() { // <-- Added async keyword
const continueBtn = document.getElementById('entropy-continue'); // Get button reference
try {
console.log('Generating wallet (async)...');
// --- Provide UI Feedback ---
if (continueBtn) {
continueBtn.disabled = true; // Disable button
continueBtn.textContent = 'Generating...'; // Update text
}
// --- Get Entropy ---
const entropyInput = document.getElementById('entropy-text');
const additionalEntropy = entropyInput ? entropyInput.value : '';
// --- Check BIP38 Options ---
const useEncryption = document.getElementById('bip38-checkbox') ?
document.getElementById('bip38-checkbox').checked : false;
let password = '';
if (useEncryption) {
const passwordInput = document.getElementById('bip38-password');
const confirmInput = document.getElementById('bip38-confirm');
// Add checks for element existence
if (!passwordInput || !confirmInput) {
throw new Error('Password input fields not found.');
}
if (!passwordInput.value) {
throw new Error('Please enter a password for encryption.'); // Use throw instead of alert here
}
if (passwordInput.value !== confirmInput.value) {
throw new Error('Passwords do not match.'); // Use throw instead of alert
}
password = passwordInput.value;
console.log("BIP38 Encryption requested.");
} else {
console.log("BIP38 Encryption NOT requested.");
}
// --- Call the ASYNC wallet generation function ---
console.log("Calling LitecoinWallet.generateWallet...");
const wallet = await LitecoinWallet.generateWallet(additionalEntropy, useEncryption, password); // <--- Added 'await'
console.log("LitecoinWallet.generateWallet finished. Result:", wallet);
// --- Validate Result ---
if (!wallet || !wallet.publicAddress || !wallet.privateKey) {
// Handle cases where the promise might resolve successfully but return invalid data
throw new Error("Wallet generation process did not return valid data.");
}
// --- Display Wallet ---
displayWallet(wallet); // Pass the resolved data
// --- Show Wallet Section ---
showSection('wallet');
console.log('Wallet generated and displayed');
} catch (e) {
// --- Handle Errors ---
// Catch errors from await LitecoinWallet.generateWallet OR validation checks above
alert('Error generating wallet: ' + e.message); // Show user-friendly error
console.error('Wallet generation error:', e);
// Consider going back to the entropy screen or showing error in place
showSection('entropy'); // Example: go back to entropy
} finally {
// --- Reset UI Feedback ---
if (continueBtn) {
continueBtn.disabled = false; // Re-enable button
continueBtn.textContent = 'Continue'; // Reset text
}
}
}
// ****************************************************************
// Display the generated wallet (MODIFIED FOR ARTISTIC HTML + Validation)
// ****************************************************************
function displayWallet(wallet) {
console.log('Attempting to display artistic wallet with data:', wallet);
// --- ADD INPUT VALIDATION ---
if (!wallet || typeof wallet !== 'object' || !wallet.publicAddress || !wallet.privateKey) {
console.error('displayWallet called with invalid or incomplete wallet data:', wallet);
alert('Error: Failed to receive valid wallet data for display.');
const walletContainer = document.querySelector('#wallet .wallet-container');
if (walletContainer) {
walletContainer.innerHTML = '<p style="color: red; padding: 20px; text-align: center;">Error: Could not display wallet.<br>Generation failed or returned invalid data.</p>';
}
return; // Stop execution
}
// --- END INPUT VALIDATION ---
const litecoinAddress = wallet.publicAddress;
const privateKeyWif = wallet.privateKey; // Can be normal WIF or BIP38 key
const walletContainer = document.querySelector('#wallet .wallet-container'); // Target the container
// --- Check Dependencies (Wallet Design Background) ---
const bgImageData = typeof walletDesign !== 'undefined' ? walletDesign.backgroundImageData : null; // Get image data
if (typeof walletDesign === 'undefined' || !bgImageData) {
console.error("walletDesign object or backgroundImageData not found! Cannot create artistic wallet.");
alert("Error: Critical wallet background image data is missing. Cannot generate the paper wallet.");
if (walletContainer) {
walletContainer.innerHTML = '<p style="color: red; padding: 20px; text-align: center;">Error: Wallet background image is missing.<br>Cannot generate wallet.</p>';
walletContainer.style.backgroundColor = '#eee';
}
return;
}
// --- Check Wallet Container ---
if (!walletContainer) {
console.error('Wallet container element (#wallet .wallet-container) not found!');
alert('Error: Could not find the area to display the wallet.');
return;
}
console.log("backgroundImageData found. Proceeding to generate artistic wallet HTML.");
// --- Generate and Inject HTML ---
try {
// Generate the new HTML structure using the artistic template
const newHtml = createArtisticWalletHtmlString(litecoinAddress, privateKeyWif, bgImageData, 1); // Assuming index 1 is okay
// Replace the container's content with the new HTML
walletContainer.innerHTML = newHtml;
console.log('Artistic wallet HTML structure injected.');
} catch (htmlError) {
console.error("Error creating or injecting wallet HTML:", htmlError);
alert("Error displaying wallet layout: " + htmlError.message);
walletContainer.innerHTML = '<p style="color: red; padding: 20px; text-align: center;">Error displaying wallet.<br>Please try again.</p>';
return; // Stop if HTML fails
}
// --- Generate QR Codes (Delayed) ---
// Use a small delay to help ensure the new elements are definitely in the DOM and ready
setTimeout(function() {
try {
const publicQrElementId = 'qrcode_public1'; // Match ID from createArtisticWalletHtmlString
const privateQrElementId = 'qrcode_private1'; // Match ID from createArtisticWalletHtmlString
const publicQrElement = document.getElementById(publicQrElementId);
const privateQrElement = document.getElementById(privateQrElementId);
if (!publicQrElement || !privateQrElement) {
throw new Error(`QR code placeholder elements ('${publicQrElementId}', '${privateQrElementId}') not found after HTML injection!`);
}
// Clear any potential placeholder content (though likely empty)
publicQrElement.innerHTML = '';
privateQrElement.innerHTML = '';
// Generate QR codes using the wrapper function
if (window.generateQRCode) {
console.log("Generating QR for Public:", litecoinAddress, "into", publicQrElementId);
window.generateQRCode(litecoinAddress, publicQrElementId); // Target new ID
console.log("Generating QR for Private:", privateKeyWif, "into", privateQrElementId);
window.generateQRCode(privateKeyWif, privateQrElementId); // Target new ID
console.log('QR codes generated into artistic structure.');
} else {
throw new Error("QR Code generator function (window.generateQRCode) not available.");
}
} catch (qrError) {
console.error('Error generating QR codes:', qrError);
alert("Error generating QR codes: " + qrError.message); // Show specific QR error
// Optionally display error text in the QR divs
const publicQrElement = document.getElementById('qrcode_public1');
const privateQrElement = document.getElementById('qrcode_private1');
if (publicQrElement) publicQrElement.textContent = "[QR Code Error]";
if (privateQrElement) privateQrElement.textContent = "[QR Code Error]";
}
}, 100); // 100ms delay usually sufficient
}
// Print the wallet
function printWallet() {
console.log('Printing wallet');
window.print();
}
// Reset and start over
function resetAndStartOver() {
console.log('Resetting application');
// --- Reset form fields ---
const entropyText = document.getElementById('entropy-text');
if (entropyText) entropyText.value = '';
const bip38Checkbox = document.getElementById('bip38-checkbox');
if (bip38Checkbox) bip38Checkbox.checked = false;
const bip38Password = document.getElementById('bip38-password');
if (bip38Password) bip38Password.value = '';
const bip38Confirm = document.getElementById('bip38-confirm');
if (bip38Confirm) bip38Confirm.value = '';
// --- Hide BIP38 password fields ---
const passwordContainer = document.getElementById('bip38-password-container');
if (passwordContainer) passwordContainer.style.display = 'none';
// --- Clear Wallet Display ---
const walletContainer = document.querySelector('#wallet .wallet-container');
if (walletContainer) walletContainer.innerHTML = ''; // Clear previous wallet
// --- Reset Entropy UI (if applicable) ---
if (typeof EntropyCollector !== 'undefined') {
// Assuming EntropyCollector has a reset method or similar
// EntropyCollector.reset();
}
const entropyProgressBar = document.getElementById('entropy-progress-bar');
if (entropyProgressBar) entropyProgressBar.style.width = '0%';
const entropyPercent = document.getElementById('entropy-percent');
if (entropyPercent) entropyPercent.textContent = '0% Complete';
const entropyContinueBtn = document.getElementById('entropy-continue');
if (entropyContinueBtn) entropyContinueBtn.disabled = true; // Should be disabled initially
// --- Show Intro Section ---
showSection('intro');
}
// Show a specific section and hide others
function showSection(sectionId) {
console.log('Showing section:', sectionId);
// Hide all main sections
const sections = document.querySelectorAll('main > section');
sections.forEach(section => {
if (section) section.style.display = 'none';
});
// Show the requested section
const targetSection = document.getElementById(sectionId);
if (targetSection) {
targetSection.style.display = 'block';
// Scroll the top of the newly visible section into view
targetSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
// Special handling for entropy section focus
if (sectionId === 'entropy') {
const entropyInput = document.getElementById('entropy-text');
if (entropyInput) {
entropyInput.focus(); // Focus the input field when showing entropy section
}
}
} else {
console.error("Target section not found:", sectionId);
}
}


