- wrap toggle button on /new editor and paste view (accent active state) - flips white-space pre <-> pre-wrap on the code body - shared localStorage preference palette-wrap, default off - settings checkbox reads and writes the same preference
105 lines
5.0 KiB
HTML
105 lines
5.0 KiB
HTML
{{template "head" .}}
|
|
{{template "topbar" .}}
|
|
<div class="page">
|
|
<div class="float">
|
|
<div class="paste-title-bar">
|
|
<h1>{{if .Title}}{{.Title}}{{else}}Untitled paste{{end}}</h1>
|
|
{{if .CustomSlug}}<span class="slug">/{{.CustomSlug}}</span>{{end}}
|
|
<div class="spacer"></div>
|
|
<button class="iconbtn wrap-toggle" id="wrap-toggle" type="button" title="Toggle line wrap" aria-label="Toggle line wrap" aria-pressed="false">wrap</button>
|
|
<a class="iconbtn" href="/raw/{{.ID}}">raw</a>
|
|
<a class="iconbtn" href="#" id="copy-btn" onclick="copyContent(this); return false;">copy</a>
|
|
{{if .DeletionToken}}<a class="iconbtn danger" href="#" onclick="redeem('{{.DeletionToken}}'); return false;">delete</a>{{end}}
|
|
</div>
|
|
</div>
|
|
<div class="float">
|
|
<div class="stats-pill" id="stats-pill">
|
|
<button type="button" class="stats-head" id="stats-toggle" aria-expanded="false" onclick="toggleStats()">
|
|
<svg class="stats-chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>
|
|
<span class="stats-summary">{{.StatsSummary}}</span>
|
|
</button>
|
|
<div class="stats-body" id="stats-body" hidden>
|
|
<div class="stats-grid">
|
|
<span class="stats-k">Language</span><span class="stats-v">{{if .Language}}{{.Language}}{{else}}text{{end}}</span>
|
|
<span class="stats-k">Size</span><span class="stats-v">{{.SizeHuman}} ({{.LineCount}} lines)</span>
|
|
<span class="stats-k">Views</span><span class="stats-v">{{.ViewCount}}</span>
|
|
<span class="stats-k">Created</span><span class="stats-v" data-ts="{{.CreatedAtUnix}}">{{.CreatedAgo}}</span>
|
|
{{if .ExpiresAt}}<span class="stats-k">Expires</span><span class="stats-v">in {{.ExpiresIn}}</span>{{end}}
|
|
<span class="stats-k">Password</span><span class="stats-v">{{if .HasPassword}}protected{{else}}none{{end}}</span>
|
|
{{if .BurnAfterRead}}{{if .ReadsLimit}}{{with .ReadsLeftN}}<span class="stats-k">Reads left</span><span class="stats-v">{{.}} of {{$.ReadsTotal}}</span>{{end}}{{else}}<span class="stats-k">Burn</span><span class="stats-v">burn after read</span>{{end}}{{end}}
|
|
{{if .CustomSlug}}<span class="stats-k">Custom URL</span><span class="stats-v">/{{.CustomSlug}}</span>{{end}}
|
|
<span class="stats-k">Visibility</span><span class="stats-v">{{.Visibility}}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{if .JustCreated}}
|
|
<div class="float">
|
|
<div class="created-banner" style="display:block">
|
|
Paste created. Link copied to clipboard: <a href="/{{.ID}}">{{.Host}}/{{.ID}}</a>
|
|
{{if .DeletionToken}} · deletion token: <code>{{.DeletionToken}}</code>{{end}}
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
<div class="float">
|
|
<div class="code"><div class="gutter">{{.Gutter}}</div><div class="codebody" id="codebody">{{.ContentHTML}}</div></div>
|
|
</div>
|
|
</div>
|
|
<input type="hidden" id="raw-content" value="{{.ContentAttr}}">
|
|
<script>
|
|
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(token) {
|
|
if (!confirm('Hard delete this paste immediately?')) return;
|
|
fetch('/api/pastes/{{.ID}}/redeem?token=' + encodeURIComponent(token), {method: 'DELETE'})
|
|
.then(r => { if (r.ok) location.href = '/history'; else alert('delete failed'); });
|
|
}
|
|
|
|
// #130: line wrap toggle, shared preference with the editor (palette-wrap)
|
|
(function () {
|
|
var el = document.getElementById('codebody');
|
|
var btn = document.getElementById('wrap-toggle');
|
|
function apply(on) {
|
|
el.classList.toggle('wrap', on);
|
|
btn.setAttribute('aria-pressed', on ? 'true' : 'false');
|
|
}
|
|
var on = false;
|
|
try { on = localStorage.getItem('palette-wrap') === 'true'; } catch (e) {}
|
|
apply(on);
|
|
btn.addEventListener('click', function () {
|
|
on = !on;
|
|
try { localStorage.setItem('palette-wrap', on ? 'true' : 'false'); } catch (e) {}
|
|
apply(on);
|
|
});
|
|
document.addEventListener('palette-wrapchange', function (e) { apply(e.detail); });
|
|
})();
|
|
</script>
|
|
{{template "foot" .}}
|