Files
localsend/packages/core/assets/web/upload.html
T

261 lines
6.8 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LocalSend</title>
<style>
body {
font-family: sans-serif, system-ui;
margin: 0;
line-height: 1.5;
text-align: center;
}
#content {
box-sizing: border-box;
width: 100%;
max-width: 400px;
margin: 15vh auto 0;
padding: 0 1em;
}
#upload-button {
width: 100%;
padding: 1em;
font-family: inherit;
font-size: 1.5em;
color: #FFFFFF;
background-color: #00796B;
border: none;
border-radius: 0.5em;
cursor: pointer;
}
#upload-button:hover {
background-color: #009688;
}
#status-text {
display: none;
font-size: 1.5em;
}
#status-text.error {
color: #C62828;
}
#progress-text {
display: none;
font-size: 1.5em;
}
</style>
</head>
<body>
<noscript>
LocalSend requires JavaScript, which is currently disabled. Please enable it and try again.
</noscript>
<h1 style="padding: 0.5em">LocalSend</h1>
<div id="content">
<button id="upload-button" type="button">Upload</button>
<input id="file-input" type="file" multiple style="display: none">
<p id="status-text"></p>
<p id="progress-text"></p>
</div>
<script>
var BASE_URL = '/api/localsend/v2';
var i18n = {};
function makeRequest(url, method, body, callback) {
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
callback(xhr);
}
};
xhr.send(body);
}
function fetchI18n(then) {
makeRequest('/i18n.json', 'GET', null, function (response) {
if (response.status === 200) {
i18n = JSON.parse(response.responseText);
then();
}
});
}
function setButtonVisible(visible) {
document.getElementById('upload-button').style.display = visible ? 'block' : 'none';
}
function showStatus(text, isError) {
var statusText = document.getElementById('status-text');
statusText.style.display = text ? 'block' : 'none';
statusText.className = isError ? 'error' : '';
statusText.innerText = text;
}
function showProgress(finished, total) {
var progressText = document.getElementById('progress-text');
progressText.style.display = 'block';
progressText.innerText = finished + '/' + total + ' file(s)';
}
function hideProgress() {
document.getElementById('progress-text').style.display = 'none';
}
// Ends the upload flow: keeps the error visible and lets the user try again.
function finishWithError(text) {
showStatus(text, true);
setButtonVisible(true);
}
// Ends the upload flow after all files have been sent.
function finishWithSuccess() {
showStatus('');
setButtonVisible(true);
}
function startUpload(fileList) {
setButtonVisible(false);
hideProgress();
showStatus(i18n.waiting);
var selectedFiles = {};
var filesDto = {};
for (var i = 0; i < fileList.length; i++) {
var file = fileList[i];
var fileId = String(i);
selectedFiles[fileId] = file;
filesDto[fileId] = {
id: fileId,
fileName: file.name,
size: file.size,
fileType: file.type || 'application/octet-stream'
};
}
var body = JSON.stringify({
info: {
alias: 'Web Browser',
version: '2.1',
deviceType: 'web',
fingerprint: getFingerprint(),
port: 0,
protocol: location.protocol === 'https:' ? 'https' : 'http',
download: false
},
files: filesDto
});
makeRequest(BASE_URL + '/prepare-upload', 'POST', body, function (response) {
if (response.status === 403) {
finishWithError(i18n.uploadRejected);
return;
}
if (response.status === 409) {
finishWithError(i18n.busy);
return;
}
if (response.status === 204) {
// The recipient accepted the request but declined every file.
finishWithError(i18n.uploadRejected);
return;
}
if (response.status !== 200) {
finishWithError(errorText(response.status));
return;
}
var data = JSON.parse(response.responseText);
uploadFiles(data.sessionId, data.files, selectedFiles);
});
}
function uploadFiles(sessionId, tokens, selectedFiles) {
var fileIds = getKeys(tokens);
var total = fileIds.length;
showStatus('');
showProgress(0, total);
function uploadNext(index) {
if (index >= total) {
finishWithSuccess();
return;
}
var fileId = fileIds[index];
var url = BASE_URL + '/upload' +
'?sessionId=' + encodeURIComponent(sessionId) +
'&fileId=' + encodeURIComponent(fileId) +
'&token=' + encodeURIComponent(tokens[fileId]);
makeRequest(url, 'POST', selectedFiles[fileId], function (response) {
if (response.status !== 200) {
finishWithError(errorText(response.status));
return;
}
showProgress(index + 1, total);
uploadNext(index + 1);
});
}
uploadNext(0);
}
function getFingerprint() {
var fingerprint = sessionStorage.getItem('fingerprint');
if (!fingerprint) {
fingerprint = 'web-';
for (var i = 0; i < 32; i++) {
fingerprint += Math.floor(Math.random() * 16).toString(16);
}
sessionStorage.setItem('fingerprint', fingerprint);
}
return fingerprint;
}
// A status of 0 means the request never completed (connection lost or aborted by the recipient).
function errorText(status) {
return status ? 'Error: ' + status : 'Error';
}
function getKeys(obj) {
var keys = [];
for (var key in obj) {
keys.push(key);
}
return keys;
}
function init() {
var fileInput = document.getElementById('file-input');
document.getElementById('upload-button').onclick = function () {
fileInput.click();
};
fileInput.onchange = function () {
if (fileInput.files.length > 0) {
startUpload(fileInput.files);
// Reset the input so selecting the same files again fires this event.
fileInput.value = '';
}
};
fetchI18n(function () {});
}
init();
</script>
</body>
</html>