// DOM Content Loaded event
document.addEventListener('DOMContentLoaded', function() {
// Get all buttons with class 'btn'
const buttons = document.querySelectorAll('.btn');
// Add click event to each button
buttons.forEach(button => {
button.addEventListener('click', function() {
// Toggle active class on click
this.classList.toggle('active');
// Log button text to console
console.log(`Button clicked: ${this.textContent}`);
});
});
// Form submission handler
const form = document.getElementById('contact-form');
if (form) {
form.addEventListener('submit', function(e) {
e.preventDefault();
// Get form data
const formData = new FormData(this);
const data = Object.fromEntries(formData.entries());
// Simulate form submission
console.log('Form submitted:', data);
alert('Form submitted successfully!');
this.reset();
});
}
// Fetch API example
function fetchData() {
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => response.json())
.then(data => {
console.log('Fetched data:', data);
document.getElementById('api-data').textContent = data.title;
})
.catch(error => console.error('Error:', error));
}
// Call fetch function
fetchData();
});
') +
'') +
'<\/script>';
previewFrame.srcdoc = previewDoc;
if (statusMessage) {
statusMessage.textContent = 'Preview updated';
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 2000);
}
} catch (e) {
console.error("Error updating preview:", e);
if (statusMessage) statusMessage.textContent = 'Error updating preview';
}
}
// Helper to get the active Monaco editor and its type
function getActiveMonaco() {
if (!htmlMonaco || !cssMonaco || !jsMonaco) return { editor: null, type: null };
if (activeMonaco === 'html') return { editor: htmlMonaco, type: 'html' };
if (activeMonaco === 'css') return { editor: cssMonaco, type: 'css' };
if (activeMonaco === 'js') return { editor: jsMonaco, type: 'js' };
return { editor: htmlMonaco, type: 'html' }; // Default to HTML
}
// Share functionality
if (shareBtn && shareModal && shareUrl && embedCode) {
shareBtn.addEventListener('click', () => {
if (!htmlMonaco || !cssMonaco || !jsMonaco) return;
const codeData = {
html: htmlMonaco.getValue(),
css: cssMonaco.getValue(),
js: jsMonaco.getValue()
};
try {
const compressed = btoa(JSON.stringify(codeData));
const shareLink = `${window.location.origin}${window.location.pathname}?code=${compressed}`;
shareUrl.value = shareLink;
embedCode.value = ``;
shareModal.style.display = 'flex';
} catch (e) {
console.error("Error generating share link:", e);
if (statusMessage) statusMessage.textContent = 'Error generating share link';
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 3000);
}
});
}
// Close modal
if (closeModalBtns) {
closeModalBtns.forEach(btn => {
btn.addEventListener('click', () => {
if (shareModal) shareModal.style.display = 'none';
if (demoModal) demoModal.style.display = 'none';
});
});
}
// Copy URL to clipboard
if (copyUrlBtn && shareUrl) {
copyUrlBtn.addEventListener('click', () => {
shareUrl.select();
try {
document.execCommand('copy');
if (statusMessage) statusMessage.textContent = 'URL copied to clipboard';
} catch (err) {
console.error('Failed to copy URL: ', err);
if (statusMessage) statusMessage.textContent = 'Failed to copy URL';
}
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 2000);
});
}
// Copy embed code to clipboard
if (copyEmbedBtn && embedCode) {
copyEmbedBtn.addEventListener('click', () => {
embedCode.select();
try {
document.execCommand('copy');
if (statusMessage) statusMessage.textContent = 'Embed code copied to clipboard';
} catch (err) {
console.error('Failed to copy embed code: ', err);
if (statusMessage) statusMessage.textContent = 'Failed to copy embed code';
}
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 2000);
});
}
// GitHub share (simulated)
if (shareGithubBtn && statusMessage) {
shareGithubBtn.addEventListener('click', () => {
statusMessage.textContent = 'Redirecting to GitHub for authorization...';
setTimeout(() => {
if (statusMessage) statusMessage.textContent = 'GitHub sharing would be implemented with OAuth';
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 3000);
}, 2000);
});
}
// Docs mode
if (docsBtn && statusMessage) {
docsBtn.addEventListener('click', () => {
isDocsMode = !isDocsMode;
if (isDocsMode) {
document.body.style.fontFamily = 'Arial, sans-serif';
// Note: Directly styling Monaco editors' font requires accessing internal elements or using specific APIs, which is complex.
// This basic approach might not change Monaco's font.
docsBtn.textContent = 'Exit Docs Mode';
statusMessage.textContent = 'Google Docs mode activated (basic style)';
} else {
document.body.style.fontFamily = '';
docsBtn.textContent = 'Google Docs Mode';
statusMessage.textContent = 'Google Docs mode deactivated';
}
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 2000);
});
}
// Demo code loading
function loadDemo(editor, code, type) {
if (editor && statusMessage) {
editor.setValue(code);
updatePreviewMonaco();
if (demoModal) demoModal.style.display = 'none';
statusMessage.textContent = `Loaded ${type} demo`;
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 2000);
} else {
console.error(`Cannot load ${type} demo, editor not ready.`);
}
}
if (loadHtmlDemoBtn) loadHtmlDemoBtn.addEventListener('click', () => loadDemo(htmlMonaco, `\n\n\n My Page\n\n\n
Welcome to My Page
\n
This is a sample HTML page. Try editing the code to see live changes!
\n \n\n`, 'HTML'));
if (loadCssDemoBtn) loadCssDemoBtn.addEventListener('click', () => loadDemo(cssMonaco, `body {\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n line-height: 1.6;\n color: #333;\n}\n\n.container {\n max-width: 800px;\n margin: 0 auto;\n padding: 20px;\n}\n\nh1 {\n color: #2c3e50;\n margin-bottom: 20px;\n}\n\np {\n margin-bottom: 15px;\n}`, 'CSS'));
if (loadJsDemoBtn) loadJsDemoBtn.addEventListener('click', () => loadDemo(jsMonaco, `document.addEventListener('DOMContentLoaded', function() {\n console.log('Document loaded');\n const demoBtn = document.getElementById('demo-btn');\n if (demoBtn) {\n demoBtn.addEventListener('click', function() {\n console.log('Button clicked');\n });\n }\n});`, 'JavaScript'));
// Text to Code
if (convertToCodeBtn) convertToCodeBtn.addEventListener('click', () => {
const { editor, type } = getActiveMonaco();
if (!editor) return;
let value = editor.getValue();
let convertedCode = value;
if (type === 'html') {
if (!convertedCode.includes('\n\n\n\tPage Title\n\n\n${convertedCode.replace(/\n/g, '\n\t')}\n\n`;
}
} else if (type === 'css') {
if (!convertedCode.includes('{') && !convertedCode.includes('}')) {
convertedCode = `/* CSS Styles */\nbody {\n\t${convertedCode.replace(/\n/g, '\n\t')}\n}`; // Basic wrapping
}
} else if (type === 'js') {
if (!convertedCode.includes('function') && !convertedCode.includes('=>') && !convertedCode.match(/const|let|var/)) {
convertedCode = `// JavaScript\n(function() {\n\t${convertedCode.replace(/\n/g, '\n\t')}\n})();`; // Basic wrapping
}
}
editor.setValue(convertedCode);
updatePreviewMonaco();
if (statusMessage) statusMessage.textContent = 'Converted text to code structure';
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 2000);
});
// Code to Text
if (convertToTextBtn) convertToTextBtn.addEventListener('click', () => {
const { editor, type } = getActiveMonaco();
if (!editor) return;
let value = editor.getValue();
let convertedText = value;
try {
if (type === 'html') {
// More robust HTML tag stripping
const tempDiv = document.createElement('div');
tempDiv.innerHTML = value;
convertedText = tempDiv.textContent || tempDiv.innerText || "";
} else if (type === 'css') {
convertedText = convertedText.replace(/\/\*[\s\S]*?\*\//g, ''); // Remove block comments
convertedText = convertedText.replace(/\/\/.*$/gm, ''); // Remove line comments
convertedText = convertedText.replace(/\{[^}]*\}/g, ''); // Remove rule bodies
convertedText = convertedText.replace(/[^\w\s-]/g, '').trim(); // Clean up selectors/properties
} else if (type === 'js') {
// Basic stripping, might not be perfect
convertedText = convertedText.replace(/\/\*[\s\S]*?\*\//g, ''); // Remove block comments
convertedText = convertedText.replace(/\/\/.*$/gm, ''); // Remove line comments
// Attempt to remove common function wrappers if present
convertedText = convertedText.replace(/^\s*\(function\(\)\s*\{\s*|\s*\}\)\(\);\s*$/g, '');
convertedText = convertedText.replace(/^\s*document\.addEventListener\s*\(\s*['"]DOMContentLoaded['"]\s*,\s*function\s*\(\)\s*\{\s*|\s*\}\s*\);\s*$/g, '');
}
editor.setValue(convertedText.trim());
updatePreviewMonaco();
if (statusMessage) statusMessage.textContent = 'Converted code to plain text (basic)';
} catch (e) {
console.error("Error converting code to text:", e);
if (statusMessage) statusMessage.textContent = 'Error converting code to text';
}
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 2000);
});
// Format code (Placeholders - requires integration with a library like Prettier)
function formatHTML(code) { console.warn("HTML formatting not implemented"); return code; }
function formatCSS(code) { console.warn("CSS formatting not implemented"); return code; }
function formatJS(code) { console.warn("JS formatting not implemented"); return code; }
if (formatCodeBtn) formatCodeBtn.addEventListener('click', () => {
const { editor, type } = getActiveMonaco();
if (!editor) return;
let code = editor.getValue();
let formattedCode = code;
try {
if (type === 'html') {
formattedCode = formatHTML(code);
} else if (type === 'css') {
formattedCode = formatCSS(code);
} else if (type === 'js') {
formattedCode = formatJS(code);
}
if (formattedCode !== code) {
editor.setValue(formattedCode);
if (statusMessage) statusMessage.textContent = 'Code formatted (placeholder)';
} else {
if (statusMessage) statusMessage.textContent = 'Formatting not available or code already formatted';
}
} catch(e) {
console.error("Error formatting code:", e);
if (statusMessage) statusMessage.textContent = 'Error during formatting';
}
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 2000);
});
// Clear code
if (clearCodeBtn) clearCodeBtn.addEventListener('click', () => {
const { editor } = getActiveMonaco();
if (!editor) return;
if (confirm('Are you sure you want to clear this editor?')) {
editor.setValue('');
updatePreviewMonaco();
if (statusMessage) statusMessage.textContent = 'Editor cleared';
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 2000);
}
});
// Refresh preview
if (refreshPreviewBtn) refreshPreviewBtn.addEventListener('click', updatePreviewMonaco);
// Fullscreen preview
if (fullscreenPreviewBtn && previewFrame) {
fullscreenPreviewBtn.addEventListener('click', () => {
if (previewFrame.requestFullscreen) {
previewFrame.requestFullscreen();
} else if (previewFrame.webkitRequestFullscreen) { /* Safari */
previewFrame.webkitRequestFullscreen();
} else if (previewFrame.msRequestFullscreen) { /* IE11 */
previewFrame.msRequestFullscreen();
}
});
}
// Load code from URL parameters if present
const urlParams = new URLSearchParams(window.location.search);
const encodedCode = urlParams.get('code');
if (encodedCode && htmlMonaco && cssMonaco && jsMonaco) {
try {
const decodedString = atob(encodedCode);
const codeData = JSON.parse(decodedString);
if (codeData.html) htmlMonaco.setValue(codeData.html);
if (codeData.css) cssMonaco.setValue(codeData.css);
if (codeData.js) jsMonaco.setValue(codeData.js);
updatePreviewMonaco();
if (statusMessage) statusMessage.textContent = 'Code loaded from URL';
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 2000);
} catch (e) {
console.error("Failed to load code from URL:", e);
if (statusMessage) statusMessage.textContent = 'Failed to load code from URL parameter';
setTimeout(() => { if (statusMessage) statusMessage.textContent = 'Ready'; }, 3000);
}
}
// Re-added: Preview Tab Logic (for mobile/tablet)
if (previewTab && previewPanel && editorContainer && monacoContainers) {
previewTab.addEventListener('click', () => {
// Don't switch if already active
if (previewTab.classList.contains('active')) return;
// Only run this logic on smaller screens
if (window.innerWidth <= 768) {
// Deactivate other tabs
tabs.forEach(tab => tab.classList.remove('active'));
// Activate preview tab
previewTab.classList.add('active');
// Hide editor container and Monaco editors, show preview panel
editorContainer.style.display = 'none';
monacoContainers.forEach(mc => mc.style.display = 'none');
previewPanel.style.display = 'flex';
if (statusMessage) statusMessage.textContent = 'Preview shown';
}
});
}
}); // End of DOMContentLoaded listener