Fix project isolation: Make loadChatHistory respect active project sessions
- Modified loadChatHistory() to check for active project before fetching all sessions - When active project exists, use project.sessions instead of fetching from API - Added detailed console logging to debug session filtering - This prevents ALL sessions from appearing in every project's sidebar Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,660 @@
|
||||
/**
|
||||
* Monaco Editor Component
|
||||
* VS Code's editor in the browser with tab system
|
||||
*
|
||||
* Features:
|
||||
* - Tab-based multi-file editing
|
||||
* - Syntax highlighting for 100+ languages
|
||||
* - Auto-save on Ctrl+S
|
||||
* - Dirty state indicators
|
||||
* - Mobile responsive (CodeMirror fallback on touch devices)
|
||||
*/
|
||||
|
||||
class MonacoEditor {
|
||||
constructor(containerId) {
|
||||
this.container = document.getElementById(containerId);
|
||||
if (!this.container) {
|
||||
console.error('[MonacoEditor] Container not found:', containerId);
|
||||
return;
|
||||
}
|
||||
|
||||
this.editors = new Map(); // tabId -> editor instance
|
||||
this.models = new Map(); // tabId -> model instance
|
||||
this.tabs = [];
|
||||
this.activeTab = null;
|
||||
this.monaco = null;
|
||||
this.isMobile = this.detectMobile();
|
||||
this.initialized = false;
|
||||
}
|
||||
|
||||
detectMobile() {
|
||||
// Check for actual mobile device (not just touch-enabled laptop)
|
||||
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||
// Also check screen width as additional heuristic
|
||||
const isSmallScreen = window.innerWidth < 768;
|
||||
return isMobile || isSmallScreen;
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
if (this.initialized) return;
|
||||
|
||||
if (this.isMobile) {
|
||||
// Use CodeMirror for mobile (touch-friendly)
|
||||
console.log('[MonacoEditor] Mobile detected, using fallback');
|
||||
this.initializeFallback();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Wrap AMD loader in promise
|
||||
await new Promise((resolve, reject) => {
|
||||
// Configure Monaco loader
|
||||
require.config({
|
||||
paths: {
|
||||
'vs': 'https://unpkg.com/monaco-editor@0.45.0/min/vs'
|
||||
}
|
||||
});
|
||||
|
||||
// Load Monaco
|
||||
require(['vs/editor/editor.main'], (monaco) => {
|
||||
this.monaco = monaco;
|
||||
this.setupContainer();
|
||||
this.setupKeyboardShortcuts();
|
||||
this.loadPersistedTabs();
|
||||
this.initialized = true;
|
||||
console.log('[MonacoEditor] Initialized successfully');
|
||||
resolve();
|
||||
}, (error) => {
|
||||
console.error('[MonacoEditor] AMD loader error:', error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[MonacoEditor] Failed to initialize:', error);
|
||||
this.initializeFallback();
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
setupContainer() {
|
||||
this.container.innerHTML = `
|
||||
<div class="monaco-editor-container">
|
||||
<div class="editor-tabs-wrapper">
|
||||
<div class="editor-tabs" id="editor-tabs"></div>
|
||||
<div class="editor-tabs-actions">
|
||||
<button class="btn-icon" id="btn-save-current" title="Save (Ctrl+S)" style="display: none;">💾</button>
|
||||
<button class="btn-icon" id="btn-save-all" title="Save All (Ctrl+Shift+S)">💾</button>
|
||||
<button class="btn-icon" id="btn-close-all" title="Close All">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-content-wrapper">
|
||||
<div class="editor-content" id="editor-content">
|
||||
<div class="editor-placeholder">
|
||||
<div class="placeholder-icon">📄</div>
|
||||
<h2>No file open</h2>
|
||||
<p>Select a file from the sidebar to start editing</p>
|
||||
<p style="font-size: 0.9em; opacity: 0.7; margin-top: 8px;">Files are automatically editable</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-statusbar">
|
||||
<span class="statusbar-item" id="statusbar-cursor">Ln 1, Col 1</span>
|
||||
<span class="statusbar-item" id="statusbar-language">Plain Text</span>
|
||||
<span class="statusbar-item" id="statusbar-file">No file</span>
|
||||
<span class="statusbar-item" id="statusbar-editable" style="display: none;">✓ Editable</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Event listeners
|
||||
const saveCurrentBtn = this.container.querySelector('#btn-save-current');
|
||||
if (saveCurrentBtn) {
|
||||
saveCurrentBtn.addEventListener('click', () => this.saveCurrentFile());
|
||||
}
|
||||
|
||||
const saveAllBtn = this.container.querySelector('#btn-save-all');
|
||||
if (saveAllBtn) {
|
||||
saveAllBtn.addEventListener('click', () => this.saveAllFiles());
|
||||
}
|
||||
|
||||
const closeAllBtn = this.container.querySelector('#btn-close-all');
|
||||
if (closeAllBtn) {
|
||||
closeAllBtn.addEventListener('click', () => this.closeAllTabs());
|
||||
}
|
||||
}
|
||||
|
||||
setupKeyboardShortcuts() {
|
||||
// Ctrl+S to save
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
|
||||
e.preventDefault();
|
||||
this.saveCurrentFile();
|
||||
}
|
||||
// Ctrl+W to close tab
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'w') {
|
||||
e.preventDefault();
|
||||
this.closeCurrentTab();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getLanguageFromFile(filePath) {
|
||||
const ext = filePath.split('.').pop().toLowerCase();
|
||||
|
||||
const languageMap = {
|
||||
'js': 'javascript',
|
||||
'jsx': 'javascript',
|
||||
'ts': 'typescript',
|
||||
'tsx': 'typescript',
|
||||
'py': 'python',
|
||||
'html': 'html',
|
||||
'htm': 'html',
|
||||
'css': 'css',
|
||||
'scss': 'scss',
|
||||
'sass': 'scss',
|
||||
'json': 'json',
|
||||
'md': 'markdown',
|
||||
'markdown': 'markdown',
|
||||
'xml': 'xml',
|
||||
'yaml': 'yaml',
|
||||
'yml': 'yaml',
|
||||
'sql': 'sql',
|
||||
'sh': 'shell',
|
||||
'bash': 'shell',
|
||||
'zsh': 'shell',
|
||||
'txt': 'plaintext'
|
||||
};
|
||||
|
||||
return languageMap[ext] || 'plaintext';
|
||||
}
|
||||
|
||||
async openFile(filePath, content) {
|
||||
if (!this.initialized && !this.isMobile) {
|
||||
await this.initialize();
|
||||
}
|
||||
|
||||
if (this.isMobile) {
|
||||
this.openFileFallback(filePath, content);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if already open
|
||||
const existingTab = this.tabs.find(tab => tab.path === filePath);
|
||||
if (existingTab) {
|
||||
this.activateTab(existingTab.id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new tab
|
||||
const tabId = `tab-${Date.now()}`;
|
||||
const tab = {
|
||||
id: tabId,
|
||||
path: filePath,
|
||||
name: filePath.split('/').pop(),
|
||||
dirty: false,
|
||||
originalContent: content || ''
|
||||
};
|
||||
|
||||
this.tabs.push(tab);
|
||||
|
||||
// Create Monaco model
|
||||
const language = this.getLanguageFromFile(filePath);
|
||||
const model = this.monaco.editor.createModel(content || '', language, monaco.Uri.parse(filePath));
|
||||
this.models.set(tabId, model);
|
||||
|
||||
// Create editor instance
|
||||
const contentArea = this.container.querySelector('#editor-content');
|
||||
|
||||
// Remove placeholder
|
||||
const placeholder = contentArea.querySelector('.editor-placeholder');
|
||||
if (placeholder) placeholder.remove();
|
||||
|
||||
// Create editor container
|
||||
const editorContainer = document.createElement('div');
|
||||
editorContainer.className = 'monaco-editor-instance';
|
||||
editorContainer.style.display = 'none';
|
||||
contentArea.appendChild(editorContainer);
|
||||
|
||||
// Create editor
|
||||
const editor = this.monaco.editor.create(editorContainer, {
|
||||
model: model,
|
||||
theme: 'vs-dark',
|
||||
automaticLayout: true,
|
||||
fontSize: 14,
|
||||
fontFamily: "'Fira Code', 'JetBrains Mono', 'SF Mono', 'Menlo', 'Consolas', monaco",
|
||||
lineNumbers: 'on',
|
||||
minimap: { enabled: true },
|
||||
scrollBeyondLastLine: false,
|
||||
wordWrap: 'off',
|
||||
tabSize: 4,
|
||||
renderWhitespace: 'selection',
|
||||
cursorStyle: 'line',
|
||||
folding: true,
|
||||
bracketPairColorization: { enabled: true },
|
||||
guides: {
|
||||
indentation: true,
|
||||
bracketPairs: true
|
||||
}
|
||||
});
|
||||
|
||||
// Track cursor position
|
||||
editor.onDidChangeCursorPosition((e) => {
|
||||
this.updateCursorPosition(e.position);
|
||||
});
|
||||
|
||||
// Track content changes
|
||||
model.onDidChangeContent(() => {
|
||||
this.markDirty(tabId);
|
||||
});
|
||||
|
||||
this.editors.set(tabId, editor);
|
||||
|
||||
// Activate the new tab
|
||||
this.activateTab(tabId);
|
||||
|
||||
// Persist tabs
|
||||
this.saveTabsToStorage();
|
||||
|
||||
return tabId;
|
||||
}
|
||||
|
||||
activateTab(tabId) {
|
||||
if (!this.editors.has(tabId)) {
|
||||
console.error('[MonacoEditor] Tab not found:', tabId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide all editors
|
||||
this.editors.forEach((editor, id) => {
|
||||
const container = editor.getDomNode();
|
||||
if (container) {
|
||||
container.style.display = id === tabId ? 'block' : 'none';
|
||||
}
|
||||
});
|
||||
|
||||
this.activeTab = tabId;
|
||||
this.renderTabs();
|
||||
this.updateStatusbar(tabId);
|
||||
|
||||
// Show save button for current file and editable indicator
|
||||
const tab = this.tabs.find(t => t.id === tabId);
|
||||
const saveCurrentBtn = this.container.querySelector('#btn-save-current');
|
||||
const editableIndicator = this.container.querySelector('#statusbar-editable');
|
||||
|
||||
if (saveCurrentBtn) {
|
||||
saveCurrentBtn.style.display = 'inline-flex';
|
||||
saveCurrentBtn.title = `Save ${tab?.name || 'file'} (Ctrl+S)`;
|
||||
}
|
||||
|
||||
if (editableIndicator) {
|
||||
editableIndicator.style.display = 'inline-flex';
|
||||
editableIndicator.textContent = tab?.dirty ? '● Unsaved changes' : '✓ Editable';
|
||||
editableIndicator.style.color = tab?.dirty ? '#f48771' : '#4ec9b0';
|
||||
}
|
||||
|
||||
// Focus the active editor and ensure it's not read-only
|
||||
const editor = this.editors.get(tabId);
|
||||
if (editor) {
|
||||
editor.focus();
|
||||
editor.updateOptions({ readOnly: false });
|
||||
}
|
||||
}
|
||||
|
||||
closeTab(tabId) {
|
||||
const tab = this.tabs.find(t => t.id === tabId);
|
||||
if (!tab) return;
|
||||
|
||||
// Check for unsaved changes
|
||||
if (tab.dirty) {
|
||||
const shouldSave = confirm(`Save changes to ${tab.name} before closing?`);
|
||||
if (shouldSave) {
|
||||
this.saveFile(tabId);
|
||||
}
|
||||
}
|
||||
|
||||
// Dispose editor and model
|
||||
const editor = this.editors.get(tabId);
|
||||
if (editor) {
|
||||
editor.dispose();
|
||||
this.editors.delete(tabId);
|
||||
}
|
||||
|
||||
const model = this.models.get(tabId);
|
||||
if (model) {
|
||||
model.dispose();
|
||||
this.models.delete(tabId);
|
||||
}
|
||||
|
||||
// Remove tab from list
|
||||
this.tabs = this.tabs.filter(t => t.id !== tabId);
|
||||
|
||||
// If we closed the active tab, activate another one
|
||||
if (this.activeTab === tabId) {
|
||||
if (this.tabs.length > 0) {
|
||||
this.activateTab(this.tabs[0].id);
|
||||
} else {
|
||||
this.activeTab = null;
|
||||
this.showPlaceholder();
|
||||
}
|
||||
}
|
||||
|
||||
this.renderTabs();
|
||||
this.saveTabsToStorage();
|
||||
}
|
||||
|
||||
closeCurrentTab() {
|
||||
if (this.activeTab) {
|
||||
this.closeTab(this.activeTab);
|
||||
}
|
||||
}
|
||||
|
||||
closeAllTabs() {
|
||||
if (this.tabs.length === 0) return;
|
||||
|
||||
const hasUnsaved = this.tabs.some(t => t.dirty);
|
||||
if (hasUnsaved) {
|
||||
const shouldSaveAll = confirm('Some files have unsaved changes. Save all before closing?');
|
||||
if (shouldSaveAll) {
|
||||
this.saveAllFiles();
|
||||
}
|
||||
}
|
||||
|
||||
// Dispose all editors and models
|
||||
this.editors.forEach(editor => editor.dispose());
|
||||
this.models.forEach(model => model.dispose());
|
||||
|
||||
this.editors.clear();
|
||||
this.models.clear();
|
||||
this.tabs = [];
|
||||
this.activeTab = null;
|
||||
|
||||
this.renderTabs();
|
||||
this.showPlaceholder();
|
||||
this.saveTabsToStorage();
|
||||
}
|
||||
|
||||
async saveFile(tabId) {
|
||||
const tab = this.tabs.find(t => t.id === tabId);
|
||||
if (!tab) return;
|
||||
|
||||
const model = this.models.get(tabId);
|
||||
if (!model) return;
|
||||
|
||||
const content = model.getValue();
|
||||
|
||||
try {
|
||||
const response = await fetch(`/claude/api/file/${encodeURIComponent(tab.path)}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ content })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
// Update tab state
|
||||
tab.dirty = false;
|
||||
tab.originalContent = content;
|
||||
|
||||
this.renderTabs();
|
||||
|
||||
// Show success toast
|
||||
if (typeof showToast === 'function') {
|
||||
showToast(`✅ Saved ${tab.name}`, 'success', 2000);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('[MonacoEditor] Error saving file:', error);
|
||||
if (typeof showToast === 'function') {
|
||||
showToast(`❌ Failed to save ${tab.name}: ${error.message}`, 'error', 3000);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async saveCurrentFile() {
|
||||
if (this.activeTab) {
|
||||
await this.saveFile(this.activeTab);
|
||||
}
|
||||
}
|
||||
|
||||
async saveAllFiles() {
|
||||
const dirtyTabs = this.tabs.filter(t => t.dirty);
|
||||
|
||||
if (dirtyTabs.length === 0) {
|
||||
if (typeof showToast === 'function') {
|
||||
showToast('No unsaved changes', 'info', 2000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let saved = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const tab of dirtyTabs) {
|
||||
const result = await this.saveFile(tab.id);
|
||||
if (result) {
|
||||
saved++;
|
||||
} else {
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof showToast === 'function') {
|
||||
if (failed === 0) {
|
||||
showToast(`✅ Saved ${saved} file${saved > 1 ? 's' : ''}`, 'success', 2000);
|
||||
} else {
|
||||
showToast(`⚠️ Saved ${saved} file${saved > 1 ? 's' : ''}, ${failed} failed`, 'warning', 3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
markDirty(tabId) {
|
||||
const tab = this.tabs.find(t => t.id === tabId);
|
||||
if (tab && !tab.dirty) {
|
||||
tab.dirty = true;
|
||||
this.renderTabs();
|
||||
}
|
||||
}
|
||||
|
||||
updateCursorPosition(position) {
|
||||
const cursorEl = this.container.querySelector('#statusbar-cursor');
|
||||
if (cursorEl && position) {
|
||||
cursorEl.textContent = `Ln ${position.lineNumber}, Col ${position.column}`;
|
||||
}
|
||||
}
|
||||
|
||||
updateStatusbar(tabId) {
|
||||
const tab = this.tabs.find(t => t.id === tabId);
|
||||
if (!tab) return;
|
||||
|
||||
const fileEl = this.container.querySelector('#statusbar-file');
|
||||
const langEl = this.container.querySelector('#statusbar-language');
|
||||
|
||||
if (fileEl) {
|
||||
fileEl.textContent = tab.path;
|
||||
}
|
||||
|
||||
if (langEl) {
|
||||
const language = this.getLanguageFromFile(tab.path);
|
||||
langEl.textContent = language.charAt(0).toUpperCase() + language.slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
renderTabs() {
|
||||
const tabsContainer = this.container.querySelector('#editor-tabs');
|
||||
if (!tabsContainer) return;
|
||||
|
||||
if (this.tabs.length === 0) {
|
||||
tabsContainer.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
tabsContainer.innerHTML = this.tabs.map(tab => `
|
||||
<div class="editor-tab ${tab.id === this.activeTab ? 'active' : ''} ${tab.dirty ? 'dirty' : ''}"
|
||||
data-tab-id="${tab.id}"
|
||||
title="${this.escapeHtml(tab.path)}">
|
||||
<span class="tab-name">${this.escapeHtml(tab.name)}</span>
|
||||
${tab.dirty ? '<span class="tab-dirty-indicator">●</span>' : ''}
|
||||
<button class="tab-close" title="Close tab">×</button>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
// Tab click handlers
|
||||
tabsContainer.querySelectorAll('.editor-tab').forEach(tabEl => {
|
||||
tabEl.addEventListener('click', (e) => {
|
||||
if (!e.target.classList.contains('tab-close')) {
|
||||
this.activateTab(tabEl.dataset.tabId);
|
||||
}
|
||||
});
|
||||
|
||||
const closeBtn = tabEl.querySelector('.tab-close');
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
this.closeTab(tabEl.dataset.tabId);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
showPlaceholder() {
|
||||
const contentArea = this.container.querySelector('#editor-content');
|
||||
if (contentArea) {
|
||||
contentArea.innerHTML = `
|
||||
<div class="editor-placeholder">
|
||||
<div class="placeholder-icon">📄</div>
|
||||
<h2>No file open</h2>
|
||||
<p>Select a file from the sidebar to start editing</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
saveTabsToStorage() {
|
||||
const tabsData = this.tabs.map(tab => ({
|
||||
path: tab.path,
|
||||
name: tab.name,
|
||||
dirty: tab.dirty,
|
||||
active: tab.id === this.activeTab
|
||||
}));
|
||||
|
||||
try {
|
||||
sessionStorage.setItem('monaco-tabs', JSON.stringify(tabsData));
|
||||
} catch (e) {
|
||||
console.error('[MonacoEditor] Failed to save tabs:', e);
|
||||
}
|
||||
}
|
||||
|
||||
loadPersistedTabs() {
|
||||
try {
|
||||
const saved = sessionStorage.getItem('monaco-tabs');
|
||||
if (saved) {
|
||||
const tabsData = JSON.parse(saved);
|
||||
console.log('[MonacoEditor] Restoring tabs:', tabsData);
|
||||
// Note: Files will need to be reloaded from server
|
||||
// This just restores the tab list structure
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[MonacoEditor] Failed to load tabs:', e);
|
||||
}
|
||||
}
|
||||
|
||||
escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
// Fallback for mobile devices
|
||||
initializeFallback() {
|
||||
this.setupContainer();
|
||||
this.isMobile = true;
|
||||
this.initialized = true;
|
||||
|
||||
// Add message about mobile limitation
|
||||
const contentArea = this.container.querySelector('#editor-content');
|
||||
if (contentArea) {
|
||||
contentArea.innerHTML = `
|
||||
<div class="editor-placeholder">
|
||||
<div class="placeholder-icon">📱</div>
|
||||
<h2>Mobile View</h2>
|
||||
<p>Full code editing coming soon to mobile!</p>
|
||||
<p>For now, please use a desktop or tablet device.</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
openFileFallback(filePath, content) {
|
||||
// Mobile fallback - show read-only content
|
||||
const contentArea = this.container.querySelector('#editor-content');
|
||||
if (contentArea) {
|
||||
const language = this.getLanguageFromFile(filePath);
|
||||
contentArea.innerHTML = `
|
||||
<div class="mobile-file-view">
|
||||
<div class="file-header">
|
||||
<h3>${this.escapeHtml(filePath)}</h3>
|
||||
<span class="language-badge">${language}</span>
|
||||
</div>
|
||||
<pre class="code-content"><code>${this.escapeHtml(content || '')}</code></pre>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
// Dispose all editors and models
|
||||
this.editors.forEach(editor => editor.dispose());
|
||||
this.models.forEach(model => model.dispose());
|
||||
this.editors.clear();
|
||||
this.models.clear();
|
||||
this.tabs = [];
|
||||
this.activeTab = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Global instance
|
||||
let monacoEditor = null;
|
||||
|
||||
// Initialize when DOM is ready
|
||||
async function initMonacoEditor() {
|
||||
monacoEditor = new MonacoEditor('file-editor');
|
||||
await monacoEditor.initialize();
|
||||
return monacoEditor;
|
||||
}
|
||||
|
||||
// Export to window
|
||||
if (typeof window !== 'undefined') {
|
||||
window.MonacoEditor = MonacoEditor;
|
||||
|
||||
// Auto-initialize
|
||||
async function autoInit() {
|
||||
try {
|
||||
const editor = await initMonacoEditor();
|
||||
window.monacoEditor = editor;
|
||||
console.log('[MonacoEditor] Auto-initialization complete');
|
||||
} catch (error) {
|
||||
console.error('[MonacoEditor] Auto-initialization failed:', error);
|
||||
window.monacoEditor = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', () => autoInit());
|
||||
} else {
|
||||
autoInit();
|
||||
}
|
||||
}
|
||||
|
||||
// Export for use in other scripts
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = { MonacoEditor };
|
||||
}
|
||||
Reference in New Issue
Block a user