Open a cited script in the editor instead of a read-only viewer
This commit is contained in:
@@ -194,7 +194,11 @@ function vv_ai_chat_assets(): void {
|
||||
.vv-ai-think.open { display:block; }
|
||||
|
||||
.vv-ai-src { margin-top:9px; border-top:1px solid #1c1c1c; padding-top:7px; }
|
||||
.vv-ai-src-h { font-size:9px; letter-spacing:.07em; text-transform:uppercase; color:#3a3a3a; margin-bottom:4px; }
|
||||
.vv-ai-src-h { font-size:9px; letter-spacing:.07em; text-transform:uppercase; color:#3a3a3a;
|
||||
margin-bottom:4px; cursor:pointer; user-select:none; }
|
||||
.vv-ai-src-h:hover { color:#6a6a6a; }
|
||||
.vv-ai-src-car { display:inline-block; width:10px; }
|
||||
.vv-ai-src.collapsed .vv-ai-src-l { display:none; }
|
||||
.vv-ai-src-i { font-size:11px; color:#5a5a5a; padding:2px 0; cursor:pointer; display:flex; gap:8px; }
|
||||
.vv-ai-src-i:hover { color:#8a8a8a; }
|
||||
.vv-ai-src-n { color:#3a4a6a; font-family:monospace; flex-shrink:0; }
|
||||
@@ -556,7 +560,12 @@ vv_ai_profiles_script();
|
||||
// path carrying a quote interpolated into an attribute is code execution, not a display bug.
|
||||
function sourcesHtml(sources) {
|
||||
if (!sources || !sources.length) return '';
|
||||
let h = '<div class="vv-ai-src"><div class="vv-ai-src-h">Sources</div>';
|
||||
// Expanded by default and collapsible by choice, never the reverse. What the model was given
|
||||
// is the first thing worth seeing when an answer is wrong, and hiding it behind a click makes
|
||||
// a bad retrieval look like a bad model.
|
||||
let h = `<div class="vv-ai-src"><div class="vv-ai-src-h" data-src-toggle>`
|
||||
+ `<span class="vv-ai-src-car">▾</span>Sources (${sources.length})</div>`
|
||||
+ `<div class="vv-ai-src-l">`;
|
||||
sources.forEach((s, i) => {
|
||||
// A web result is a page on the internet, not a file in this install: it opens in a tab
|
||||
// rather than in the source viewer, it leads with its title rather than its URL, and it
|
||||
@@ -573,7 +582,7 @@ vv_ai_profiles_script();
|
||||
+ `<span class="vv-ai-src-n">[${i+1}]</span><span>${esc(label)}</span>`
|
||||
+ `<span class="vv-ai-src-s">${Number(s.score).toFixed(3)}</span></div>`;
|
||||
});
|
||||
return h + '</div>';
|
||||
return h + '</div></div>';
|
||||
}
|
||||
|
||||
function addAnswer(job) {
|
||||
@@ -623,7 +632,14 @@ vv_ai_profiles_script();
|
||||
if (u) window.open(u, '_blank', 'noopener,noreferrer');
|
||||
return;
|
||||
}
|
||||
if (src && src.dataset.src) { vvAiOpen(src.dataset.src); return; }
|
||||
// A page that can do something better with a source than show it gets first refusal — the
|
||||
// Scheduler opens scripts in its editor, where they can actually be changed. Everything
|
||||
// else falls through to the read-only viewer.
|
||||
if (src && src.dataset.src) {
|
||||
if (o.onOpenSource) o.onOpenSource(src.dataset.src);
|
||||
else vvAiOpen(src.dataset.src);
|
||||
return;
|
||||
}
|
||||
const cite = e.target.closest('.vv-ai-cite');
|
||||
if (cite) {
|
||||
const s = lastSources[Number(cite.dataset.cite) - 1];
|
||||
@@ -632,9 +648,23 @@ vv_ai_profiles_script();
|
||||
if (u) window.open(u, '_blank', 'noopener,noreferrer');
|
||||
return;
|
||||
}
|
||||
if (s && s.path) vvAiOpen(s.path);
|
||||
// Same routing as a source row — a citation and the row it refers to must not behave
|
||||
// differently, or clicking [3] and clicking source 3 land in different places.
|
||||
if (s && s.path) {
|
||||
if (o.onOpenSource) o.onOpenSource(s.path);
|
||||
else vvAiOpen(s.path);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const stog = e.target.closest('[data-src-toggle]');
|
||||
if (stog) {
|
||||
const box = stog.parentElement;
|
||||
box.classList.toggle('collapsed');
|
||||
const car = stog.querySelector('.vv-ai-src-car');
|
||||
if (car) car.textContent = box.classList.contains('collapsed') ? '▸' : '▾';
|
||||
return;
|
||||
}
|
||||
|
||||
const off = e.target.closest('[data-offer]');
|
||||
if (off) { answerOffer(+off.dataset.offer, off.dataset.yes === '1'); return; }
|
||||
|
||||
|
||||
@@ -2444,6 +2444,7 @@ if (document.getElementById('vv-sched-ai-chat')) {
|
||||
onOffer: (kind, yes) => { if (kind === 'fix') vvAiFixAnswer(yes); },
|
||||
// Per-block Insert buttons render only where a page can receive them.
|
||||
onInsertCode: vvAiInsertCode,
|
||||
onOpenSource: vvAiOpenSource,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2510,6 +2511,19 @@ let vvAiFixAsk = null; // { scope, symptom } while the offer is open and awa
|
||||
// It is an offer, never automatic: the editor usually holds work in progress, and a reply that
|
||||
// silently rewrote it would be far worse than copy/paste.
|
||||
|
||||
// Clicking a retrieved source here opens it where it can be changed, not just read. The component
|
||||
// falls back to its read-only viewer for anything this declines — which is everything that is not
|
||||
// a script, since api/script.php serves scripts and the index also carries READMEs and manuals.
|
||||
function vvAiOpenSource(path) {
|
||||
if (!path) return;
|
||||
if (/\.sh$/.test(path)) {
|
||||
vvEditScript(path);
|
||||
if (vvSchedChat) vvSchedChat.note('Opened ' + path + ' in the editor.');
|
||||
return;
|
||||
}
|
||||
vvAiOpen(path);
|
||||
}
|
||||
|
||||
// display:'' vs 'none' is how this panel switches views — see vvShowEditor and friends.
|
||||
function vvAiEditorOpen() {
|
||||
const ed = document.getElementById('vv-editor');
|
||||
|
||||
Reference in New Issue
Block a user