- Browse dashboard at / with search, framework filter, tag pills, and pagination - Tags system with autocomplete datalist and per-fiddle tag management - Listed/unlisted toggle for visibility control (unlisted still accessible via direct URL) - Export standalone HTML with inlined CSS/JS and framework CDN tags - QR code modal for sharing fiddle URLs - Embed mode at /embed/:id for minimal preview-only rendering - Extract shared loadScript() utility from 4 files into utils.js - Database schema: listed column, tags and fiddle_tags tables with index
98 lines
2.5 KiB
JavaScript
98 lines
2.5 KiB
JavaScript
import { getPref, setPref } from './preferences.js';
|
|
import { getActiveEditor, setOnTabSwitch, setOnModeChange } from './editors.js';
|
|
import { loadScript } from './utils.js';
|
|
|
|
let currentMode = 'default'; // 'default' | 'vim' | 'emacs'
|
|
let activeAdapter = null; // vim or emacs adapter instance
|
|
let vimLoaded = false;
|
|
let emacsLoaded = false;
|
|
|
|
const statusBar = () => document.getElementById('vim-status-bar');
|
|
|
|
async function ensureVim() {
|
|
if (vimLoaded) return;
|
|
window.monaco = monaco;
|
|
await loadScript('https://unpkg.com/monaco-vim@0.4.2/dist/monaco-vim.js');
|
|
vimLoaded = true;
|
|
}
|
|
|
|
async function ensureEmacs() {
|
|
if (emacsLoaded) return;
|
|
window.monaco = monaco;
|
|
await loadScript('https://unpkg.com/monaco-emacs/dist/monaco-emacs.js');
|
|
emacsLoaded = true;
|
|
}
|
|
|
|
function disposeAdapter() {
|
|
if (activeAdapter) {
|
|
activeAdapter.dispose();
|
|
activeAdapter = null;
|
|
}
|
|
const bar = statusBar();
|
|
if (bar) {
|
|
bar.style.display = 'none';
|
|
bar.textContent = '';
|
|
}
|
|
}
|
|
|
|
async function attachToEditor(editor) {
|
|
if (!editor) return;
|
|
disposeAdapter();
|
|
|
|
if (currentMode === 'vim') {
|
|
await ensureVim();
|
|
const bar = statusBar();
|
|
if (bar) bar.style.display = 'block';
|
|
activeAdapter = MonacoVim.initVimMode(editor, bar);
|
|
} else if (currentMode === 'emacs') {
|
|
await ensureEmacs();
|
|
const EmacsExtension = MonacoEmacs.EmacsExtension;
|
|
activeAdapter = new EmacsExtension(editor);
|
|
activeAdapter.start();
|
|
}
|
|
}
|
|
|
|
export async function setKeybindingMode(mode) {
|
|
disposeAdapter();
|
|
currentMode = mode;
|
|
setPref('keybindings', mode);
|
|
|
|
if (mode === 'default') return;
|
|
|
|
const editor = getActiveEditor();
|
|
if (editor) await attachToEditor(editor);
|
|
}
|
|
|
|
export function initKeybindings() {
|
|
currentMode = getPref('keybindings') || 'default';
|
|
|
|
const select = document.getElementById('keybinding-mode');
|
|
if (select) {
|
|
select.value = currentMode;
|
|
select.addEventListener('change', (e) => setKeybindingMode(e.target.value));
|
|
}
|
|
|
|
// Reattach on tab switch
|
|
setOnTabSwitch((_tabId, editor) => {
|
|
if (currentMode !== 'default' && editor) {
|
|
attachToEditor(editor);
|
|
}
|
|
});
|
|
|
|
// Reattach on mode change
|
|
setOnModeChange(() => {
|
|
if (currentMode !== 'default') {
|
|
setTimeout(() => {
|
|
const editor = getActiveEditor();
|
|
if (editor) attachToEditor(editor);
|
|
}, 50);
|
|
}
|
|
});
|
|
|
|
// Initial attach if non-default
|
|
if (currentMode !== 'default') {
|
|
const editor = getActiveEditor();
|
|
if (editor) attachToEditor(editor);
|
|
}
|
|
}
|