Label and checkmark stack in one grid cell (inline-grid, grid-area 1/1, checkmark visibility-hidden until .ok), so the button width is static by construction across the click. Replaces the min-width pin from fix attempt 1, which enlarged buttons by up to 0.64px (ceil of fractional width) and leaked the pin after restore. Applies to paste-view Copy/Link (paste.html + paste.js copyFeedback) and the /new result-box copy button (new.js). Verified with CDP bounding-box probes: Copy width/x identical before/during/after at 1400x900 and 375x812 (including the previously failing 52.36px mobile case), Link button static, checkmark visible during feedback, no minWidth pin set.
65 lines
2.9 KiB
JavaScript
65 lines
2.9 KiB
JavaScript
// #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 copyFeedback(btn) {
|
|
if (!btn) return;
|
|
// #260: the .swapbtn grid stacks label + checkmark in one cell, so the
|
|
// width is static by construction — feedback is a pure class toggle.
|
|
btn.classList.add('ok');
|
|
clearTimeout(btn._okh);
|
|
btn._okh = setTimeout(() => btn.classList.remove('ok'), 2000);
|
|
}
|
|
function copyContent(btn) {
|
|
navigator.clipboard.writeText(document.getElementById('raw-content').value)
|
|
.then(() => copyFeedback(btn))
|
|
.catch(() => toast('Copy failed'));
|
|
}
|
|
// #243: copy the paste LINK (full URL), not the paste id or content
|
|
function copyLink(btn) {
|
|
const url = location.origin + location.pathname;
|
|
navigator.clipboard.writeText(url)
|
|
.then(() => copyFeedback(btn))
|
|
.catch(() => toast('Copy failed'));
|
|
}
|
|
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 = '/public'; 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 copyLinkBtn = document.getElementById('copy-link-btn');
|
|
if (copyLinkBtn) copyLinkBtn.addEventListener('click', function (e) { e.preventDefault(); copyLink(copyLinkBtn); });
|
|
var delBtn = document.getElementById('delete-btn');
|
|
|
|
// #168: show the compact paste-created pill in the bottom corner, then fade it out
|
|
const createdPill = document.getElementById('created-pill');
|
|
if (createdPill) {
|
|
requestAnimationFrame(() => createdPill.classList.add('show'));
|
|
setTimeout(() => createdPill.classList.remove('show'), 4000);
|
|
}
|
|
if (delBtn) delBtn.addEventListener('click', function (e) { e.preventDefault(); redeem(); });
|
|
var statsToggle = document.getElementById('stats-toggle');
|
|
if (statsToggle) statsToggle.addEventListener('click', toggleStats);
|