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
|
// 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
|
// 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.
|
// 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 {
|
function vv_docs_markdown(string $md, array $vars, ?callable $keep = null): string {
|
||||||
if (file_exists(PARSEDOWN_PATH)) {
|
if (file_exists(PARSEDOWN_PATH)) {
|
||||||
require_once 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);
|
return $pd->text($md);
|
||||||
}
|
}
|
||||||
|
|
||||||
$inline = function (string $s) use ($vars): string {
|
$inline = fn(string $s): string => vv_docs_inline($s, $vars);
|
||||||
$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;
|
|
||||||
};
|
|
||||||
|
|
||||||
$out = '';
|
$out = '';
|
||||||
$list = null; // 'ul' | 'ol' | null
|
$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
|
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
|
assistant gives are the same text and cannot drift — the same argument that
|
||||||
makes this page parse script PURPOSE blocks instead of restating them.
|
makes this page parse script PURPOSE blocks instead of restating them.
|
||||||
Everything lives inside the collapsible body, and collapsed means gone. An
|
Two views of one file, swapped rather than stacked. Collapsed shows the terse
|
||||||
earlier version kept the reference tables permanently visible below the fold
|
one-line-per-control list this help used to be — short enough that Next Runs and
|
||||||
line: 33 table rows that pushed Next Runs, Recent Errors, Activity, Locks and
|
the error blocks stay on screen, which an earlier always-visible tier of 33
|
||||||
the rest off the bottom of a fixed-height panel. Reference material must not
|
table rows was not. Expanding replaces it with the full document.
|
||||||
outrank the live state of the machine on the page you watch it from. -->
|
.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-sug-body vv-info-body">
|
||||||
<div class="vv-doc">
|
<div class="vv-doc">
|
||||||
<?= vv_docs_render('Plugin/unraid/pages/readme/scheduler-readme.md', $_vv_doc_vars) ?>
|
<?= vv_docs_render('Plugin/unraid/pages/readme/scheduler-readme.md', $_vv_doc_vars) ?>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
|
|
||||||
<!-- ── Next Runs ── -->
|
<!-- ── Next Runs ── -->
|
||||||
@@ -2104,6 +2109,10 @@ function vvToggleSug(header) {
|
|||||||
body.style.display = open ? 'none' : '';
|
body.style.display = open ? 'none' : '';
|
||||||
chevron.textContent = open ? '▸' : '▾';
|
chevron.textContent = open ? '▸' : '▾';
|
||||||
const block = header.closest('[data-save-key]');
|
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');
|
if (block) localStorage.setItem('vv-sug-' + block.dataset.saveKey, open ? '0' : '1');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2117,6 +2126,8 @@ function vvRestoreSugStates() {
|
|||||||
const open = saved === '1';
|
const open = saved === '1';
|
||||||
body.style.display = open ? '' : 'none';
|
body.style.display = open ? '' : 'none';
|
||||||
if (chevron) chevron.textContent = open ? '▾' : '▸';
|
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