From 0b3d7d542fec640b40aca71caaa90d9d73aeb5e6 Mon Sep 17 00:00:00 2001 From: Gmer4Lfe Date: Thu, 4 Jun 2026 21:56:22 -0400 Subject: [PATCH] editor: add word wrap toggle to status bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a "Wrap" button to the editor status bar that toggles word wrap on/off, persisted in localStorage. Default is nowrap with horizontal scroll (standard code editor behaviour). In wrap mode the line-number gutter and current-line highlight are hidden — both rely on fixed line-height calculations that break when lines wrap visually. CSS: textarea/overlay default to white-space:pre; .vv-ed-wrap class (on #vv-editor-wrap) overrides to pre-wrap, hides gutter and cur-line. JS: vvWordWrap state, vvApplyWordWrap(), vvToggleWordWrap(); guards in vvUpdateLineNums() and vvUpdateCurLine(); restored via vvRestoreEditorPrefs() on both script and raw-conf editor entry points. --- Plugin/unraid/css/varaverk.css | 11 +++++++++-- Plugin/unraid/pages/scheduler.php | 31 +++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Plugin/unraid/css/varaverk.css b/Plugin/unraid/css/varaverk.css index b01af3a..09ca18c 100644 --- a/Plugin/unraid/css/varaverk.css +++ b/Plugin/unraid/css/varaverk.css @@ -323,7 +323,8 @@ #vv-editor { flex-direction: column; gap: 0; } .vv-editor-body { font-family: monospace; font-size: 12px; background: #0d0d0d; color: #ccc; border: 1px solid #333; border-radius: 4px; padding: 10px 12px; resize: none; - line-height: 1.5; scroll-behavior: auto; tab-size: 2; width: 100%; box-sizing: border-box; } + line-height: 1.5; scroll-behavior: auto; tab-size: 2; width: 100%; box-sizing: border-box; + white-space: pre; overflow-x: auto; } /* Editor layout: gutter + inner area — unified bordered block */ #vv-editor-wrap { display: flex; border: 1px solid #2e2e2e; border-radius: 4px 4px 0 0; @@ -347,7 +348,7 @@ #vv-hl-overlay { display: none; position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: 0; padding: 10px 12px; box-sizing: border-box; font-family: monospace; font-size: 12px; line-height: 1.5; tab-size: 2; - white-space: pre-wrap; word-break: break-all; overflow: hidden; + white-space: pre; overflow: hidden; pointer-events: none; user-select: none; background: transparent; border: none; border-radius: 0; } .vv-editor-hl #vv-hl-overlay { display: block; } @@ -414,6 +415,12 @@ .vv-es-btn.active { color: #6495ed; } #vv-es-fontsize { color: #444; font-size: 10px; min-width: 26px; text-align: center; } +/* Word wrap mode — applied to #vv-editor-wrap when wrap is enabled */ +#vv-editor-wrap.vv-ed-wrap .vv-editor-body { white-space: pre-wrap !important; overflow-x: hidden !important; } +#vv-editor-wrap.vv-ed-wrap #vv-hl-overlay { white-space: pre-wrap !important; word-break: break-word !important; } +#vv-editor-wrap.vv-ed-wrap #vv-ln-gutter { display: none; } +#vv-editor-wrap.vv-ed-wrap #vv-cur-line { display: none !important; } + /* Indent guides — 1px lines every 2 chars, starting at indent level 1 */ #vv-editor-inner { position: relative; flex: 1; overflow: hidden; diff --git a/Plugin/unraid/pages/scheduler.php b/Plugin/unraid/pages/scheduler.php index 704b2be..7c1f7d7 100644 --- a/Plugin/unraid/pages/scheduler.php +++ b/Plugin/unraid/pages/scheduler.php @@ -944,6 +944,7 @@ Still the same two servers, two households, the same media stack running itself. 12px + @@ -1031,6 +1032,7 @@ const VV_PAIRS = {'(':')', '[':']', '{':'}', '"':'"', "'":"'", '`':'`'}; const VV_CLOSE = new Set([')', ']', '}', '"', "'", '`']); // Editor display prefs let vvFontSizePx = parseInt(localStorage.getItem('vv-editor-fontsize') || '12') || 12; +let vvWordWrap = localStorage.getItem('vv-editor-wordwrap') === '1'; // Line height helper — used everywhere instead of hardcoded 18 function vvLH() { return vvFontSizePx * 1.5; } @@ -2693,6 +2695,7 @@ function vvEditRawConf(file) { function vvShowRawConfMode(title) { vvEditorReset(); + vvRestoreEditorPrefs(); document.getElementById('vv-editor-status').classList.add('vv-ed-active'); document.getElementById('vv-es-lang').textContent = 'Bash / Config'; document.getElementById('vv-undo-btn').style.display = ''; @@ -2836,7 +2839,7 @@ function vvSyncHlScroll() { function vvUpdateLineNums() { const gutter = document.getElementById('vv-ln-gutter'); const ta = document.getElementById('vv-editor-body'); - if (!gutter || !ta) return; + if (!gutter || !ta || vvWordWrap) return; const lines = ta.value.split('\n').length; const curLn = ta.value.slice(0, ta.selectionStart).split('\n').length; let html = ''; @@ -2851,7 +2854,7 @@ function vvUpdateLineNums() { function vvUpdateCurLine() { const ta = document.getElementById('vv-editor-body'); const cl = document.getElementById('vv-cur-line'); - if (!cl || !ta) return; + if (!cl || !ta || vvWordWrap) return; const lineH = vvLH(); const padTop = 10; // overlay padding-top const lineN = ta.value.slice(0, ta.selectionStart).split('\n').length - 1; // 0-indexed @@ -3058,6 +3061,30 @@ function vvRestoreEditorPrefs() { const fs_el = document.getElementById('vv-es-fontsize'); if (fs_el) fs_el.textContent = '12px'; } + vvWordWrap = localStorage.getItem('vv-editor-wordwrap') === '1'; + vvApplyWordWrap(false); +} + +// ── Word wrap toggle ────────────────────────────────────────────────────────── + +function vvApplyWordWrap(save) { + const wrap = document.getElementById('vv-editor-wrap'); + const btn = document.getElementById('vv-es-wrap-btn'); + if (!wrap) return; + if (vvWordWrap) { + wrap.classList.add('vv-ed-wrap'); + if (btn) { btn.classList.add('active'); btn.title = 'Word wrap ON — click to disable'; } + } else { + wrap.classList.remove('vv-ed-wrap'); + if (btn) { btn.classList.remove('active'); btn.title = 'Word wrap OFF — click to enable'; } + } + if (save) localStorage.setItem('vv-editor-wordwrap', vvWordWrap ? '1' : '0'); + vvSyncHlOverlay(); +} + +function vvToggleWordWrap() { + vvWordWrap = !vvWordWrap; + vvApplyWordWrap(true); } // ── Go to line ────────────────────────────────────────────────────────────────