Move home page into svelte and remove some old junk

This commit is contained in:
2022-02-21 23:25:44 +01:00
parent e4e061869e
commit 692c96eb63
27 changed files with 1497 additions and 2564 deletions

View File

@@ -1,99 +0,0 @@
let modal_global_index = 100
// Modal creates a new modal window and shows it. The width and height are will
// be adjusted to the screen size. Content should be added to the `body`
// property
function Modal(parent, closeCallback, title, width, height) {
this.parent = parent
this.closeCallback = closeCallback
this.title = title
this.width = width
this.height = height
this.visible = false
this.background = document.createElement("div")
this.background.classList = "modal_background"
this.background.addEventListener("click", e => { this.close() })
this.window = document.createElement("div")
this.window.classList = "modal_window"
this.window.style.width = this.width
this.window.style.height = this.height
this.window.addEventListener("click", e => { e.stopPropagation() })
this.header = document.createElement("div")
this.header.classList = "modal_header"
this.titleDiv = document.createElement("div")
this.titleDiv.classList = "modal_title"
this.titleDiv.innerText = this.title
this.btnClose = document.createElement("button")
this.btnClose.classList = "modal_btn_close button_red round"
this.btnClose.innerHTML = '<i class="icon">close</i>'
this.btnClose.addEventListener("click", e => { this.close() })
this.body = document.createElement("div")
this.body.classList = "modal_body"
// And add all the elements to eachother.
this.header.append(this.titleDiv)
this.header.append(this.btnClose)
this.window.append(this.header)
this.window.append(this.body)
this.background.append(this.window)
}
Modal.prototype.setTitle = function (title) {
this.title = title
this.titleDiv.innerText = title
}
Modal.prototype.setBody = function (element) {
this.body.innerHTML = ""
this.body.append(element)
}
Modal.prototype.cloneTemplate = function (templateID) {
this.setBody(document.getElementById(templateID).content.cloneNode(true))
}
Modal.prototype.open = function () {
if (this.visible) { return }
this.visible = true
console.debug("Showing modal " + this.title)
// Each time a modal is shown it gets a z-index which is one higher of the
// previous one. This makes sure they are always shown and closed in order
this.background.style.zIndex = modal_global_index
modal_global_index++
this.parent.prepend(this.background)
// If an element is created and shown in the same frame it won't render the
// transition. So here we wait for a few frames to make it visible
this.background.style.display = ""
setTimeout(() => { this.background.style.opacity = 1 }, 40)
// This is a workaround for a chrome bug which makes it so hidden
// windows can't be scrolled after they are shown
this.body.focus()
}
Modal.prototype.close = function () {
if (!this.visible) { return }
this.visible = false
if (this.closeCallback) {
this.closeCallback()
}
// First we make it invisible with a transition. When we remove it so the
// user can click through it
this.background.style.opacity = 0
// Wait for the animation to finish and remove the window
setTimeout(() => { this.parent.removeChild(this.background) }, 400)
}

View File

@@ -1,166 +0,0 @@
function UploadManager(uploadEndpoint, uploadsFinished) {
this.uploadEndpoint = uploadEndpoint;
// Callback function for when the queue is empty
this.uploadsFinished = uploadsFinished;
// Counts the total number of upload jobs
this.jobCounter = 0;
// Queue of files to be uploaded. Format:
// {
// jobID: number,
// file: Blob,
// name: string,
// onProgress: function,
// onFinished: function,
// onFailure: function,
// tries: number
// }
this.uploadQueue = [];
// Here we put successful jobs. The array should be sorted by job ID.
// Format:
// { jobID: number, fileID: string, fileName: string }
this.uploadLog = [];
// Max number of uploading threads at once
this.maxWorkers = 3;
// Threads which are currently uploading
this.activeWorkers = 0;
// Total number of jobs accepted
this.jobCounter = 0;
}
UploadManager.prototype.finishedUploads = function () {
this.uploadLog.sort((a, b) => {
return a.jobID - b.jobID;
})
return this.uploadLog;
}
UploadManager.prototype.addFile = function (
file, // Blob
name, // string
onProgress, // func (progress: number)
onFinished, // func (id: string)
onFailure // func (errorID: string, errorMessage: string)
) {
this.uploadQueue.push({
jobID: this.jobCounter,
file: file,
name: name,
onProgress: onProgress,
onFinished: onFinished,
onFailure: onFailure,
tries: 0
});
// Increment the job counter
this.jobCounter++
if (this.activeWorkers < this.maxWorkers) {
// Run the upload function
this.startUpload();
}
}
UploadManager.prototype.startUpload = function () {
if (this.uploadQueue.length === 0) {
return; // Nothing to upload
}
if (this.activeWorkers < this.maxWorkers) {
this.activeWorkers++;
this.uploadThread();
}
}
UploadManager.prototype.finishUpload = function () {
this.activeWorkers--;
if (
this.uploadQueue.length === 0 &&
this.activeWorkers === 0 &&
typeof (this.uploadsFinished) === "function"
) {
this.uploadsFinished();
return;
}
// Run the upload function for the next file
this.startUpload();
}
UploadManager.prototype.uploadThread = function () {
let job = this.uploadQueue.shift(); // Get the first element of the array
console.debug("Starting upload of " + job.name);
let form = new FormData();
form.append('file', job.file, job.name);
let xhr = new XMLHttpRequest();
xhr.open("POST", this.uploadEndpoint, true);
xhr.timeout = 21600000; // 6 hours, to account for slow connections
// Report progress updates back to the caller
xhr.upload.addEventListener("progress", evt => {
if (evt.lengthComputable && typeof (job.onProgress) === "function") {
job.onProgress(evt.loaded / evt.total);
}
});
xhr.onreadystatechange = () => {
// readystate 4 means the upload is done
if (xhr.readyState !== 4) { return; }
if (xhr.status >= 100 && xhr.status < 400) {
// Request is a success
let resp = JSON.parse(xhr.response);
addUploadHistory(resp.id)
// Log the successful job
this.uploadLog.push({
jobID: job.jobID,
fileID: resp.id,
fileName: job.name
});
if (typeof (job.onFinished) === "function") {
job.onFinished(resp.id);
}
// Finish the upload job
this.finishUpload();
} else if (xhr.status >= 400) {
// Request failed
console.log("Upload error. status: " + xhr.status + " response: " + xhr.response);
let resp = JSON.parse(xhr.response);
if (resp.value == "file_too_large" || job.tries === 3) { // Upload failed
job.onFailure(resp.value, resp.message);
} else { // Try again
job.tries++;
this.uploadQueue.push(job);
}
// Sleep the upload thread for 5 seconds
window.setTimeout(() => { this.finishUpload(); }, 5000);
} else {
// Request did not arrive
if (job.tries === 3) { // Upload failed
if (typeof (job.onFailure) === "function") {
job.onFailure(xhr.responseText, xhr.responseText);
}
} else { // Try again
job.tries++;
this.uploadQueue.push(job);
}
// Sleep the upload thread for 5 seconds
window.setTimeout(() => { this.finishUpload(); }, 5000);
}
};
xhr.send(form);
}

View File

@@ -1,104 +0,0 @@
function addUploadHistory(fileID) {
// Make sure the user is not logged in, for privacy. This keeps the
// files uploaded while logged in and anonymously uploaded files
// separated
if (document.cookie.includes("pd_auth_key")) { return; }
let uploads = localStorage.getItem("uploaded_files");
if (uploads === null) { uploads = ""; }
// Check if there are not too many values stored
if (uploads.length > 3600) {
// 3600 characters is enough to store 400 file IDs. If we exceed that
// number we'll drop the last two items
uploads = uploads.substring(
uploads.indexOf(",") + 1
).substring(
uploads.indexOf(",") + 1
);
}
// Save the new ID
localStorage.setItem("uploaded_files", fileID + "," + uploads);
}
function printDate(date, hours, minutes, seconds) {
let dateStr = date.getFullYear()
+ "-" + ("00" + (date.getMonth() + 1)).slice(-2)
+ "-" + ("00" + date.getDate()).slice(-2)
if (hours) { dateStr += " " + ("00" + date.getHours()).slice(-2) }
if (minutes) { dateStr += ":" + ("00" + date.getMinutes()).slice(-2) }
if (seconds) { dateStr += ":" + ("00" + date.getMinutes()).slice(-2) }
return dateStr
}
function copyText(text) {
// Create a textarea to copy the text from
let ta = document.createElement("textarea");
ta.setAttribute("readonly", "readonly")
ta.style.position = "absolute";
ta.style.left = "-9999px";
ta.value = text; // Put the text in the textarea
// Add the textarea to the DOM so it can be seleted by the user
document.body.appendChild(ta);
ta.select() // Select the contents of the textarea
let success = document.execCommand("copy"); // Copy the selected text
document.body.removeChild(ta); // Remove the textarea
return success;
}
function domainURL() {
let url = window.location.protocol + "//" + window.location.hostname;
if (window.location.port != "") {
url = url + ":" + window.location.port;
}
return url;
}
function formatNumber(amt, precision) {
if (precision < 3) { precision = 3; }
if (amt >= 1e6) {
return (amt / 1e6).toPrecision(precision) + "M";
} else if (amt >= 1e3) {
return (amt / 1e3).toPrecision(precision) + "k";
}
return amt
}
function formatThousands(x) {
// Inject a space every three digits
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
}
function formatDataVolume(amt, precision) {
if (precision < 3) { precision = 3; }
if (amt >= 1e18) {
return (amt / 1e18).toPrecision(precision) + " EB";
} else if (amt >= 1e15) {
return (amt / 1e15).toPrecision(precision) + " PB";
} else if (amt >= 1e12) {
return (amt / 1e12).toPrecision(precision) + " TB";
} else if (amt >= 1e9) {
return (amt / 1e9).toPrecision(precision) + " GB";
} else if (amt >= 1e6) {
return (amt / 1e6).toPrecision(precision) + " MB";
} else if (amt >= 1e3) {
return (amt / 1e3).toPrecision(precision) + " kB";
}
return Math.floor(amt) + " B"
}
const second = 1000
const minute = second * 60
const hour = minute * 60
const day = hour * 24
function formatDuration(ms) {
let res = ""
if (ms >= day) { res += Math.floor(ms / day) + "d " }
if (ms >= hour) { res += Math.floor((ms % day) / hour) + "h " }
if (ms >= minute) { res += Math.floor((ms % hour) / minute) + "m " }
return res + ((ms % minute) / second).toFixed(3) + "s"
}

View File

@@ -1,16 +1,16 @@
function renderFileButton(apiURL, id, title, subtitle) {
let btn = document.createElement("a")
btn.classList = "file_button"
btn.href = "/u/"+id
btn.target = "_blank"
let thumbnail = document.createElement("img")
thumbnail.src = apiURL+"/file/"+id+"/thumbnail?width=80&height=80"
thumbnail.alt = title
let titleSpan = document.createElement("span")
titleSpan.classList = "file_button_title"
titleSpan.innerText = title
let br = document.createElement("br")
let subtitleSpan = document.createElement("span")
let btn = document.createElement("a")
btn.classList = "file_button"
btn.href = "/u/" + id
btn.target = "_blank"
let thumbnail = document.createElement("img")
thumbnail.src = apiURL + "/file/" + id + "/thumbnail?width=80&height=80"
thumbnail.alt = title
let titleSpan = document.createElement("span")
titleSpan.classList = "file_button_title"
titleSpan.innerText = title
let br = document.createElement("br")
let subtitleSpan = document.createElement("span")
subtitleSpan.classList = "file_button_subtitle"
subtitleSpan.innerText = subtitle
@@ -26,6 +26,17 @@ function getCookie(name) {
return result ? result[1] : null
}
function printDate(date, hours, minutes, seconds) {
let dateStr = date.getFullYear()
+ "-" + ("00" + (date.getMonth() + 1)).slice(-2)
+ "-" + ("00" + date.getDate()).slice(-2)
if (hours) { dateStr += " " + ("00" + date.getHours()).slice(-2) }
if (minutes) { dateStr += ":" + ("00" + date.getMinutes()).slice(-2) }
if (seconds) { dateStr += ":" + ("00" + date.getMinutes()).slice(-2) }
return dateStr
}
// Get the uploads from localstorage
let uploadsStr = localStorage.getItem("uploaded_files")
if (uploadsStr === null) { uploadsStr = "" }
@@ -51,7 +62,7 @@ function getHistoryItem() {
if (item === undefined || item === "") { return }
fetch(
apiEndpoint+"/file/"+item+"/info"
apiEndpoint + "/file/" + item + "/info"
).then(resp => {
if (!resp.ok) {
return Promise.reject()
@@ -68,7 +79,7 @@ function getHistoryItem() {
)
getHistoryItem()
}).catch(err => {
console.log("Fetch failed: "+err)
console.log("Fetch failed: " + err)
getHistoryItem()
})
}

View File

@@ -1,64 +0,0 @@
.modal_background {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.7);
opacity: 0;
transition: opacity .4s;
}
.modal_window {
position: absolute;
z-index: inherit;
display: flex;
flex-direction: column;
background-color: var(--layer_2_color);
max-height: 100%;
max-width: 100%;
top: 20%;
left: 50%;
transform: translate(-50%, -20%);
padding: 0;
text-align: left;
/* box-shadow: var(--shadow_color) 0px 0px 50px; */
border-radius: 20px 20px 8px 8px;
overflow: hidden;
}
.modal_header {
flex-grow: 0;
flex-shrink: 0;
display: flex;
flex-direction: row;
background: var(--layer_1_color);
color: var(--layer_1_text_color);
padding: 1px;
}
.modal_title {
flex-grow: 1;
flex-shrink: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
font-size: 1.2em;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.modal_btn_close {
flex-grow: 0;
flex-shrink: 0;
}
.modal_body {
flex-grow: 1;
flex-shrink: 1;
overflow: auto;
padding: 10px;
}