<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>quad.pe</title>
</head>
<style>
html {
min-height: 100%;
}
body {
height: 100%;
margin: 0;
overflow-y: hidden;
}
#form {
position: absolute;
display: block;
width: 100%;
height: 100%;
transition: height 1s;
}
#realos {
position: absolute;
left: -99999px;
}
#form:before {
content: "Drag & drop, click, or paste";
display: block;
position: absolute;
line-height: 1;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#form.uploading:before {
content: "Uploading...";
}
#form.dragover {
box-shadow: inset 0 0 10px 0 rgba(0, 0, 0, 0.75);
}
#form.dragover:before {
content: "Now drop";
}
ul#images {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
box-sizing: border-box;
border-top: 1px solid #ddd;
height: 200px;
transform: translateY(100%);
margin: 0;
padding: 10px;
overflow-y: hidden;
overflow-x: scroll;
white-space: nowrap;
transition: transform 1s;
}
ul#images li {
height: 100%;
display: inline-block;
max-width: 150px;
width: 100%;
margin-left: 10px;
list-style: none;
position: relative;
background: #f5f5f5;
}
ul#images li:first-child {
margin-left: 0;
}
ul#images li a {
display: block;
transform: translateY(-100%);
transition: transform 1s ease-in-out;
position: relative;
height: 100%;
width: 100%;
}
ul#images li a img {
max-height: 100%;
max-width: 100%;
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1;
}
ul#images li:after {
position: absolute;
content: "Uploading";
font-size: 12px;
display: block;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
opacity: 0;
transition: all 0.5s;
}
ul#images li.loading:after {
color: #aaa;
opacity: 1;
transition: all 0.5s;
}
ul#images li.loaded a {
transform: translateY(0);
}
ul#images li.failed:after {
content: "Failed to upload";
color: red;
opacity: 1;
}
ul#images li button {
position: absolute;
top: 0;
right: 0;
display: none;
border: 1px solid #f5f5f5;
font-family: inherit;
background: #fff;
font-size: 12px;
line-height: 1;
padding: 5px;
z-index: 2;
}
ul#images li button + button {
top: 0;
left: 0;
}
ul#images li button:hover {
background: #ddd;
}
ul#images li button + button:hover {
background: #d77;
}
ul#images li input {
position: absolute;
left: -99999px;
}
ul#images li.failed button {
display: inline-block;
}
ul#images li.failed button:after {
content: "!";
}
ul#images li.loaded:hover button {
display: inline-block;
}
body.active-upload #form {
height: calc(100% - 200px);
}
body.active-upload #images {
transform: translateY(0);
}
#errors {
position: fixed;
top: 1em;
left: 1em;
border: 2px dashed red;
background-color: red;
font-family: sans-serif;
font-weight: bold;
padding: 0.2em;
color: white;
}
#tcs {
position: fixed;
top: 1em;
right: 1em;
font-family: sans-serif;
color: black;
text-align: center;
font-size: 50%;
}
</style>
<body>
<label for="realos" id="form"></label>
<input type="file" multiple id="realos">
<ul id="images"></ul>
<div id="errors">
Waiting for Javascript to initialise...
</div>
<div id="tcs">
<p><a href="/terms/">T&Cs</a></p>
</div>
<script>
var storage = localStorage.getItem("quadpees");
var quadpees = [];
if (storage) {
quadpees = JSON.parse(storage);
setBodyActive();
quadpees.forEach(function (pee) {
makeLoadedItem(makePlaceholderItem(), pee);
})
} else {
localStorage.setItem("quadpees", "[]");
}
function upload(fileBlob, cb) {
var quadPeer = new XMLHttpRequest();
var fd = new FormData();
fd.append('image', fileBlob);
fd.append('return_json', 'true');
quadPeer.open("POST", "/api/upload");
quadPeer.onreadystatechange = function () {
if (quadPeer.readyState === 4) {
if (quadPeer.status === 200) {
var resp = JSON.parse(quadPeer.responseText);
var url = resp.data.id;
quadpees.push(url);
localStorage.setItem("quadpees", JSON.stringify(quadpees));
cb(null, url);
} else {
cb(quadPeer.responseText || "Error.");
}
}
};
quadPeer.send(fd);
}
function makePlaceholderItem(isLoading) {
var li = document.createElement("li");
images.insertBefore(li, images.firstChild);
if (isLoading) {
li.classList.add("loading");
}
var actionButton = document.createElement("button");
li.appendChild(actionButton);
var binButton = document.createElement("button");
li.appendChild(binButton);
return {
li: li,
actionButton: actionButton,
binButton: binButton
};
}
function makeLoadedItem(loadingItem, url) {
var a = document.createElement("a");
var img = document.createElement("img");
a.href = url;
a.target = "_blank";
var copyInput = document.createElement("input");
copyInput.value = a.href;
loadingItem.actionButton.innerHTML = t = "copy";
loadingItem.actionButton.onclick = function (e) {
e.preventDefault();
copyInput.select();
document.execCommand("Copy");
this.innerHTML = "copied";
};
loadingItem.actionButton.onmouseleave = function () {
this.innerHTML = t;
};
loadingItem.binButton.innerHTML = "🗑➡️";
loadingItem.binButton.onclick = function (e) {
e.preventDefault();
var removing = false;
Array.prototype.slice.call(images.childNodes).forEach(function (i) {
if (url === i.dataset.miniUrl) {
removing = true;
}
if (removing) {
images.removeChild(i);
var idx = quadpees.indexOf(i.dataset.miniUrl);
if (idx >= 0) {
quadpees.splice(idx, 1);
}
}
});
localStorage.setItem("quadpees", JSON.stringify(quadpees));
};
a.appendChild(img);
loadingItem.li.appendChild(a);
loadingItem.li.appendChild(copyInput);
loadingItem.li.dataset.miniUrl = url;
img.onload = function () {
loadingItem.li.classList.remove("loading");
loadingItem.li.classList.add("loaded");
};
img.src = a.href;
}
function process(file) {
setBodyActive();
var reader = new FileReader();
reader.onload = function (e) {
var blob = new Blob([e.target.result], {type: "image/jpeg"});
var loadingItem = makePlaceholderItem(true);
upload(blob, function (err, resp) {
if (err) {
loadingItem.actionButton.onclick = function () {
alert(err);
};
loadingItem.li.classList.add("failed");
loadingItem.li.classList.remove("loading");
return;
}
makeLoadedItem(loadingItem, resp);
});
};
reader.readAsArrayBuffer(file);
}
function setBodyActive() {
document.body.classList.add("active-upload");
}
function onFiles(items, context) {
var keys = Object.keys(items);
if (0 === keys.length) {
error("No files, valid or not, were found in your " + context
+ ". Maybe it wasn't a valid image, or your browser is confused about what it was?");
}
for (var f in keys) {
var item = items[f];
console.log(item);
if (item.type.match(/image.*/)) {
process(item);
} else {
error("Ignoring non-image item (of type '" + item.type + "') in " + context + ": " + item.name);
}
}
form.classList.remove("dragover");
}
function error(msg) {
var errors = document.getElementById('errors');
errors.style.display = 'block';
var span = document.createElement('p');
span.innerHTML = msg;
errors.insertBefore(span, errors.firstChild);
}
realos.onchange = function () {
onFiles(this.files, "picked files");
};
document.documentElement.onpaste = function (e) {
e.preventDefault();
onFiles(e.clipboardData.files, "pasted content");
};
document.documentElement.ondrop = function (e) {
e.preventDefault();
form.classList.remove("dragover");
onFiles(e.dataTransfer.files, "dropped objects");
};
document.documentElement.ondragenter = function (e) {
e.dataTransfer.dropEffect = "copy";
e.preventDefault();
};
document.documentElement.ondragover = function (e) {
e.preventDefault();
e.dataTransfer.dropEffect = "copy";
form.classList.add("dragover");
};
document.documentElement.ondragexit = document.documentElement.ondragleave = function (e) {
form.classList.remove("dragover");
};
var errors = document.getElementById("errors");
errors.style.display = 'none';
errors.innerHTML = '';
</script>
</body>
</html>