mirror of
https://codeberg.org/icewind/shelve.git
synced 2026-06-03 12:04:09 +02:00
422 lines
No EOL
13 KiB
HTML
422 lines
No EOL
13 KiB
HTML
<html>
|
|
<head>
|
|
<meta name="viewport" content="width=device-width" />
|
|
<link rel="shortcut icon" href="icon.svg" />
|
|
<title>Shelve</title>
|
|
<style>
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html, body {
|
|
height: 100%;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
body {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
align-content: stretch;
|
|
flex-direction: column;
|
|
font-family: Roboto, sans-serif;
|
|
color: #0f3c4b;
|
|
background-color: #e5edf1;
|
|
}
|
|
|
|
#uploads {
|
|
display: block;
|
|
max-width: 100%;
|
|
width: 400px;
|
|
font-size: 1.2rem;
|
|
overflow: hidden;
|
|
margin-left: -40px;
|
|
}
|
|
|
|
#uploads a {
|
|
text-overflow: ellipsis;
|
|
width: 400px;
|
|
}
|
|
|
|
p {
|
|
display: flex;
|
|
justify-content: stretch;
|
|
align-items: center;
|
|
}
|
|
|
|
p input, p select {
|
|
flex-grow: 1;
|
|
}
|
|
|
|
label[for="token"], label[for="expire"] {
|
|
display: inline-block;
|
|
width: 60px;
|
|
}
|
|
|
|
.dropbox {
|
|
width: 100%;
|
|
font-size: 1.25rem; /* 20 */
|
|
position: relative;
|
|
padding: 100px 20px;
|
|
background-color: white;
|
|
cursor: pointer;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
text-align: center;
|
|
}
|
|
|
|
.dropbox.has-advanced-upload {
|
|
outline: 2px dashed #92b0b3;
|
|
outline-offset: -10px;
|
|
transition: outline-offset .15s ease-in-out, background-color .15s linear;
|
|
}
|
|
|
|
.dropbox.is-dragover {
|
|
outline-offset: -20px;
|
|
outline-color: #c8dadf;
|
|
background-color: #fff;
|
|
}
|
|
|
|
.box__dragndrop,
|
|
.box__icon {
|
|
display: none;
|
|
}
|
|
|
|
.dropbox.has-advanced-upload .box__dragndrop {
|
|
display: inline;
|
|
}
|
|
|
|
.dropbox.has-advanced-upload .box__icon {
|
|
width: 100%;
|
|
height: 80px;
|
|
fill: #92b0b3;
|
|
display: block;
|
|
margin-bottom: 40px;
|
|
}
|
|
|
|
.box__input {
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.dropbox.is-uploading .box__input,
|
|
.dropbox.is-success .box__input,
|
|
.dropbox.is-error .box__input {
|
|
visibility: hidden;
|
|
}
|
|
|
|
.box__uploading,
|
|
.box__success,
|
|
.box__error {
|
|
display: none;
|
|
}
|
|
|
|
.dropbox.is-uploading .box__uploading,
|
|
.dropbox.is-success .box__success,
|
|
.dropbox.is-error .box__error {
|
|
display: block;
|
|
position: absolute;
|
|
top: 50%;
|
|
right: 0;
|
|
left: 0;
|
|
}
|
|
|
|
.box__uploading {
|
|
font-style: italic;
|
|
}
|
|
|
|
.box__success {
|
|
-webkit-animation: appear-from-inside .25s ease-in-out;
|
|
animation: appear-from-inside .25s ease-in-out;
|
|
}
|
|
|
|
@-webkit-keyframes appear-from-inside {
|
|
from {
|
|
-webkit-transform: translateY(-50%) scale(0);
|
|
}
|
|
75% {
|
|
-webkit-transform: translateY(-50%) scale(1.1);
|
|
}
|
|
to {
|
|
-webkit-transform: translateY(-50%) scale(1);
|
|
}
|
|
}
|
|
|
|
@keyframes appear-from-inside {
|
|
from {
|
|
transform: translateY(-50%) scale(0);
|
|
}
|
|
75% {
|
|
transform: translateY(-50%) scale(1.1);
|
|
}
|
|
to {
|
|
transform: translateY(-50%) scale(1);
|
|
}
|
|
}
|
|
|
|
.js .box__file {
|
|
width: 0.1px;
|
|
height: 0.1px;
|
|
opacity: 0;
|
|
overflow: hidden;
|
|
position: absolute;
|
|
z-index: -1;
|
|
}
|
|
|
|
.js .box__file + label {
|
|
max-width: 80%;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
cursor: pointer;
|
|
display: inline-block;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.js .box__file + label:hover strong,
|
|
.box__file:focus + label strong,
|
|
.box__file.has-focus + label strong {
|
|
color: #39bfd3;
|
|
}
|
|
|
|
.js .box__file:focus + label,
|
|
.js .box__file.has-focus + label {
|
|
outline: 1px dotted #000;
|
|
outline: -webkit-focus-ring-color auto 5px;
|
|
}
|
|
|
|
.js .box__file + label * {
|
|
/* pointer-events: none; */ /* in case of FastClick lib use */
|
|
}
|
|
|
|
.no-js .box__file + label {
|
|
display: none;
|
|
}
|
|
|
|
.no-js .box__button {
|
|
display: block;
|
|
}
|
|
|
|
.box__button {
|
|
font-weight: 700;
|
|
color: #e5edf1;
|
|
background-color: #39bfd3;
|
|
display: none;
|
|
padding: 8px 16px;
|
|
margin: 40px auto 0;
|
|
}
|
|
|
|
.box__button:hover,
|
|
.box__button:focus {
|
|
background-color: #0f3c4b;
|
|
}
|
|
|
|
#box {
|
|
max-width: 100%;
|
|
width: 400px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="no-js">
|
|
<form method="post" id="box" action="upload" enctype="multipart/form-data" class="box">
|
|
<p>
|
|
<label for="token">Token</label>
|
|
<input id="token" type="text" name="token"/>
|
|
</p>
|
|
<div class="dropbox">
|
|
<div class="box__input">
|
|
<svg class="box__icon" xmlns="http://www.w3.org/2000/svg" width="50" height="43" viewBox="0 0 50 43">
|
|
<path d="M48.4 26.5c-.9 0-1.7.7-1.7 1.7v11.6h-43.3v-11.6c0-.9-.7-1.7-1.7-1.7s-1.7.7-1.7 1.7v13.2c0 .9.7 1.7 1.7 1.7h46.7c.9 0 1.7-.7 1.7-1.7v-13.2c0-1-.7-1.7-1.7-1.7zm-24.5 6.1c.3.3.8.5 1.2.5.4 0 .9-.2 1.2-.5l10-11.6c.7-.7.7-1.7 0-2.4s-1.7-.7-2.4 0l-7.1 8.3v-25.3c0-.9-.7-1.7-1.7-1.7s-1.7.7-1.7 1.7v25.3l-7.1-8.3c-.7-.7-1.7-.7-2.4 0s-.7 1.7 0 2.4l10 11.6z"/>
|
|
</svg>
|
|
<input type="file" name="files[]" id="file" class="box__file" data-multiple-caption="{count} files selected"
|
|
multiple/>
|
|
<label for="file" class="file_label"><strong>Choose a file</strong><span
|
|
class="box__dragndrop"> or drag it here</span>.</label>
|
|
<button type="submit" class="box__button">Upload</button>
|
|
</div>
|
|
<div class="box__uploading">
|
|
<Uploading>…</Uploading>
|
|
</div>
|
|
<div class="box__success">Done!</div>
|
|
<div class="box__error">Error! <span></span>.</div>
|
|
</div>
|
|
<p>
|
|
<label for="expire">Expire</label>
|
|
<select id="expire" name="expire">
|
|
<option value="30758400000">Never</option>
|
|
<option value="259200">3 Days</option>
|
|
<option value="86400">24 hours</option>
|
|
<option value="10800">3 hours</option>
|
|
<option value="300">5 minutes</option>
|
|
</select>
|
|
</p>
|
|
</form>
|
|
<ul id="uploads"></ul>
|
|
<script defer>
|
|
'use strict';
|
|
document.body.classList.remove('no-js');
|
|
document.body.classList.add('js');
|
|
|
|
// feature detection for drag&drop upload
|
|
var isAdvancedUpload = function () {
|
|
var div = document.createElement('div');
|
|
return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && 'FormData' in window && 'FileReader' in window;
|
|
}();
|
|
|
|
var form = document.getElementById('box');
|
|
var input = form.querySelector('input[type="file"]'),
|
|
label = form.querySelector('.file_label'),
|
|
tokenInput = document.getElementById('token'),
|
|
expireInput = document.getElementById('expire'),
|
|
box = form.querySelector('.dropbox'),
|
|
errorMsg = form.querySelector('.box__error span'),
|
|
uploads = document.getElementById('uploads'),
|
|
droppedFiles = false,
|
|
showFiles = function (files) {
|
|
label.textContent = files.length > 1 ? (input.getAttribute('data-multiple-caption') || '').replace('{count}', files.length) : files[0].name;
|
|
},
|
|
triggerFormSubmit = function () {
|
|
var event = document.createEvent('HTMLEvents');
|
|
event.initEvent('submit', true, true);
|
|
form.dispatchEvent(event);
|
|
};
|
|
|
|
// letting the server side to know we are going to make an Ajax request
|
|
var ajaxFlag = document.createElement('input');
|
|
ajaxFlag.setAttribute('type', 'hidden');
|
|
ajaxFlag.setAttribute('name', 'ajax');
|
|
ajaxFlag.setAttribute('value', 'true');
|
|
form.appendChild(ajaxFlag);
|
|
|
|
box.addEventListener('click', function () {
|
|
input.click();
|
|
});
|
|
|
|
tokenInput.addEventListener('change', function (e) {
|
|
localStorage.setItem('token', e.target.value);
|
|
});
|
|
let token = localStorage.getItem('token');
|
|
if (token) {
|
|
tokenInput.value = token;
|
|
}
|
|
|
|
expireInput.addEventListener('change', function (e) {
|
|
localStorage.setItem('expire', e.target.value);
|
|
});
|
|
let expire = localStorage.getItem('expire');
|
|
if (expire) {
|
|
expireInput.value = expire;
|
|
}
|
|
|
|
function resetForm() {
|
|
form.reset();
|
|
let token = localStorage.getItem('token');
|
|
if (token) {
|
|
tokenInput.value = token;
|
|
}
|
|
let expire = localStorage.getItem('expire');
|
|
if (expire) {
|
|
expireInput.value = expire;
|
|
}
|
|
}
|
|
|
|
// automatically submit the form on file select
|
|
input.addEventListener('change', function (e) {
|
|
showFiles(e.target.files);
|
|
triggerFormSubmit();
|
|
});
|
|
|
|
// drag&drop files if the feature is available
|
|
if (isAdvancedUpload) {
|
|
box.classList.add('has-advanced-upload'); // letting the CSS part to know drag&drop is supported by the browser
|
|
|
|
['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'].forEach(function (event) {
|
|
box.addEventListener(event, function (e) {
|
|
// preventing the unwanted behaviours
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
});
|
|
});
|
|
['dragover', 'dragenter'].forEach(function (event) {
|
|
box.addEventListener(event, function () {
|
|
box.classList.add('is-dragover');
|
|
});
|
|
});
|
|
['dragleave', 'dragend', 'drop'].forEach(function (event) {
|
|
box.addEventListener(event, function () {
|
|
box.classList.remove('is-dragover');
|
|
});
|
|
});
|
|
box.addEventListener('drop', function (e) {
|
|
droppedFiles = e.dataTransfer.files; // the files that were dropped
|
|
showFiles(droppedFiles);
|
|
|
|
triggerFormSubmit();
|
|
});
|
|
}
|
|
|
|
// if the form was submitted
|
|
form.addEventListener('submit', function (e) {
|
|
e.preventDefault();
|
|
// preventing the duplicate submissions if the current one is in progress
|
|
if (form.classList.contains('is-uploading')) {
|
|
return false;
|
|
}
|
|
|
|
box.classList.add('is-uploading');
|
|
box.classList.remove('is-error');
|
|
|
|
// gathering the form data
|
|
var ajaxData = new FormData(form);
|
|
if (droppedFiles) {
|
|
Array.prototype.forEach.call(droppedFiles, function (file) {
|
|
ajaxData.append(input.getAttribute('name'), file);
|
|
});
|
|
}
|
|
|
|
// ajax request
|
|
var ajax = new XMLHttpRequest();
|
|
ajax.open(form.getAttribute('method'), form.getAttribute('action'), true);
|
|
|
|
ajax.onload = function () {
|
|
resetForm();
|
|
|
|
box.classList.remove('is-uploading');
|
|
if (ajax.status >= 200 && ajax.status < 400) {
|
|
var data = JSON.parse(ajax.responseText);
|
|
box.classList.add(data.success == true ? 'is-success' : 'is-error');
|
|
if (!data.success) {
|
|
errorMsg.textContent = data.error;
|
|
} else {
|
|
for (let url of data.urls) {
|
|
let item = document.createElement('li');
|
|
let link = document.createElement('a');
|
|
link.setAttribute('href', url);
|
|
link.textContent = url.split('/')[1];
|
|
item.appendChild(link);
|
|
uploads.appendChild(item);
|
|
}
|
|
}
|
|
} else alert('Error. Please, contact the webmaster!');
|
|
};
|
|
|
|
ajax.onerror = function () {
|
|
box.classList.remove('is-uploading');
|
|
alert('Error. Please, try again!');
|
|
};
|
|
|
|
ajax.send(ajaxData);
|
|
|
|
return false;
|
|
});
|
|
|
|
// Firefox focus bug fix for file input
|
|
input.addEventListener('focus', function () {
|
|
input.classList.add('has-focus');
|
|
});
|
|
input.addEventListener('blur', function () {
|
|
input.classList.remove('has-focus');
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |