Add share link UI after upload
This commit is contained in:
+85
-40
@@ -4,6 +4,30 @@
|
||||
'use strict';
|
||||
|
||||
var base = document.body.dataset.base || '/';
|
||||
|
||||
// Copy buttons appear on the server-rendered result page too, which has no
|
||||
// upload form, so they are wired before anything form-specific bails out.
|
||||
// They ship hidden so that without this script there is no dead button.
|
||||
function wireCopy(root) {
|
||||
var buttons = root.querySelectorAll('button.copy[data-copy]');
|
||||
Array.prototype.forEach.call(buttons, function (button) {
|
||||
var target = document.getElementById(button.dataset.copy);
|
||||
if (!target) return;
|
||||
button.hidden = false;
|
||||
button.addEventListener('click', function () {
|
||||
target.select();
|
||||
var done = function () {
|
||||
var was = button.textContent;
|
||||
button.textContent = 'Copied';
|
||||
setTimeout(function () { button.textContent = was; }, 1500);
|
||||
};
|
||||
if (navigator.clipboard) navigator.clipboard.writeText(target.value).then(done, function () {});
|
||||
else { document.execCommand('copy'); done(); }
|
||||
});
|
||||
});
|
||||
}
|
||||
wireCopy(document);
|
||||
|
||||
var form = document.getElementById('upload');
|
||||
if (!form) return;
|
||||
|
||||
@@ -174,58 +198,79 @@
|
||||
return Math.floor(m / 60) + 'h ' + (m % 60) + 'm';
|
||||
}
|
||||
|
||||
// Mirrors web/templates/result.html, so the JavaScript and no-JavaScript
|
||||
// paths show the same thing.
|
||||
function showResult(r) {
|
||||
var card = document.createElement('section');
|
||||
card.className = 'card result';
|
||||
var card = el('section', 'card result');
|
||||
card.appendChild(el('h1', null, 'Uploaded'));
|
||||
card.appendChild(el('p', 'filename', r.filename));
|
||||
|
||||
var h = document.createElement('h1');
|
||||
h.textContent = 'Uploaded';
|
||||
card.appendChild(h);
|
||||
|
||||
var field = document.createElement('label');
|
||||
field.className = 'field';
|
||||
var span = document.createElement('span');
|
||||
span.textContent = 'Download link';
|
||||
var input = document.createElement('input');
|
||||
input.type = 'text';
|
||||
input.readOnly = true;
|
||||
input.value = r.url;
|
||||
field.appendChild(span);
|
||||
field.appendChild(input);
|
||||
card.appendChild(field);
|
||||
|
||||
var copy = document.createElement('button');
|
||||
copy.type = 'button';
|
||||
copy.textContent = 'Copy link';
|
||||
copy.addEventListener('click', function () {
|
||||
input.select();
|
||||
var done = function () { copy.textContent = 'Copied'; };
|
||||
if (navigator.clipboard) navigator.clipboard.writeText(r.url).then(done, function () {});
|
||||
else { document.execCommand('copy'); done(); }
|
||||
});
|
||||
card.appendChild(copy);
|
||||
var links = el('div', 'links');
|
||||
links.appendChild(linkField(
|
||||
'Share link', 'a page showing size, expiry and a download button',
|
||||
'link-info', r.info_url));
|
||||
links.appendChild(linkField(
|
||||
'Direct download', 'the file itself, for curl, wget or a browser',
|
||||
'link-file', r.url));
|
||||
card.appendChild(links);
|
||||
|
||||
var dl = document.createElement('dl');
|
||||
addRow(dl, 'Size', formatSize(r.size));
|
||||
addRow(dl, 'Expires', r.expires || 'never');
|
||||
addRow(dl, 'SHA-256', r.sha256, 'mono wrap');
|
||||
card.appendChild(dl);
|
||||
|
||||
var warn = document.createElement('div');
|
||||
warn.className = 'warn';
|
||||
var wh = document.createElement('h2');
|
||||
wh.textContent = 'Delete token';
|
||||
var wp = document.createElement('p');
|
||||
wp.textContent = 'Shown once. Keep it if you want to remove the file early.';
|
||||
var wt = document.createElement('p');
|
||||
wt.className = 'mono wrap';
|
||||
wt.textContent = r.delete_token;
|
||||
warn.appendChild(wh);
|
||||
warn.appendChild(wp);
|
||||
warn.appendChild(wt);
|
||||
var warn = el('div', 'warn');
|
||||
warn.appendChild(el('h2', null, 'Delete token'));
|
||||
warn.appendChild(el('p', null, 'Shown once. Keep it if you want to remove the file before it expires.'));
|
||||
warn.appendChild(el('p', 'mono wrap', r.delete_token));
|
||||
card.appendChild(warn);
|
||||
|
||||
var actions = el('p', 'actions');
|
||||
var again = document.createElement('a');
|
||||
again.className = 'button';
|
||||
again.href = base;
|
||||
again.textContent = 'Upload another file';
|
||||
actions.appendChild(again);
|
||||
card.appendChild(actions);
|
||||
|
||||
form.parentNode.insertBefore(card, form);
|
||||
form.hidden = true;
|
||||
wireCopy(card);
|
||||
card.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
|
||||
function el(tag, cls, text) {
|
||||
var node = document.createElement(tag);
|
||||
if (cls) node.className = cls;
|
||||
if (text !== undefined && text !== null) node.textContent = text;
|
||||
return node;
|
||||
}
|
||||
|
||||
// One labelled, read-only URL with a copy button beside it.
|
||||
function linkField(label, hint, id, value) {
|
||||
var field = el('div', 'field');
|
||||
var span = document.createElement('span');
|
||||
span.appendChild(document.createTextNode(label + ' '));
|
||||
span.appendChild(el('em', null, hint));
|
||||
field.appendChild(span);
|
||||
|
||||
var row = el('div', 'copyrow');
|
||||
var input = document.createElement('input');
|
||||
input.type = 'text';
|
||||
input.id = id;
|
||||
input.readOnly = true;
|
||||
input.value = value;
|
||||
row.appendChild(input);
|
||||
|
||||
var button = el('button', 'copy', 'Copy');
|
||||
button.type = 'button';
|
||||
button.hidden = true;
|
||||
button.dataset.copy = id;
|
||||
row.appendChild(button);
|
||||
|
||||
field.appendChild(row);
|
||||
return field;
|
||||
}
|
||||
|
||||
function addRow(dl, label, value, cls) {
|
||||
|
||||
@@ -166,3 +166,24 @@ button.link {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Result card ------------------------------------------------------------ */
|
||||
|
||||
.result .links { margin: 1.25rem 0 0; }
|
||||
.result .links .field { margin-bottom: 1rem; }
|
||||
|
||||
/* A read-only URL with its copy button alongside. */
|
||||
.copyrow { display: flex; gap: .5rem; align-items: stretch; }
|
||||
.copyrow input { flex: 1 1 auto; min-width: 0; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .8125rem; }
|
||||
.copyrow .copy { flex: 0 0 auto; }
|
||||
|
||||
/* Keep the detail list clear of the copy buttons above it. */
|
||||
.result dl { margin-top: 1.75rem; padding-top: 1.25rem; border-top: 1px solid var(--line); }
|
||||
.result dl dd { margin-bottom: .25rem; }
|
||||
|
||||
.result .actions { margin: 1.5rem 0 0; }
|
||||
|
||||
@media (max-width: 26rem) {
|
||||
.copyrow { flex-wrap: wrap; }
|
||||
.copyrow input { flex-basis: 100%; }
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<main>
|
||||
{{template "content" .}}
|
||||
</main>
|
||||
<footer>Files are removed automatically when they expire.</footer>
|
||||
{{if .Script}}<script src="{{.Base}}static/app.js" defer></script>{{end}}
|
||||
</body>
|
||||
</html>{{end}}
|
||||
|
||||
@@ -3,10 +3,23 @@
|
||||
<h1>Uploaded</h1>
|
||||
<p class="filename">{{.Meta.Filename}}</p>
|
||||
|
||||
<label class="field">
|
||||
<span>Download link</span>
|
||||
<input type="text" id="link" value="{{.URL}}" readonly>
|
||||
</label>
|
||||
<div class="links">
|
||||
<div class="field">
|
||||
<span>Share link <em>a page showing size, expiry and a download button</em></span>
|
||||
<div class="copyrow">
|
||||
<input type="text" id="link-info" value="{{.InfoURL}}" readonly>
|
||||
<button type="button" class="copy" data-copy="link-info" hidden>Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<span>Direct download <em>the file itself, for curl, wget or a browser</em></span>
|
||||
<div class="copyrow">
|
||||
<input type="text" id="link-file" value="{{.URL}}" readonly>
|
||||
<button type="button" class="copy" data-copy="link-file" hidden>Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<dl>
|
||||
<dt>Size</dt><dd>{{.Size}}</dd>
|
||||
@@ -24,6 +37,6 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<p><a href="{{.Base}}">Upload another</a></p>
|
||||
<p class="actions"><a class="button" href="{{.Base}}">Upload another file</a></p>
|
||||
</section>
|
||||
{{end}}
|
||||
|
||||
Reference in New Issue
Block a user