mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-09-20 00:48:00 +00:00
fix(ui): clipboard fallback for non-secure contexts; touch-friendly delete button on key scope blocks; append named model after AUTO when adding (+ docs sync: encrypted storage, AUTO chain, live probing, image endpoint)
This commit is contained in:
@ -172,6 +172,9 @@ td.t-tag { white-space:nowrap; }
|
||||
border-radius:99px; white-space:nowrap; }
|
||||
.mb .copy-b { cursor:pointer; opacity:.8; font-size:12px; padding:0 3px; }
|
||||
.mb .copy-b:hover { opacity:1; }
|
||||
.mb .mb-x { cursor:pointer; font-size:15px; line-height:1; padding:4px 5px; margin:0 2px; border-radius:6px;
|
||||
color:rgba(255,255,255,.85); background:rgba(0,0,0,.18); user-select:none; }
|
||||
.mb .mb-x:hover { background:rgba(220,53,69,.85); color:#fff; }
|
||||
.mb-ghost { position:fixed; pointer-events:none; opacity:.85; z-index:60; transform:rotate(2deg); }
|
||||
.mb-empty { color:var(--muted); font-size:12.5px; }
|
||||
.add-brick { display:inline-flex; align-items:center; gap:6px; padding:9px 16px; border-radius:12px;
|
||||
@ -582,9 +585,29 @@ function toast(m) { const el = $('#toast'); el.textContent = m; el.style.display
|
||||
function esc(s) { return String(s ?? '').replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); }
|
||||
function escAttr(s) { return esc(s).replace(/"/g, '"'); }
|
||||
function copyText(txt, okMsg) {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(txt).then(() => toast(okMsg || t('toastCopied')), () => toast(t('toastCopyFail')));
|
||||
} else { toast(t('toastCopyFail')); }
|
||||
const done = () => toast(okMsg || t('toastCopied'));
|
||||
const fail = () => toast(t('toastCopyFail'));
|
||||
if (navigator.clipboard && navigator.clipboard.writeText && window.isSecureContext) {
|
||||
navigator.clipboard.writeText(txt).then(done, () => legacyCopy(txt) ? done() : fail());
|
||||
return;
|
||||
}
|
||||
legacyCopy(txt) ? done() : fail();
|
||||
}
|
||||
function legacyCopy(txt) {
|
||||
try {
|
||||
const ta = document.createElement('textarea');
|
||||
ta.value = txt;
|
||||
ta.setAttribute('readonly', '');
|
||||
ta.style.position = 'fixed';
|
||||
ta.style.opacity = '0';
|
||||
ta.style.pointerEvents = 'none';
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
ta.setSelectionRange(0, ta.value.length);
|
||||
const ok = document.execCommand('copy');
|
||||
document.body.removeChild(ta);
|
||||
return ok;
|
||||
} catch (e) { return false; }
|
||||
}
|
||||
|
||||
/* ---------- status tab ---------- */
|
||||
@ -1779,6 +1802,7 @@ function scopeHtml(key, m) {
|
||||
<span class="mb-name">${esc(m.model)}${src ? `<em class="mb-src">${esc(src)}</em>` : ''}</span>
|
||||
<span class="mb-quota">${esc(quantBadge(m.token_quota, m.period, m.hours))}</span>
|
||||
<span class="copy-b" title="${escAttr(t('kCopyB'))}" onclick="event.stopPropagation();scopeDup('${escAttr(key)}','${escAttr(comb)}')">⧉</span>
|
||||
<span class="mb-x" title="${escAttr(t('kDelB'))}" onclick="event.stopPropagation();scopeRm('${escAttr(key)}','${escAttr(comb)}')">×</span>
|
||||
</span>`;
|
||||
}
|
||||
function normSrc(s) { return (!s || s === 'undefined' || s === 'null') ? '' : s; }
|
||||
@ -1824,10 +1848,18 @@ async function scopePush(key) {
|
||||
const canvas = document.querySelector(`.key-canvas[data-key="${CSS.escape(key)}"]`);
|
||||
if (!canvas) return;
|
||||
const scopes = readScopes(canvas);
|
||||
if (!scopes.some(s => s.model === 'AUTO')) scopes.push({ model: 'AUTO', token_quota: 0 });
|
||||
let added;
|
||||
if (!scopes.some(s => s.model === 'AUTO')) {
|
||||
added = { model: 'AUTO', token_quota: 0 };
|
||||
scopes.push(added);
|
||||
} else {
|
||||
const pick = (allModels || []).find(m => m.id && m.id !== 'AUTO' && !scopes.some(s => s.model === m.id && normSrc(s.source) === m.src));
|
||||
added = pick ? { model: pick.id, source: pick.src, token_quota: 0 } : { model: 'AUTO', token_quota: 0 };
|
||||
scopes.push(added);
|
||||
}
|
||||
try { await putScope(key, scopes); } catch (e) { toast(e.message); return; }
|
||||
await loadKeys();
|
||||
scopeEdit(key, 'AUTO');
|
||||
scopeEdit(key, scopeComb(added));
|
||||
}
|
||||
async function scopeDup(key, comb) {
|
||||
const canvas = document.querySelector(`.key-canvas[data-key="${CSS.escape(key)}"]`);
|
||||
|
||||
Reference in New Issue
Block a user