- Move all inline <script> blocks (layout head/theme, topbar dark toggle, foot, paste, new, history, mine, settings, admin, unlock) to external files under internal/web/static/. Page data reaches scripts via data-* attributes (data-paste-id, data-default-dark) instead of template vars. - Replace inline onclick handlers (copy, delete, stats toggle) with addEventListener wiring. - Convert inline style="" attributes to CSS utility classes; swatch colors are now set via CSSOM/DOM APIs instead of innerHTML strings. - script-src/style-src are now plain 'self'; img-src data: stays for the SVG data-URI backgrounds. Verified with headless chromium: zero CSP violations on all pages in dark and light presets, theme swatches, admin lock, tables and paste view render correctly.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
// #53/#139: paste viewer page logic. Paste id arrives via <body data-paste-id>.
|
||||
function toast(msg) {
|
||||
let t = document.querySelector('.toast');
|
||||
if (!t) { t = document.createElement('div'); t.className = 'toast'; document.body.appendChild(t); }
|
||||
t.textContent = msg;
|
||||
t.classList.add('show');
|
||||
clearTimeout(t._h);
|
||||
t._h = setTimeout(() => t.classList.remove('show'), 2000);
|
||||
}
|
||||
function toggleStats() {
|
||||
const body = document.getElementById('stats-body');
|
||||
const pill = document.getElementById('stats-pill');
|
||||
const btn = document.getElementById('stats-toggle');
|
||||
const open = body.hidden;
|
||||
body.hidden = !open;
|
||||
pill.classList.toggle('open', open);
|
||||
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||||
}
|
||||
function copyContent(btn) {
|
||||
navigator.clipboard.writeText(document.getElementById('raw-content').value);
|
||||
// in-place success feedback (#53)
|
||||
if (btn) {
|
||||
btn.classList.add('ok');
|
||||
btn.textContent = 'Success!';
|
||||
clearTimeout(btn._okh);
|
||||
btn._okh = setTimeout(() => { btn.classList.remove('ok'); btn.textContent = 'copy'; }, 2000);
|
||||
} else {
|
||||
toast('Copied', 'success');
|
||||
}
|
||||
}
|
||||
function redeem() {
|
||||
if (!confirm('Hard delete this paste immediately?')) return;
|
||||
let tok = '';
|
||||
try { tok = sessionStorage.getItem('deletion_token_' + PASTE_ID) || ''; } catch(e) {}
|
||||
if (!tok) { alert('deletion token not available in this browser'); return; }
|
||||
fetch('/api/pastes/' + PASTE_ID + '/redeem', {method: 'DELETE', headers: {'Authorization': 'Bearer ' + tok}})
|
||||
.then(r => { if (r.ok) location.href = '/history'; else alert('delete failed'); });
|
||||
}
|
||||
|
||||
// wiring (moved from inline handlers for CSP #139)
|
||||
var PASTE_ID = document.currentScript.getAttribute('data-paste-id');
|
||||
var copyBtn = document.getElementById('copy-btn');
|
||||
if (copyBtn) copyBtn.addEventListener('click', function (e) { e.preventDefault(); copyContent(copyBtn); });
|
||||
var delBtn = document.getElementById('delete-btn');
|
||||
if (delBtn) delBtn.addEventListener('click', function (e) { e.preventDefault(); redeem(); });
|
||||
var statsToggle = document.getElementById('stats-toggle');
|
||||
if (statsToggle) statsToggle.addEventListener('click', toggleStats);
|
||||
Reference in New Issue
Block a user