1
0
Fork 0
mirror of https://codeberg.org/icewind/shelve.git synced 2026-06-03 12:04:09 +02:00
shelve/templates/index.html
2021-07-30 22:27:14 +02:00

441 lines
No EOL
13 KiB
HTML

<html>
<head>
<meta name="viewport" content="width=device-width" />
<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);
}
}
.box__restart {
font-weight: 700;
}
.box__restart:focus,
.box__restart:hover {
color: #39bfd3;
}
.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'),
restart = form.querySelectorAll('.box__restart'),
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;
});
// restart the form if has a state of error/success
Array.prototype.forEach.call(restart, function (entry) {
entry.addEventListener('click', function (e) {
e.preventDefault();
form.classList.remove('is-error', 'is-success');
input.click();
});
});
// 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>