feat: HTTP interface fully functional

This commit is contained in:
meeg_leeto 2022-04-30 01:36:15 +01:00
parent b3f73fde50
commit 6c7b06f021
4 changed files with 97 additions and 17 deletions

View File

@ -6,6 +6,7 @@
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Lonk</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' media='screen' href='reset.min.css'>
<link rel='stylesheet' type='text/css' media='screen' href='main.css'>
<script src="main.js"></script>
</head>
@ -19,12 +20,12 @@
be browsing the web with Javascript blocked, then
just do a POST request to /shorten with the URL you
wish to shorten Base64-encoded as the body. -->
<form id="form">
<input type="url" name="url" id="url" required>
<form id="form" novalidate>
<input type="url" name="url" id="url" autocomplete="off" required autofocus>
<input type="submit" hidden />
</form>
<p id="info"></p>
<p id="info" state="hidden"></p>
</body>
</html>

View File

@ -0,0 +1,56 @@
body {
background-color: #0b0b0e;
width: 100vw;
min-height: 100vh;
height: 1px;
box-sizing: border-box;
padding-top: 5vh;
padding-bottom: 5vh;
display: flex;
flex-flow: column nowrap;
align-items: center;
justify-content: space-between;
}
#form {
width: 95%;
}
#form > input {
width: 100%;
background-color: transparent;
color: #ffab3e;
text-align: center;
font-family: monospace;
border: none;
border-bottom: #15151b;
}
#shortened {
font-size: calc(min(20pt, 10vw));
font-family: monospace;
color: #385d22;
text-align: center;
}
#info {
font-family: monospace;
color: rgb(91, 91, 91);
text-align: center;
}
#info[state="hidden"] {
display: none;
}
#info[state~="hidden"] {
display: block;
}
#info[state="error"] {
color: rgb(142, 49, 33);
}

View File

@ -2,19 +2,21 @@
(() => {
document.addEventListener('DOMContentLoaded', (_) => {
const waiting = false;
let waiting = false;
let xhr;
const shortened = document.getElementById('shortened');
const info = document.getElementById('info');
const field = document.getElementById('url');
field.addEventListener('change', () => {
if (waiting && xhr != null) {
xhr.abort();
}
});
const form = document.getElementById('form');
// Select the full link with one click
shortened.onclick = () => {
this.focus();
this.select();
};
// Set up the actual submission
form.addEventListener('submit', (event) => {
// We need to create a different body, so prevent the default submission.
event.preventDefault();
@ -25,7 +27,12 @@
}
// Get the URL the user is trying to shorten.
const url = document.getElementById('url').value;
let url = document.getElementById('url').value;
// If it doesn't have a protocol, assume https.
if (!/^\w+:\/\/.*$/.test(url)) {
url = 'https://' + url;
}
// Encode the URL as Base64.
const encoded = btoa(encodeURIComponent(url).replace(/%([0-9A-F]{2})/g, (match, p1) =>
@ -38,18 +45,33 @@
xhr.overrideMimeType('text/plain');
xhr.send(encoded);
xhr.onload = () => {
waiting = false;
switch (xhr.status) {
case 200:
let slug = xhr.response;
console.log(slug);
break;
const short_link = `${window.location.href}l/${slug}`;
// Display to the user
shortened.innerText = short_link;
info.setAttribute('state', 'info');
info.innerText = 'Link successfully shortened and copied to your clipboard.';
// Copy the link to the clipboard
navigator.clipboard.writeText(short_link);
break;
default:
console.log(xhr.response);
break;
info.setAttribute('state', 'error');
info.innerText = xhr.response;
break;
}
};
xhr.onerror = () => {
// TODO
waiting = false;
info.setAttribute('state', 'error');
info.innerText = "Failed to shorten the URL. Please try again.";
};
});
});

1
data/served/reset.min.css vendored Normal file
View File

@ -0,0 +1 @@
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {margin: 0;padding: 0;border: 0;font-size: 100%;font: inherit;vertical-align: baseline;}:focus {outline: 0;}article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {display: block;}body {line-height: 1;}ol, ul {list-style: none;}blockquote, q {quotes: none;}blockquote:before, blockquote:after, q:before, q:after {content: '';content: none;}table {border-collapse: collapse;border-spacing: 0;}input[type=search]::-webkit-search-cancel-button, input[type=search]::-webkit-search-decoration, input[type=search]::-webkit-search-results-button, input[type=search]::-webkit-search-results-decoration {-webkit-appearance: none;-moz-appearance: none;}input[type=search] {-webkit-appearance: none;-moz-appearance: none;-webkit-box-sizing: content-box;-moz-box-sizing: content-box;box-sizing: content-box;}textarea {overflow: auto;vertical-align: top;resize: vertical;}audio, canvas, video {display: inline-block;*display: inline;*zoom: 1;max-width: 100%;}audio:not([controls]) {display: none;height: 0;}[hidden] {display: none;}html {font-size: 100%;-webkit-text-size-adjust: 100%;-ms-text-size-adjust: 100%;}a:focus {outline: thin dotted;}a:active, a:hover {outline: 0;}img {border: 0;-ms-interpolation-mode: bicubic;}figure {margin: 0;}form {margin: 0;}fieldset {border: 1px solid #c0c0c0;margin: 0 2px;padding: 0.35em 0.625em 0.75em;}legend {border: 0;padding: 0;white-space: normal;*margin-left: -7px;}button, input, select, textarea {font-size: 100%;margin: 0;vertical-align: baseline;*vertical-align: middle;}button, input {line-height: normal;}button, select {text-transform: none;}button, html input[type="button"], input[type="reset"], input[type="submit"] {-webkit-appearance: button;cursor: pointer;*overflow: visible;}button[disabled], html input[disabled] {cursor: default;}input[type="checkbox"], input[type="radio"] {box-sizing: border-box;padding: 0;*height: 13px;*width: 13px;}input[type="search"] {-webkit-appearance: textfield;-moz-box-sizing: content-box;-webkit-box-sizing: content-box;box-sizing: content-box;}input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {-webkit-appearance: none;}button::-moz-focus-inner, input::-moz-focus-inner {border: 0;padding: 0;}textarea {overflow: auto;vertical-align: top;}table {border-collapse: collapse;border-spacing: 0;}html, button, input, select, textarea {color: #222;}::-moz-selection {background: #b3d4fc;text-shadow: none;}::selection {background: #b3d4fc;text-shadow: none;}img {vertical-align: middle;}fieldset {border: 0;margin: 0;padding: 0;}textarea {resize: vertical;}.chromeframe {margin: 0.2em 0;background: #ccc;color: #000;padding: 0.2em 0;}