Show the terse control list when the help block is collapsed
This commit is contained in:
@@ -106,6 +106,79 @@ function vv_docs_render(string $rel, array $vars, ?callable $keep = null): strin
|
||||
// here, after escaping. Injecting <code> into the markdown before rendering, as this file used to
|
||||
// do, meant both Parsedown's safe mode and the <pre> fallback escaped the tags and printed them
|
||||
// as literal text. The feature never worked; nothing called it, so nothing reported it.
|
||||
// Inline formatting for one line of markdown. Standalone rather than a closure because both the
|
||||
// full renderer and the brief list below use it — two copies would drift, and the whole point of
|
||||
// these docs is that the panel and the assistant cannot disagree.
|
||||
//
|
||||
// Escape first, then format: the only HTML in the output is HTML this function put there.
|
||||
function vv_docs_inline(string $s, array $vars): string {
|
||||
$s = htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
|
||||
// `$VAR` → the live conf value. Unresolved names render in their own class rather than
|
||||
// silently reading as prose, so a stale reference in a doc is visible as a defect.
|
||||
$s = preg_replace_callback('/`\$([A-Z0-9_]+)`/', function ($m) use ($vars) {
|
||||
return isset($vars[$m[1]])
|
||||
? '<code class="vv-live-var">' . htmlspecialchars($vars[$m[1]]) . '</code>'
|
||||
: '<code class="vv-unknown-var">$' . $m[1] . '</code>';
|
||||
}, $s);
|
||||
$s = preg_replace('/`([^`]+)`/', '<code>$1</code>', $s);
|
||||
$s = preg_replace('/\*\*([^*]+)\*\*/', '<strong>$1</strong>', $s);
|
||||
$s = preg_replace('/(?<![\w*])\*([^*]+)\*(?![\w*])/', '<em>$1</em>', $s);
|
||||
// Links are restricted to http/https and relative paths — a doc is trusted, but these files
|
||||
// sync between hosts, so javascript: must not be reachable through one.
|
||||
$s = preg_replace('/\[([^\]]+)\]\((https?:\/\/[^\s)]+|[^\s):]+)\)/', '<a href="$2">$1</a>', $s);
|
||||
return $s;
|
||||
}
|
||||
|
||||
// Terse one-line-per-control list — the shape this help had before it became a document.
|
||||
// Reads the same markdown as the full render, so the collapsed and expanded views cannot drift.
|
||||
//
|
||||
// Only table rows and bullets survive. Paragraphs are dropped on purpose: a list you sweep with
|
||||
// your eye stops working the moment there is prose between the rows, and that is precisely what
|
||||
// made the original comb well. Section titles become the full-width divider the old list used.
|
||||
function vv_docs_brief(string $rel, array $vars, ?callable $keep = null): string {
|
||||
$base = realpath(SCRIPTS_DIR);
|
||||
$path = realpath(SCRIPTS_DIR . '/' . $rel);
|
||||
if ($base === false || $path === false) return '';
|
||||
if (!str_starts_with($path, $base . '/')) return '';
|
||||
if (strtolower(pathinfo($path, PATHINFO_EXTENSION)) !== 'md') return '';
|
||||
|
||||
$out = '';
|
||||
$skip = $keep !== null && !$keep(null);
|
||||
$rowN = 0; // per-table row counter — row 0 is the header, not content
|
||||
|
||||
foreach (explode("\n", str_replace("\r\n", "\n", (string)@file_get_contents($path))) as $line) {
|
||||
$t = trim($line);
|
||||
|
||||
if (preg_match('/^(#{1,6})\s+(.*)$/', $t, $m)) {
|
||||
$rowN = 0;
|
||||
$skip = $keep !== null && !$keep(strlen($m[1]) === 1 ? null : $m[2]);
|
||||
// "Reference — the controls on a job row" reads as "the controls on a job row" once
|
||||
// the whole list is reference material.
|
||||
if (!$skip && strlen($m[1]) > 1) {
|
||||
$h = preg_replace('/^Reference\s*—\s*/u', '', $m[2]);
|
||||
$out .= '<li class="vv-info-sep">' . vv_docs_inline($h, $vars) . "</li>\n";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($skip || $t === '') { if ($t === '') $rowN = 0; continue; }
|
||||
|
||||
if (preg_match('/^[-*]\s+(.*)$/', $t, $m)) {
|
||||
$out .= '<li>' . vv_docs_inline($m[1], $vars) . "</li>\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos($t, '|') !== false && substr_count($t, '|') >= 2) {
|
||||
if (preg_match('/^\|?[\s:-]*-[\s|:-]*\|/', $t)) continue; // the --- separator
|
||||
$cells = array_map('trim', explode('|', trim($t, '| ')));
|
||||
if ($rowN++ === 0) continue; // header row
|
||||
$term = array_shift($cells);
|
||||
$out .= '<li><strong>' . vv_docs_inline($term, $vars) . '</strong> — '
|
||||
. vv_docs_inline(implode(' · ', array_filter($cells)), $vars) . "</li>\n";
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
function vv_docs_markdown(string $md, array $vars, ?callable $keep = null): string {
|
||||
if (file_exists(PARSEDOWN_PATH)) {
|
||||
require_once PARSEDOWN_PATH;
|
||||
@@ -114,23 +187,7 @@ function vv_docs_markdown(string $md, array $vars, ?callable $keep = null): stri
|
||||
return $pd->text($md);
|
||||
}
|
||||
|
||||
$inline = function (string $s) use ($vars): string {
|
||||
$s = htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
|
||||
// `$VAR` → the live conf value. Unresolved names render in their own class rather than
|
||||
// silently reading as prose, so a stale reference in a doc is visible as a defect.
|
||||
$s = preg_replace_callback('/`\$([A-Z0-9_]+)`/', function ($m) use ($vars) {
|
||||
return isset($vars[$m[1]])
|
||||
? '<code class="vv-live-var">' . htmlspecialchars($vars[$m[1]]) . '</code>'
|
||||
: '<code class="vv-unknown-var">$' . $m[1] . '</code>';
|
||||
}, $s);
|
||||
$s = preg_replace('/`([^`]+)`/', '<code>$1</code>', $s);
|
||||
$s = preg_replace('/\*\*([^*]+)\*\*/', '<strong>$1</strong>', $s);
|
||||
$s = preg_replace('/(?<![\w*])\*([^*]+)\*(?![\w*])/', '<em>$1</em>', $s);
|
||||
// Links are restricted to http/https and relative paths — a doc is trusted, but these
|
||||
// files sync between hosts, so javascript: must not be reachable through one.
|
||||
$s = preg_replace('/\[([^\]]+)\]\((https?:\/\/[^\s)]+|[^\s):]+)\)/', '<a href="$2">$1</a>', $s);
|
||||
return $s;
|
||||
};
|
||||
$inline = fn(string $s): string => vv_docs_inline($s, $vars);
|
||||
|
||||
$out = '';
|
||||
$list = null; // 'ul' | 'ol' | null
|
||||
|
||||
@@ -508,16 +508,21 @@ $runningScripts = array_unique($runningScripts);
|
||||
also what the AI tab retrieves, so the panel you read and the answer the
|
||||
assistant gives are the same text and cannot drift — the same argument that
|
||||
makes this page parse script PURPOSE blocks instead of restating them.
|
||||
Everything lives inside the collapsible body, and collapsed means gone. An
|
||||
earlier version kept the reference tables permanently visible below the fold
|
||||
line: 33 table rows that pushed Next Runs, Recent Errors, Activity, Locks and
|
||||
the rest off the bottom of a fixed-height panel. Reference material must not
|
||||
outrank the live state of the machine on the page you watch it from. -->
|
||||
Two views of one file, swapped rather than stacked. Collapsed shows the terse
|
||||
one-line-per-control list this help used to be — short enough that Next Runs and
|
||||
the error blocks stay on screen, which an earlier always-visible tier of 33
|
||||
table rows was not. Expanding replaces it with the full document.
|
||||
.vv-sug-brief is the inverse of .vv-sug-body; vvToggleSug() and
|
||||
vvRestoreSugStates() drive both. -->
|
||||
<div class="vv-sug-body vv-info-body">
|
||||
<div class="vv-doc">
|
||||
<?= vv_docs_render('Plugin/unraid/pages/readme/scheduler-readme.md', $_vv_doc_vars) ?>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="vv-info-cols vv-sug-brief vv-info-body" style="display:none">
|
||||
<?= vv_docs_brief('Plugin/unraid/pages/readme/scheduler-readme.md', $_vv_doc_vars,
|
||||
fn($h) => is_string($h) && str_starts_with($h, 'Reference —')) ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- ── Next Runs ── -->
|
||||
@@ -2104,6 +2109,10 @@ function vvToggleSug(header) {
|
||||
body.style.display = open ? 'none' : '';
|
||||
chevron.textContent = open ? '▸' : '▾';
|
||||
const block = header.closest('[data-save-key]');
|
||||
// Optional collapsed-state summary: shown exactly when the body is hidden. Lets a block put
|
||||
// something terse on screen while shut instead of nothing, without a second toggle to manage.
|
||||
const brief = block && block.querySelector('.vv-sug-brief');
|
||||
if (brief) brief.style.display = open ? '' : 'none';
|
||||
if (block) localStorage.setItem('vv-sug-' + block.dataset.saveKey, open ? '0' : '1');
|
||||
}
|
||||
|
||||
@@ -2117,6 +2126,8 @@ function vvRestoreSugStates() {
|
||||
const open = saved === '1';
|
||||
body.style.display = open ? '' : 'none';
|
||||
if (chevron) chevron.textContent = open ? '▾' : '▸';
|
||||
const brief = block.querySelector('.vv-sug-brief');
|
||||
if (brief) brief.style.display = open ? 'none' : '';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user