From e8d4985bbb60797936d31b65604a7f94c76bf623 Mon Sep 17 00:00:00 2001 From: Agando Date: Tue, 9 Jun 2026 18:00:26 +0200 Subject: auto: 2026-06-09_18:00 changes --- modules/ext/floating.js | 90 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 6 deletions(-) (limited to 'modules/ext') diff --git a/modules/ext/floating.js b/modules/ext/floating.js index f59aa29..4c332fc 100644 --- a/modules/ext/floating.js +++ b/modules/ext/floating.js @@ -37,9 +37,14 @@ class FloatingModule { this.commands['floating-toggle'] = (args) => this._cmdToggle(args); // Restore persisted elements at boot — registerCommands() is the only hook called by ModuleManager // but defer to next tick so terminal/fs are ready - setTimeout(() => { - this._restore(); - }, 0); + const doRestore = () => { + if (document.body) { + this._restore(); + } else { + setTimeout(doRestore, 50); + } + }; + setTimeout(doRestore, 0); } // ── Persistence ── @@ -125,10 +130,62 @@ class FloatingModule { node.style.bottom = 'auto'; node.style.right = 'auto'; } + // Attach drag behavior to draggable elements (buttons, menu headers, panel titles) + if (el.type === 'button' || el.type === 'menu' || el.type === 'panel') { + const handle = el.type === 'menu' ? node.querySelector('.floating-menu-header') + : el.type === 'panel' ? node.querySelector('.floating-panel-title') + : node; + if (handle) { + this._makeDraggable(handle, node, id); + } + } container.appendChild(node); } } + _makeDraggable(handle, node, id) { + let startX, startY, startLeft, startTop, dragging = false; + const onStart = (e) => { + const ev = e.touches ? e.touches[0] : e; + dragging = true; + startX = ev.clientX; + startY = ev.clientY; + const rect = node.getBoundingClientRect(); + startLeft = rect.left; + startTop = rect.top; + handle.setPointerCapture(ev.pointerId); + handle.style.cursor = 'grabbing'; + }; + const onMove = (e) => { + if (!dragging) return; + const ev = e.touches ? e.touches[0] : e; + node.style.position = 'fixed'; + node.style.left = (startLeft + (ev.clientX - startX)) + 'px'; + node.style.top = (startTop + (ev.clientY - startY)) + 'px'; + node.style.bottom = 'auto'; + node.style.right = 'auto'; + }; + const onEnd = (e) => { + if (!dragging) return; + dragging = false; + handle.style.cursor = ''; + handle.releasePointerCapture(e.pointerId); + const el = this._elements[id]; + if (el) { + const rect = node.getBoundingClientRect(); + el.x = Math.round(rect.left); + el.y = Math.round(rect.top); + this._save(); + } + }; + handle.addEventListener('pointerdown', onStart); + handle.addEventListener('pointermove', onMove); + handle.addEventListener('pointerup', onEnd); + handle.addEventListener('pointercancel', onEnd); + handle.style.touchAction = 'none'; + handle.style.cursor = 'grab'; + } + _renderElement(el) { switch (el.type) { case 'button': return this._renderButton(el); @@ -191,13 +248,31 @@ class FloatingModule { _renderPanel(el) { const panel = document.createElement('div'); panel.className = 'floating-panel'; + const titleHtml = this._escapeHtml(el.label); + const contentHtml = this._renderMarkdownLite(el.content); panel.innerHTML = ` -
${this._escapeHtml(el.label)}
-
${this._escapeHtml(el.content)}
+
${titleHtml}
+
${contentHtml}
`; return panel; } + _renderMarkdownLite(str) { + if (!str) return ''; + let html = this._escapeHtml(str); + // **bold** + html = html.replace(/\*\*(.+?)\*\*/g, '$1'); + // *italic* + html = html.replace(/\*(.+?)\*/g, '$1'); + // `code` + html = html.replace(/`([^`]+)`/g, '$1'); + // [text](url) + html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); + // newlines to
+ html = html.replace(/\n/g, '
'); + return html; + } + _escapeHtml(str) { if (!str) return ''; return str.replace(/&/g, '&').replace(//g, '>') @@ -252,7 +327,10 @@ class FloatingModule { const secondColon = btnBuf.indexOf(':', firstColon + 1); if (secondColon === -1) continue; // need more args to find command const prefix = btnBuf.substring(0, firstColon); - if (prefix !== 'btn') { btnBuf = ''; continue; } + if (prefix !== 'btn') { + this.terminal.print(`Warning: skipping "${btnBuf}" — expected "btn:Label:cmd" (got prefix "${prefix}")`, 'warning'); + btnBuf = ''; continue; + } const label = btnBuf.substring(firstColon + 1, secondColon); const command = btnBuf.substring(secondColon + 1); if (label && command) { -- cgit v1.2.3