// 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();
});
\n`,
language: 'html',
theme: 'vs-dark',
automaticLayout: true,
fontSize: 15,
minimap: { enabled: false }
});
cssMonaco = monaco.editor.create(document.getElementById('css-monaco'), {
value: `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}`,
language: 'css',
theme: 'vs-dark',
automaticLayout: true,
fontSize: 15,
minimap: { enabled: false }
});
jsMonaco = monaco.editor.create(document.getElementById('js-monaco'), {
value: `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});`,
language: 'javascript',
theme: 'vs-dark',
automaticLayout: true,
fontSize: 15,
minimap: { enabled: false }
});// Tab switching for Monaco
if (codeTabs) codeTabs.addEventListener('click', (e) => {
if (e.target.classList.contains('tab') && e.target.hasAttribute('data-target')) {
// Handle code tab switching
const target = e.target.getAttribute('data-target');// Hide preview panel and show editor container (if mobile)
if (window.innerWidth <= 768) {
if (previewPanel) previewPanel.style.display = 'none';
if (editorContainer) editorContainer.style.display = 'flex'; // Or 'block' depending on its default
}// Hide all Monaco editors first
monacoContainers.forEach(mc => mc.style.display = 'none');// Show the target editor
if (target === 'html-editor') {
document.getElementById('html-monaco').style.display = 'block';
activeMonaco = 'html';
} else if (target === 'css-editor') {
document.getElementById('css-monaco').style.display = 'block';
activeMonaco = 'css';
} else if (target === 'js-editor') {
document.getElementById('js-monaco').style.display = 'block';
activeMonaco = 'js';
}// Update tab active class
tabs.forEach(tab => tab.classList.remove('active'));
e.target.classList.add('active');// Ensure preview tab is inactive
if (previewTab) previewTab.classList.remove('active');// Ensure layout updates on tab switch
setTimeout(() => {
if (htmlMonaco) htmlMonaco.layout();
if (cssMonaco) cssMonaco.layout();
if (jsMonaco) jsMonaco.layout();
}, 0);
}
});// Live preview update with Monaco
[htmlMonaco, cssMonaco, jsMonaco].forEach((editor) => {
if (editor) {
editor.onDidChangeModelContent(() => {
updatePreviewMonaco();
});
}
});// Initial preview
updatePreviewMonaco();
}); // End of Monaco require callback// Helper function to safely update preview
function updatePreviewMonaco() {
if (!htmlMonaco || !cssMonaco || !jsMonaco || !previewFrame) return; // Guard clause
try {
const html = htmlMonaco.getValue();
const css = cssMonaco.getValue();
const js = jsMonaco.getValue();
const previewDoc = '' +
html.replace(/<\/script>/g, '</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\nMy 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