go from classes to prototypes
This commit is contained in:
3
res/include/img/icons/pixeldrain.svg
Normal file
3
res/include/img/icons/pixeldrain.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg enable-background="new 0 0 283.46 283.46" version="1.1" viewBox="0 0 283 283" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#{{.Style.InputTextColor.RGB}}" d="m142 2.23c-77 0-139 62.5-139 140 0 77 62.5 139 139 139 77 0 139-62.5 139-139 1e-3 -77-62.5-140-139-140zm0 258c-65.7 0-119-53.2-119-119s53.2-119 119-119c65.7 0 119 53.2 119 119 0 65.7-53.2 119-119 119zm0-219c-55.1 0-99.8 44.7-99.8 99.8 0 55.1 44.7 99.8 99.8 99.8s99.8-44.7 99.8-99.8c0-55.1-44.7-99.8-99.8-99.8zm49.3 36c8.69 0 15.7 7.04 15.7 15.7 0 8.69-7.04 15.7-15.7 15.7s-15.7-7.04-15.7-15.7c0-8.69 7.04-15.7 15.7-15.7zm-49.3-20c8.69 0 15.7 7.04 15.7 15.7 0 8.69-7.04 15.7-15.7 15.7s-15.7-7.04-15.7-15.7c0-8.69 7.04-15.7 15.7-15.7zm-48.7 20c8.69 0 15.7 7.04 15.7 15.7 0 8.69-7.04 15.7-15.7 15.7s-15.7-7.04-15.7-15.7c-1e-3 -8.69 7.04-15.7 15.7-15.7zm-35 63.8c0-8.69 7.04-15.7 15.7-15.7s15.7 7.04 15.7 15.7c0 8.69-7.04 15.7-15.7 15.7-8.69 0-15.7-7.04-15.7-15.7zm35 65.6c-8.69 0-15.7-7.04-15.7-15.7s7.04-15.7 15.7-15.7 15.7 7.04 15.7 15.7-7.04 15.7-15.7 15.7zm48.7 20.7c-8.69 0-15.7-7.04-15.7-15.7 0-8.69 7.04-15.7 15.7-15.7 8.69 0 15.7 7.04 15.7 15.7 1e-3 8.68-7.04 15.7-15.7 15.7zm2e-3 -47c-21.2 0-38.5-17.2-38.5-38.5 0-21.2 17.2-38.5 38.5-38.5 21.2 0 38.5 17.2 38.5 38.5 0 21.2-17.2 38.5-38.5 38.5zm49.3 26.3c-8.69 0-15.7-7.04-15.7-15.7s7.04-15.7 15.7-15.7 15.7 7.04 15.7 15.7-7.04 15.7-15.7 15.7zm18.6-49.9c-8.69 0-15.7-7.04-15.7-15.7 0-8.69 7.04-15.7 15.7-15.7s15.7 7.04 15.7 15.7c0 8.69-7.04 15.7-15.7 15.7z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1,170 +1,168 @@
|
||||
class UploadManager {
|
||||
constructor(apiAddress, uploadsFinished) {let um = this;
|
||||
function UploadManager(apiAddress, uploadsFinished) {let um = this;
|
||||
|
||||
um.apiAddress = apiAddress;
|
||||
um.apiAddress = apiAddress;
|
||||
|
||||
// Callback function for when the queue is empty
|
||||
um.uploadsFinished = uploadsFinished;
|
||||
// Callback function for when the queue is empty
|
||||
um.uploadsFinished = uploadsFinished;
|
||||
|
||||
// Counts the total number of upload jobs
|
||||
um.jobCounter = 0;
|
||||
// Counts the total number of upload jobs
|
||||
um.jobCounter = 0;
|
||||
|
||||
// Queue of files to be uploaded. Format:
|
||||
// {
|
||||
// jobID: number,
|
||||
// file: Blob,
|
||||
// name: string,
|
||||
// onProgress: function,
|
||||
// onFinished: function,
|
||||
// onFailure: function,
|
||||
// tries: number
|
||||
// }
|
||||
um.uploadQueue = [];
|
||||
// Queue of files to be uploaded. Format:
|
||||
// {
|
||||
// jobID: number,
|
||||
// file: Blob,
|
||||
// name: string,
|
||||
// onProgress: function,
|
||||
// onFinished: function,
|
||||
// onFailure: function,
|
||||
// tries: number
|
||||
// }
|
||||
um.uploadQueue = [];
|
||||
|
||||
// Here we put successful jobs. The array should be sorted by job ID.
|
||||
// Format:
|
||||
// { jobID: number, fileID: string, fileName: string }
|
||||
um.uploadLog = [];
|
||||
// Here we put successful jobs. The array should be sorted by job ID.
|
||||
// Format:
|
||||
// { jobID: number, fileID: string, fileName: string }
|
||||
um.uploadLog = [];
|
||||
|
||||
// Max number of uploading threads at once
|
||||
um.maxWorkers = 3;
|
||||
// Max number of uploading threads at once
|
||||
um.maxWorkers = 3;
|
||||
|
||||
// Threads which are currently uploading
|
||||
um.activeWorkers = 0;
|
||||
// Threads which are currently uploading
|
||||
um.activeWorkers = 0;
|
||||
|
||||
// Total number of jobs accepted
|
||||
um.jobCounter = 0;
|
||||
}
|
||||
// Total number of jobs accepted
|
||||
um.jobCounter = 0;
|
||||
}
|
||||
|
||||
finishedUploads() {let um = this;
|
||||
um.uploadLog.sort(function(a, b) {
|
||||
return a.jobID - b.jobID;
|
||||
})
|
||||
return um.uploadLog;
|
||||
}
|
||||
UploadManager.prototype.finishedUploads = function() {let um = this;
|
||||
um.uploadLog.sort(function(a, b) {
|
||||
return a.jobID - b.jobID;
|
||||
})
|
||||
return um.uploadLog;
|
||||
}
|
||||
|
||||
addFile(
|
||||
file, // Blob
|
||||
name, // string
|
||||
onProgress, // func (progress: number)
|
||||
onFinished, // func (id: string)
|
||||
onFailure // func (errorID: string, errorMessage: string)
|
||||
) {let um = this;
|
||||
um.uploadQueue.push({
|
||||
jobID: um.jobCounter,
|
||||
file: file,
|
||||
name: name,
|
||||
onProgress: onProgress,
|
||||
onFinished: onFinished,
|
||||
onFailure: onFailure,
|
||||
tries: 0
|
||||
});
|
||||
UploadManager.prototype.addFile = function(
|
||||
file, // Blob
|
||||
name, // string
|
||||
onProgress, // func (progress: number)
|
||||
onFinished, // func (id: string)
|
||||
onFailure // func (errorID: string, errorMessage: string)
|
||||
) {let um = this;
|
||||
um.uploadQueue.push({
|
||||
jobID: um.jobCounter,
|
||||
file: file,
|
||||
name: name,
|
||||
onProgress: onProgress,
|
||||
onFinished: onFinished,
|
||||
onFailure: onFailure,
|
||||
tries: 0
|
||||
});
|
||||
|
||||
// Increment the job counter
|
||||
um.jobCounter++
|
||||
// Increment the job counter
|
||||
um.jobCounter++
|
||||
|
||||
if (um.activeWorkers < um.maxWorkers) {
|
||||
// Run the upload function
|
||||
um.startUpload();
|
||||
}
|
||||
}
|
||||
|
||||
startUpload() {let um = this;
|
||||
if (um.uploadQueue.length === 0) {
|
||||
return; // Nothing to upload
|
||||
}
|
||||
|
||||
if (um.activeWorkers < um.maxWorkers) {
|
||||
um.activeWorkers++;
|
||||
um.uploadThread();
|
||||
}
|
||||
}
|
||||
|
||||
finishUpload() {let um = this;
|
||||
um.activeWorkers--;
|
||||
|
||||
if (
|
||||
um.uploadQueue.length === 0 &&
|
||||
um.activeWorkers === 0 &&
|
||||
typeof(um.uploadsFinished) === "function"
|
||||
) {
|
||||
um.uploadsFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Run the upload function for the next file
|
||||
if (um.activeWorkers < um.maxWorkers) {
|
||||
// Run the upload function
|
||||
um.startUpload();
|
||||
}
|
||||
}
|
||||
|
||||
uploadThread() {let um = this;
|
||||
let job = um.uploadQueue.shift(); // Get the first element of the array
|
||||
console.debug("Starting upload of " + job.name);
|
||||
UploadManager.prototype.startUpload = function() {let um = this;
|
||||
if (um.uploadQueue.length === 0) {
|
||||
return; // Nothing to upload
|
||||
}
|
||||
|
||||
let form = new FormData();
|
||||
form.append("name", job.name);
|
||||
form.append('file', job.file);
|
||||
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", um.apiAddress + "/file", true);
|
||||
xhr.timeout = 21600000; // 6 hours, to account for slow connections
|
||||
|
||||
// Report progress updates back to the caller
|
||||
xhr.upload.addEventListener("progress", function (evt) {
|
||||
if (evt.lengthComputable && typeof(job.onProgress) === "function") {
|
||||
job.onProgress(evt.loaded / evt.total);
|
||||
}
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
// 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
|
||||
um.uploadLog.push({
|
||||
jobID: job.jobID,
|
||||
fileID: resp.id,
|
||||
fileName: job.name
|
||||
});
|
||||
|
||||
if (typeof(job.onFinished) === "function") {
|
||||
job.onFinished(resp.id);
|
||||
}
|
||||
|
||||
// Finish the upload job
|
||||
um.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 (job.tries === 3) { // Upload failed
|
||||
job.onFailure(resp.value, resp.message);
|
||||
} else { // Try again
|
||||
job.tries++;
|
||||
um.uploadQueue.push(job);
|
||||
}
|
||||
|
||||
// Sleep the upload thread for 5 seconds
|
||||
window.setTimeout(() => { um.finishUpload(); }, 5000);
|
||||
} else {
|
||||
// Request did not arrive
|
||||
if (job.tries === 3) { // Upload failed
|
||||
if (typeof(job.onFailure) === "function") {
|
||||
job.onFailure(xhr.response, xhr.response);
|
||||
}
|
||||
} else { // Try again
|
||||
job.tries++;
|
||||
um.uploadQueue.push(job);
|
||||
}
|
||||
|
||||
// Sleep the upload thread for 5 seconds
|
||||
window.setTimeout(() => { um.finishUpload(); }, 5000);
|
||||
}
|
||||
};
|
||||
xhr.send(form);
|
||||
if (um.activeWorkers < um.maxWorkers) {
|
||||
um.activeWorkers++;
|
||||
um.uploadThread();
|
||||
}
|
||||
}
|
||||
|
||||
UploadManager.prototype.finishUpload = function() {let um = this;
|
||||
um.activeWorkers--;
|
||||
|
||||
if (
|
||||
um.uploadQueue.length === 0 &&
|
||||
um.activeWorkers === 0 &&
|
||||
typeof(um.uploadsFinished) === "function"
|
||||
) {
|
||||
um.uploadsFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
// Run the upload function for the next file
|
||||
um.startUpload();
|
||||
}
|
||||
|
||||
UploadManager.prototype.uploadThread = function() {let um = this;
|
||||
let job = um.uploadQueue.shift(); // Get the first element of the array
|
||||
console.debug("Starting upload of " + job.name);
|
||||
|
||||
let form = new FormData();
|
||||
form.append("name", job.name);
|
||||
form.append('file', job.file);
|
||||
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", um.apiAddress + "/file", true);
|
||||
xhr.timeout = 21600000; // 6 hours, to account for slow connections
|
||||
|
||||
// Report progress updates back to the caller
|
||||
xhr.upload.addEventListener("progress", function (evt) {
|
||||
if (evt.lengthComputable && typeof(job.onProgress) === "function") {
|
||||
job.onProgress(evt.loaded / evt.total);
|
||||
}
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
// 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
|
||||
um.uploadLog.push({
|
||||
jobID: job.jobID,
|
||||
fileID: resp.id,
|
||||
fileName: job.name
|
||||
});
|
||||
|
||||
if (typeof(job.onFinished) === "function") {
|
||||
job.onFinished(resp.id);
|
||||
}
|
||||
|
||||
// Finish the upload job
|
||||
um.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 (job.tries === 3) { // Upload failed
|
||||
job.onFailure(resp.value, resp.message);
|
||||
} else { // Try again
|
||||
job.tries++;
|
||||
um.uploadQueue.push(job);
|
||||
}
|
||||
|
||||
// Sleep the upload thread for 5 seconds
|
||||
window.setTimeout(() => { um.finishUpload(); }, 5000);
|
||||
} else {
|
||||
// Request did not arrive
|
||||
if (job.tries === 3) { // Upload failed
|
||||
if (typeof(job.onFailure) === "function") {
|
||||
job.onFailure(xhr.response, xhr.response);
|
||||
}
|
||||
} else { // Try again
|
||||
job.tries++;
|
||||
um.uploadQueue.push(job);
|
||||
}
|
||||
|
||||
// Sleep the upload thread for 5 seconds
|
||||
window.setTimeout(() => { um.finishUpload(); }, 5000);
|
||||
}
|
||||
};
|
||||
xhr.send(form);
|
||||
}
|
||||
|
@@ -1,154 +1,152 @@
|
||||
class DetailsWindow {
|
||||
constructor(viewer) {let dw = this;
|
||||
dw.viewer = viewer;
|
||||
function DetailsWindow(viewer) {let dw = this;
|
||||
dw.viewer = viewer;
|
||||
dw.visible = false;
|
||||
dw.fileID = "";
|
||||
dw.graph = 0;
|
||||
|
||||
dw.divPopup = document.getElementById("details_popup");
|
||||
dw.btnDetails = document.getElementById("btn_details");
|
||||
dw.btnCloseDetails = document.getElementById("btn_close_details");
|
||||
dw.divFileDetails = document.getElementById("info_file_details");
|
||||
|
||||
dw.btnDetails.addEventListener("click", () => { dw.toggle(); });
|
||||
dw.btnCloseDetails.addEventListener("click", () => { dw.toggle(); });
|
||||
}
|
||||
|
||||
DetailsWindow.prototype.toggle = function() {let dw = this;
|
||||
if (dw.visible) {
|
||||
dw.divPopup.style.opacity = "0";
|
||||
dw.divPopup.style.visibility = "hidden";
|
||||
dw.btnDetails.classList.remove("button_highlight");
|
||||
dw.visible = false;
|
||||
dw.fileID = "";
|
||||
dw.graph = 0;
|
||||
} else {
|
||||
dw.divPopup.style.opacity = "1";
|
||||
dw.divPopup.style.visibility = "visible";
|
||||
dw.btnDetails.classList.add("button_highlight");
|
||||
dw.visible = true;
|
||||
|
||||
dw.divPopup = document.getElementById("details_popup");
|
||||
dw.btnDetails = document.getElementById("btn_details");
|
||||
dw.btnCloseDetails = document.getElementById("btn_close_details");
|
||||
dw.divFileDetails = document.getElementById("info_file_details");
|
||||
// This is a workaround for a chrome bug which makes it so hidden
|
||||
// windows can't be scrolled after they are shown
|
||||
dw.divPopup.focus();
|
||||
|
||||
dw.btnDetails.addEventListener("click", () => { dw.toggle(); });
|
||||
dw.btnCloseDetails.addEventListener("click", () => { dw.toggle(); });
|
||||
}
|
||||
|
||||
toggle() {let dw = this;
|
||||
if (dw.visible) {
|
||||
dw.divPopup.style.opacity = "0";
|
||||
dw.divPopup.style.visibility = "hidden";
|
||||
dw.btnDetails.classList.remove("button_highlight");
|
||||
dw.visible = false;
|
||||
} else {
|
||||
dw.divPopup.style.opacity = "1";
|
||||
dw.divPopup.style.visibility = "visible";
|
||||
dw.btnDetails.classList.add("button_highlight");
|
||||
dw.visible = true;
|
||||
|
||||
// This is a workaround for a chrome bug which makes it so hidden
|
||||
// windows can't be scrolled after they are shown
|
||||
dw.divPopup.focus();
|
||||
|
||||
if (dw.graph === 0) {
|
||||
dw.renderGraph();
|
||||
}
|
||||
dw.updateGraph(dw.fileID);
|
||||
if (dw.graph === 0) {
|
||||
dw.renderGraph();
|
||||
}
|
||||
}
|
||||
|
||||
setDetails(file) {let dw = this;
|
||||
let desc = "";
|
||||
if (dw.viewer.isList) {
|
||||
desc = file.description;
|
||||
}
|
||||
dw.fileID = file.id;
|
||||
dw.divFileDetails.innerHTML = "<table>"
|
||||
+ "<tr><td>Name<td><td>" + escapeHTML(file.name) + "</td></tr>"
|
||||
+ "<tr><td>URL<td><td><a href=\"/u/" + file.id + "\">"+domainURL()+"/u/" + file.id + "</a></td></tr>"
|
||||
+ "<tr><td>Mime Type<td><td>" + escapeHTML(file.mime_type) + "</td></tr>"
|
||||
+ "<tr><td>ID<td><td>" + file.id + "</td></tr>"
|
||||
+ "<tr><td>Size<td><td>" + formatDataVolume(file.size, 4) + "</td></tr>"
|
||||
+ "<tr><td>Bandwidth<td><td>" + formatDataVolume(file.bandwidth_used, 4) + "</td></tr>"
|
||||
+ "<tr><td>Upload Date<td><td>" + file.date_upload + "</td></tr>"
|
||||
+ "<tr><td>Description<td><td>" + escapeHTML(desc) + "</td></tr>"
|
||||
+ "</table>";
|
||||
|
||||
if(dw.visible) {
|
||||
dw.updateGraph(file.id);
|
||||
}
|
||||
}
|
||||
|
||||
updateGraph(fileID) {let dw = this;
|
||||
console.log("updating graph "+fileID);
|
||||
fetch(apiEndpoint+"/file/" + fileID + "/timeseries?interval=60?days=14").then(resp => {
|
||||
if (!resp.ok) {return null;}
|
||||
return resp.json();
|
||||
}).then(resp => {
|
||||
dw.graph.data.labels = resp.labels;
|
||||
dw.graph.data.datasets[0].data = resp.downloads;
|
||||
dw.graph.data.datasets[1].data = resp.views;
|
||||
dw.graph.update();
|
||||
})
|
||||
}
|
||||
|
||||
renderGraph() {let dw = this;
|
||||
console.log("rendering graph");
|
||||
Chart.defaults.global.defaultFontColor = "#b3b3b3";
|
||||
Chart.defaults.global.defaultFontSize = 15;
|
||||
Chart.defaults.global.defaultFontFamily = "Ubuntu";
|
||||
Chart.defaults.global.aspectRatio = 2.5;
|
||||
Chart.defaults.global.elements.point.radius = 0;
|
||||
Chart.defaults.global.tooltips.mode = "index";
|
||||
Chart.defaults.global.tooltips.axis = "x";
|
||||
Chart.defaults.global.tooltips.intersect = false;
|
||||
dw.graph = new Chart(
|
||||
document.getElementById('bandwidth_chart'),
|
||||
{
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
label: "Downloads",
|
||||
backgroundColor: "rgba(64, 255, 64, .05)",
|
||||
borderColor: "rgba(128, 255, 128, 1)",
|
||||
borderWidth: 1.5,
|
||||
lineTension: 0.1,
|
||||
fill: true,
|
||||
yAxisID: "y_bandwidth",
|
||||
}, {
|
||||
label: "Views",
|
||||
backgroundColor: "rgba(64, 64, 255, .1)",
|
||||
borderColor: "rgba(128, 128, 255, 1)",
|
||||
borderWidth: 1.5,
|
||||
lineTension: 0.1,
|
||||
fill: true,
|
||||
yAxisID: "y_views",
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
type: "linear",
|
||||
display: true,
|
||||
position: "left",
|
||||
id: "y_bandwidth",
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: "Downloads"
|
||||
},
|
||||
gridLines: {
|
||||
color: "rgba(100, 255, 100, .1)"
|
||||
}
|
||||
}, {
|
||||
type: "linear",
|
||||
display: true,
|
||||
position: "right",
|
||||
id: "y_views",
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: "Views"
|
||||
},
|
||||
gridLines: {
|
||||
color: "rgba(128, 128, 255, .2)"
|
||||
}
|
||||
}
|
||||
],
|
||||
xAxes: [
|
||||
{
|
||||
ticks: {
|
||||
maxRotation: 20
|
||||
},
|
||||
gridLines: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
dw.updateGraph(dw.fileID);
|
||||
}
|
||||
}
|
||||
|
||||
DetailsWindow.prototype.setDetails = function(file) {let dw = this;
|
||||
let desc = "";
|
||||
if (dw.viewer.isList) {
|
||||
desc = file.description;
|
||||
}
|
||||
dw.fileID = file.id;
|
||||
dw.divFileDetails.innerHTML = "<table>"
|
||||
+ "<tr><td>Name<td><td>" + escapeHTML(file.name) + "</td></tr>"
|
||||
+ "<tr><td>URL<td><td><a href=\"/u/" + file.id + "\">"+domainURL()+"/u/" + file.id + "</a></td></tr>"
|
||||
+ "<tr><td>Mime Type<td><td>" + escapeHTML(file.mime_type) + "</td></tr>"
|
||||
+ "<tr><td>ID<td><td>" + file.id + "</td></tr>"
|
||||
+ "<tr><td>Size<td><td>" + formatDataVolume(file.size, 4) + "</td></tr>"
|
||||
+ "<tr><td>Bandwidth<td><td>" + formatDataVolume(file.bandwidth_used, 4) + "</td></tr>"
|
||||
+ "<tr><td>Upload Date<td><td>" + file.date_upload + "</td></tr>"
|
||||
+ "<tr><td>Description<td><td>" + escapeHTML(desc) + "</td></tr>"
|
||||
+ "</table>";
|
||||
|
||||
if(dw.visible) {
|
||||
dw.updateGraph(file.id);
|
||||
}
|
||||
}
|
||||
|
||||
DetailsWindow.prototype.updateGraph = function(fileID) {let dw = this;
|
||||
console.log("updating graph "+fileID);
|
||||
fetch(apiEndpoint+"/file/" + fileID + "/timeseries?interval=60?days=14").then(resp => {
|
||||
if (!resp.ok) {return null;}
|
||||
return resp.json();
|
||||
}).then(resp => {
|
||||
dw.graph.data.labels = resp.labels;
|
||||
dw.graph.data.datasets[0].data = resp.downloads;
|
||||
dw.graph.data.datasets[1].data = resp.views;
|
||||
dw.graph.update();
|
||||
})
|
||||
}
|
||||
|
||||
DetailsWindow.prototype.renderGraph = function() {let dw = this;
|
||||
console.log("rendering graph");
|
||||
Chart.defaults.global.defaultFontColor = "#b3b3b3";
|
||||
Chart.defaults.global.defaultFontSize = 15;
|
||||
Chart.defaults.global.defaultFontFamily = "Ubuntu";
|
||||
Chart.defaults.global.aspectRatio = 2.5;
|
||||
Chart.defaults.global.elements.point.radius = 0;
|
||||
Chart.defaults.global.tooltips.mode = "index";
|
||||
Chart.defaults.global.tooltips.axis = "x";
|
||||
Chart.defaults.global.tooltips.intersect = false;
|
||||
dw.graph = new Chart(
|
||||
document.getElementById('bandwidth_chart'),
|
||||
{
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
label: "Downloads",
|
||||
backgroundColor: "rgba(64, 255, 64, .05)",
|
||||
borderColor: "rgba(128, 255, 128, 1)",
|
||||
borderWidth: 1.5,
|
||||
lineTension: 0.1,
|
||||
fill: true,
|
||||
yAxisID: "y_bandwidth",
|
||||
}, {
|
||||
label: "Views",
|
||||
backgroundColor: "rgba(64, 64, 255, .1)",
|
||||
borderColor: "rgba(128, 128, 255, 1)",
|
||||
borderWidth: 1.5,
|
||||
lineTension: 0.1,
|
||||
fill: true,
|
||||
yAxisID: "y_views",
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
type: "linear",
|
||||
display: true,
|
||||
position: "left",
|
||||
id: "y_bandwidth",
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: "Downloads"
|
||||
},
|
||||
gridLines: {
|
||||
color: "rgba(100, 255, 100, .1)"
|
||||
}
|
||||
}, {
|
||||
type: "linear",
|
||||
display: true,
|
||||
position: "right",
|
||||
id: "y_views",
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: "Views"
|
||||
},
|
||||
gridLines: {
|
||||
color: "rgba(128, 128, 255, .2)"
|
||||
}
|
||||
}
|
||||
],
|
||||
xAxes: [
|
||||
{
|
||||
ticks: {
|
||||
maxRotation: 20
|
||||
},
|
||||
gridLines: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@@ -1,181 +1,180 @@
|
||||
class ListNavigator {
|
||||
constructor(viewer, data){let ln = this;
|
||||
ln.viewer = viewer;
|
||||
ln.data = data;
|
||||
ln.length = data.length;
|
||||
function ListNavigator(viewer, data) {let ln = this;
|
||||
ln.viewer = viewer;
|
||||
ln.data = data;
|
||||
ln.length = data.length;
|
||||
ln.position = 0;
|
||||
ln.history = [];
|
||||
ln.shuffle = false;
|
||||
|
||||
ln.divListNavigator = document.getElementById("list_navigator");
|
||||
|
||||
ln.btnDownloadList = document.getElementById("btn_download_list");
|
||||
ln.btnDownloadList.style.display = "";
|
||||
ln.btnDownloadList.addEventListener("click", () => { ln.downloadList(); });
|
||||
|
||||
ln.btnShuffle = document.getElementById("btn_shuffle");
|
||||
ln.btnShuffle.style.display = "";
|
||||
ln.btnShuffle.addEventListener("click", () => { ln.toggleShuffle(); });
|
||||
|
||||
// Render list contents in list navigator div
|
||||
data.forEach((item, i) => {
|
||||
let filename;
|
||||
if(item.name !== "null"){
|
||||
filename = item.name;
|
||||
}else{
|
||||
filename = "Removed File";
|
||||
}
|
||||
|
||||
let d = document.createElement("div");
|
||||
d.classList = "file_button list_item";
|
||||
d.addEventListener("click", () => { ln.setItem(i); });
|
||||
d.innerText = filename;
|
||||
ln.divListNavigator.appendChild(d);
|
||||
});
|
||||
|
||||
// Make the navigator visible
|
||||
ln.divListNavigator.style.display = "inline-block";
|
||||
|
||||
// Skip to the file defined in the link hash
|
||||
if(Number.isInteger(parseInt(getHashValue("item")))){
|
||||
ln.setItem(parseInt(getHashValue("item")));
|
||||
}else{
|
||||
ln.setItem(0);
|
||||
}
|
||||
}
|
||||
|
||||
ListNavigator.prototype.nextItem = function() {let ln = this;
|
||||
if(ln.shuffle){
|
||||
ln.randItem();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ln.position >= ln.length) {
|
||||
ln.position = 0;
|
||||
ln.history = [];
|
||||
ln.shuffle = false;
|
||||
|
||||
ln.divListNavigator = document.getElementById("list_navigator");
|
||||
|
||||
ln.btnDownloadList = document.getElementById("btn_download_list");
|
||||
ln.btnDownloadList.style.display = "";
|
||||
ln.btnDownloadList.addEventListener("click", () => { ln.downloadList(); });
|
||||
|
||||
ln.btnShuffle = document.getElementById("btn_shuffle");
|
||||
ln.btnShuffle.style.display = "";
|
||||
ln.btnShuffle.addEventListener("click", () => { ln.toggleShuffle(); });
|
||||
|
||||
// Render list contents in list navigator div
|
||||
data.forEach((item, i) => {
|
||||
let filename;
|
||||
if(item.name !== "null"){
|
||||
filename = item.name;
|
||||
}else{
|
||||
filename = "Removed File";
|
||||
}
|
||||
|
||||
let d = document.createElement("div");
|
||||
d.classList = "file_button list_item";
|
||||
d.addEventListener("click", () => { ln.setItem(i); });
|
||||
d.innerText = filename;
|
||||
ln.divListNavigator.appendChild(d);
|
||||
});
|
||||
|
||||
// Make the navigator visible
|
||||
ln.divListNavigator.style.display = "inline-block";
|
||||
|
||||
// Skip to the file defined in the link hash
|
||||
if(Number.isInteger(parseInt(getHashValue("item")))){
|
||||
ln.setItem(parseInt(getHashValue("item")));
|
||||
}else{
|
||||
ln.setItem(0);
|
||||
}
|
||||
} else {
|
||||
ln.position++;
|
||||
}
|
||||
|
||||
nextItem(){let ln = this;
|
||||
if(ln.shuffle){
|
||||
ln.randItem();
|
||||
return;
|
||||
}
|
||||
ln.setItem(ln.position);
|
||||
}
|
||||
|
||||
if (ln.position >= ln.length) {
|
||||
ln.position = 0;
|
||||
} else {
|
||||
ln.position++;
|
||||
}
|
||||
|
||||
ln.setItem(ln.position);
|
||||
ListNavigator.prototype.previousItem = function() {let ln = this;
|
||||
if(ln.position === 0){
|
||||
ln.position = ln.length - 1;
|
||||
}else{
|
||||
ln.position--;
|
||||
}
|
||||
|
||||
previousItem(){let ln = this;
|
||||
if(ln.position === 0){
|
||||
ln.position = ln.length - 1;
|
||||
}else{
|
||||
ln.position--;
|
||||
}
|
||||
ln.setItem(ln.position);
|
||||
}
|
||||
|
||||
ln.setItem(ln.position);
|
||||
ListNavigator.prototype.randItem = function() {let ln = this;
|
||||
// Avoid viewing the same file multiple times
|
||||
let rand;
|
||||
do {
|
||||
rand = Math.round(Math.random() * ln.length);
|
||||
console.log("rand is " + rand);
|
||||
} while(ln.history.indexOf(rand) > -1);
|
||||
|
||||
ln.setItem(rand);
|
||||
}
|
||||
|
||||
ListNavigator.prototype.setItem = function(index) {let ln = this;
|
||||
if(index >= ln.length){
|
||||
ln.position = 0;
|
||||
}else{
|
||||
ln.position = index;
|
||||
}
|
||||
|
||||
randItem(){let ln = this;
|
||||
// Avoid viewing the same file multiple times
|
||||
let rand;
|
||||
do {
|
||||
rand = Math.round(Math.random() * ln.length);
|
||||
console.log("rand is " + rand);
|
||||
} while(ln.history.indexOf(rand) > -1);
|
||||
// Set the URL hash
|
||||
location.hash = "item=" + ln.position;
|
||||
ln.viewer.setFile(ln.data[ln.position]);
|
||||
|
||||
ln.setItem(rand);
|
||||
ln.addToHistory(index);
|
||||
ln.loadThumbnails(index);
|
||||
|
||||
document.querySelectorAll("#list_navigator > .file_button_selected").forEach(el => {
|
||||
el.classList.remove("file_button_selected");
|
||||
});
|
||||
|
||||
let selectedItem = ln.divListNavigator.children[ln.position];
|
||||
selectedItem.classList.add("file_button_selected");
|
||||
|
||||
let cst = window.getComputedStyle(selectedItem);
|
||||
let itemWidth = selectedItem.offsetWidth + parseInt(cst.marginLeft) + parseInt(cst.marginRight);
|
||||
|
||||
let start = ln.divListNavigator.scrollLeft;
|
||||
let end = ((ln.position * itemWidth) + (itemWidth / 2)) - (ln.divListNavigator.clientWidth / 2);
|
||||
let steps = 60; // One second
|
||||
let stepSize = (end - start)/steps;
|
||||
|
||||
let animateScroll = (pos, step) => {
|
||||
ln.divListNavigator.scrollLeft = pos;
|
||||
|
||||
if (step < steps) {
|
||||
requestAnimationFrame(() => {
|
||||
animateScroll(pos+stepSize, step+1);
|
||||
});
|
||||
}
|
||||
};
|
||||
animateScroll(start, 0);
|
||||
}
|
||||
|
||||
ListNavigator.prototype.downloadList = function() {let ln = this;
|
||||
document.getElementById("download_frame").src = "/api/list/" + ln.viewer.listId + "/zip";
|
||||
}
|
||||
|
||||
ListNavigator.prototype.addToHistory = function(index) {let ln = this;
|
||||
if(ln.history.length >= (ln.length - 6)){
|
||||
ln.history.shift();
|
||||
}
|
||||
|
||||
setItem(index){let ln = this;
|
||||
if(index >= ln.length){
|
||||
ln.position = 0;
|
||||
}else{
|
||||
ln.position = index;
|
||||
}
|
||||
ln.history.push(index);
|
||||
}
|
||||
|
||||
// Set the URL hash
|
||||
location.hash = "item=" + ln.position;
|
||||
ln.viewer.setFile(ln.data[ln.position]);
|
||||
ListNavigator.prototype.toggleShuffle = function() {let ln = this;
|
||||
ln.shuffle = !ln.shuffle; // :P
|
||||
|
||||
ln.addToHistory(index);
|
||||
ln.loadThumbnails(index);
|
||||
if(ln.shuffle){
|
||||
document.querySelector("#btn_shuffle > span").innerHTML = "Shuffle ☑"; // Check icon
|
||||
ln.btnShuffle.classList.add("button_highlight");
|
||||
}else{
|
||||
document.querySelector("#btn_shuffle > span").innerHTML = "Shuffle ☐"; // Empty checkbox
|
||||
ln.btnShuffle.classList.remove("button_highlight");
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll("#list_navigator > .file_button_selected").forEach(el => {
|
||||
el.classList.remove("file_button_selected");
|
||||
});
|
||||
ListNavigator.prototype.loadThumbnails = function(index) {let ln = this;
|
||||
let startPos = +index - 50;
|
||||
let endPos = +index + 50;
|
||||
// fyi, the + is to let javascript know it's actually a number instead of a string
|
||||
|
||||
let selectedItem = ln.divListNavigator.children[ln.position];
|
||||
selectedItem.classList.add("file_button_selected");
|
||||
|
||||
let cst = window.getComputedStyle(selectedItem);
|
||||
let itemWidth = selectedItem.offsetWidth + parseInt(cst.marginLeft) + parseInt(cst.marginRight);
|
||||
|
||||
let start = ln.divListNavigator.scrollLeft;
|
||||
let end = ((ln.position * itemWidth) + (itemWidth / 2)) - (ln.divListNavigator.clientWidth / 2);
|
||||
let steps = 60; // One second
|
||||
let stepSize = (end - start)/steps;
|
||||
|
||||
let animateScroll = (pos, step) => {
|
||||
ln.divListNavigator.scrollLeft = pos;
|
||||
|
||||
if (step < steps) {
|
||||
requestAnimationFrame(() => {
|
||||
animateScroll(pos+stepSize, step+1);
|
||||
});
|
||||
}
|
||||
};
|
||||
animateScroll(start, 0);
|
||||
if(startPos < 0){
|
||||
startPos = 0;
|
||||
}
|
||||
|
||||
downloadList(){let ln = this;
|
||||
document.getElementById("download_frame").src = "/api/list/" + ln.viewer.listId + "/zip";
|
||||
if(endPos >= ln.length){
|
||||
endPos = ln.length - 1;
|
||||
}
|
||||
|
||||
addToHistory(index){let ln = this;
|
||||
if(ln.history.length >= (ln.length - 6)){
|
||||
ln.history.shift();
|
||||
let navigatorItems = document.getElementById("list_navigator").children
|
||||
|
||||
for (let i = startPos; i <= endPos; i++){
|
||||
if (navigatorItems[i].innerHTML.includes("list_item_thumbnail")) {
|
||||
continue; // Thumbnail already loaded
|
||||
}
|
||||
|
||||
ln.history.push(index);
|
||||
let thumb = "/api/file/" + ln.data[i].id + "/thumbnail?width=48&height=48";
|
||||
let name = ln.data[i].name;
|
||||
|
||||
let itemHtml = "<img src=\"" + thumb + "\" "
|
||||
+ "class=\"list_item_thumbnail\" alt=\"" + escapeHTML(name) + "\"/>"
|
||||
+ escapeHTML(name);
|
||||
|
||||
navigatorItems[i].innerHTML = itemHtml;
|
||||
}
|
||||
}
|
||||
|
||||
toggleShuffle(){let ln = this;
|
||||
ln.shuffle = !ln.shuffle; // :P
|
||||
|
||||
if(ln.shuffle){
|
||||
document.querySelector("#btn_shuffle > span").innerHTML = "Shuffle ☑"; // Check icon
|
||||
ln.btnShuffle.classList.add("button_highlight");
|
||||
}else{
|
||||
document.querySelector("#btn_shuffle > span").innerHTML = "Shuffle ☐"; // Empty checkbox
|
||||
ln.btnShuffle.classList.remove("button_highlight");
|
||||
}
|
||||
}
|
||||
|
||||
loadThumbnails(index){let ln = this;
|
||||
let startPos = +index - 50;
|
||||
let endPos = +index + 50;
|
||||
// fyi, the + is to let javascript know it's actually a number instead of a string
|
||||
|
||||
if(startPos < 0){
|
||||
startPos = 0;
|
||||
}
|
||||
|
||||
if(endPos >= ln.length){
|
||||
endPos = ln.length - 1;
|
||||
}
|
||||
|
||||
let navigatorItems = document.getElementById("list_navigator").children
|
||||
|
||||
for (let i = startPos; i <= endPos; i++){
|
||||
if (navigatorItems[i].innerHTML.includes("list_item_thumbnail")) {
|
||||
continue; // Thumbnail already loaded
|
||||
}
|
||||
|
||||
let thumb = "/api/file/" + ln.data[i].id + "/thumbnail?width=48&height=48";
|
||||
let name = ln.data[i].name;
|
||||
|
||||
let itemHtml = "<img src=\"" + thumb + "\" "
|
||||
+ "class=\"list_item_thumbnail\" alt=\"" + escapeHTML(name) + "\"/>"
|
||||
+ escapeHTML(name);
|
||||
|
||||
navigatorItems[i].innerHTML = itemHtml;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Misc function, don't really know where else to put it
|
||||
|
@@ -1,161 +1,160 @@
|
||||
class Toolbar {
|
||||
constructor(viewer) {let t = this;
|
||||
t.viewer = viewer;
|
||||
function Toolbar(viewer) {let t = this;
|
||||
t.viewer = viewer;
|
||||
t.visible = false;
|
||||
t.sharebarVisible = false;
|
||||
|
||||
t.divToolbar = document.getElementById("toolbar");
|
||||
t.divFilePreview = document.getElementById("filepreview");
|
||||
t.downloadFrame = document.getElementById("download_frame");
|
||||
t.spanViews = document.getElementById("stat_views");
|
||||
t.spanDownloads = document.getElementById("stat_downloads");
|
||||
t.spanSize = document.getElementById("stat_size");
|
||||
|
||||
t.btnToggleToolbar = document.getElementById("btn_toggle_toolbar");
|
||||
t.btnDownload = document.getElementById("btn_download");
|
||||
t.btnCopyLink = document.getElementById("btn_copy");
|
||||
t.spanCopyLink = document.querySelector("#btn_copy > span");
|
||||
t.btnShare = document.getElementById("btn_share");
|
||||
t.divSharebar = document.getElementById("sharebar");
|
||||
|
||||
t.btnToggleToolbar.addEventListener("click", () => { t.toggle(); });
|
||||
t.btnDownload.addEventListener("click", () => { t.download(); });
|
||||
t.btnCopyLink.addEventListener("click", () => { t.copyUrl(); });
|
||||
t.btnShare.addEventListener("click", () => { t.toggleSharebar(); });
|
||||
}
|
||||
|
||||
Toolbar.prototype.toggle = function() {let t = this;
|
||||
if (t.visible) {
|
||||
if (t.sharebarVisible) { t.toggleSharebar(); }
|
||||
|
||||
t.divToolbar.style.left = "-8em";
|
||||
t.divFilePreview.style.left = "0px";
|
||||
t.btnToggleToolbar.classList.remove("button_highlight");
|
||||
t.visible = false;
|
||||
t.sharebarVisible = false;
|
||||
|
||||
t.divToolbar = document.getElementById("toolbar");
|
||||
t.divFilePreview = document.getElementById("filepreview");
|
||||
t.downloadFrame = document.getElementById("download_frame");
|
||||
t.spanViews = document.getElementById("stat_views");
|
||||
t.spanDownloads = document.getElementById("stat_downloads");
|
||||
t.spanSize = document.getElementById("stat_size");
|
||||
|
||||
t.btnToggleToolbar = document.getElementById("btn_toggle_toolbar");
|
||||
t.btnDownload = document.getElementById("btn_download");
|
||||
t.btnCopyLink = document.getElementById("btn_copy");
|
||||
t.spanCopyLink = document.querySelector("#btn_copy > span");
|
||||
t.btnShare = document.getElementById("btn_share");
|
||||
t.divSharebar = document.getElementById("sharebar");
|
||||
|
||||
t.btnToggleToolbar.addEventListener("click", () => { t.toggle(); });
|
||||
t.btnDownload.addEventListener("click", () => { t.download(); });
|
||||
t.btnCopyLink.addEventListener("click", () => { t.copyUrl(); });
|
||||
t.btnShare.addEventListener("click", () => { t.toggleSharebar(); });
|
||||
}
|
||||
|
||||
toggle() {let t = this;
|
||||
if (t.visible) {
|
||||
if (t.sharebarVisible) { t.toggleSharebar(); }
|
||||
|
||||
t.divToolbar.style.left = "-8em";
|
||||
t.divFilePreview.style.left = "0px";
|
||||
t.btnToggleToolbar.classList.remove("button_highlight");
|
||||
t.visible = false;
|
||||
} else {
|
||||
t.divToolbar.style.left = "0px";
|
||||
t.divFilePreview.style.left = "8em";
|
||||
t.btnToggleToolbar.classList.add("button_highlight");
|
||||
t.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
toggleSharebar(){let t = this;
|
||||
if (navigator.share) {
|
||||
navigator.share({
|
||||
title: t.viewer.title,
|
||||
text: "Download " + t.viewer.title + " here",
|
||||
url: window.location.href
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if(t.sharebarVisible){
|
||||
t.divSharebar.style.left = "-8em";
|
||||
t.btnShare.classList.remove("button_highlight")
|
||||
t.sharebarVisible = false;
|
||||
}else{
|
||||
t.divSharebar.style.left = "8em";
|
||||
t.btnShare.classList.add("button_highlight")
|
||||
t.sharebarVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
download() {let t = this;
|
||||
let triggerDL = (captchaResp = "") => {
|
||||
if (captchaResp === "") {
|
||||
t.downloadFrame.src = apiEndpoint+"/file/"+
|
||||
t.viewer.currentFile+"?download";
|
||||
} else {
|
||||
t.downloadFrame.src = apiEndpoint+"/file/"+
|
||||
t.viewer.currentFile+"?download&recaptcha_response="+captchaResp;
|
||||
}
|
||||
}
|
||||
|
||||
if (captchaKey === "none"){
|
||||
// If the server doesn't support captcha there's no use in checking
|
||||
// availability
|
||||
triggerDL();
|
||||
return;
|
||||
}
|
||||
if (recaptchaResponse !== "") {
|
||||
// Captcha already filled in. Use the saved captcha responsse to
|
||||
// download the file
|
||||
triggerDL(recaptchaResponse);
|
||||
|
||||
// Reset the key
|
||||
recaptchaResponse = "";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(apiEndpoint+"/file/"+t.viewer.currentFile+"/availability").then(resp => {
|
||||
return resp.json();
|
||||
}).then(resp => {
|
||||
let popupDiv = document.getElementById("captcha_popup");
|
||||
let popupTitle = document.getElementById("captcha_popup_title");
|
||||
let popupContent = document.getElementById("captcha_popup_content");
|
||||
|
||||
let showCaptcha = () => {
|
||||
// Load the recaptcha script with a load function
|
||||
let script = document.createElement("script");
|
||||
script.src = "https://www.google.com/recaptcha/api.js?onload=loadCaptcha&render=explicit";
|
||||
document.body.appendChild(script);
|
||||
|
||||
// Show the popup
|
||||
popupDiv.style.opacity = "1";
|
||||
popupDiv.style.visibility = "visible";
|
||||
}
|
||||
|
||||
if (resp.value === "file_rate_limited_captcha_required") {
|
||||
popupTitle.innerText = "Rate limiting enabled!";
|
||||
popupContent.innerText = "This file is using a suspicious "+
|
||||
"amount of bandwidth relative to its popularity. To "+
|
||||
"continue downloading this file you will have to "+
|
||||
"prove that you're a human first.";
|
||||
showCaptcha();
|
||||
} else if (resp.value === "virus_detected_captcha_required") {
|
||||
popupTitle.innerText = "Malware warning!";
|
||||
popupContent.innerText = "According to our scanning "+
|
||||
"systems this file may contain a virus of type '"+
|
||||
resp.extra+"'. You can continue downloading this file at "+
|
||||
"your own risk, but you will have to prove that you're a "+
|
||||
"human first.";
|
||||
showCaptcha();
|
||||
} else {
|
||||
console.warn("resp.value not valid: "+resp.value);
|
||||
triggerDL();
|
||||
}
|
||||
}).catch(e => {
|
||||
console.warn("fetch availability failed: "+e);
|
||||
triggerDL();
|
||||
});
|
||||
}
|
||||
|
||||
copyUrl() {let t = this;
|
||||
if(copyText(window.location.href)) {
|
||||
console.log('Text copied');
|
||||
t.spanCopyLink.innerText = "Copied!";
|
||||
t.btnCopyLink.classList.add("button_highlight")
|
||||
} else {
|
||||
console.log('Copying not supported');
|
||||
t.spanCopyLink.innerText = "Error!";
|
||||
alert("Your browser does not support copying text.");
|
||||
}
|
||||
|
||||
// Return to normal
|
||||
setTimeout(() => {
|
||||
t.spanCopyLink.innerText = "Copy";
|
||||
t.btnCopyLink.classList.remove("button_highlight")
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
setStats(file) {let t = this;
|
||||
t.spanViews.innerText = file.views
|
||||
t.spanDownloads.innerText = Math.round((file.bandwidth_used/file.size)*10)/10;
|
||||
t.spanSize.innerText = formatDataVolume(file.size, 3);
|
||||
} else {
|
||||
t.divToolbar.style.left = "0px";
|
||||
t.divFilePreview.style.left = "8em";
|
||||
t.btnToggleToolbar.classList.add("button_highlight");
|
||||
t.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
Toolbar.prototype.toggleSharebar = function() {let t = this;
|
||||
if (navigator.share) {
|
||||
navigator.share({
|
||||
title: t.viewer.title,
|
||||
text: "Download " + t.viewer.title + " here",
|
||||
url: window.location.href
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if(t.sharebarVisible){
|
||||
t.divSharebar.style.left = "-8em";
|
||||
t.btnShare.classList.remove("button_highlight")
|
||||
t.sharebarVisible = false;
|
||||
}else{
|
||||
t.divSharebar.style.left = "8em";
|
||||
t.btnShare.classList.add("button_highlight")
|
||||
t.sharebarVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
Toolbar.prototype.download = function() {let t = this;
|
||||
let triggerDL = (captchaResp = "") => {
|
||||
if (captchaResp === "") {
|
||||
t.downloadFrame.src = apiEndpoint+"/file/"+
|
||||
t.viewer.currentFile+"?download";
|
||||
} else {
|
||||
t.downloadFrame.src = apiEndpoint+"/file/"+
|
||||
t.viewer.currentFile+"?download&recaptcha_response="+captchaResp;
|
||||
}
|
||||
}
|
||||
|
||||
if (captchaKey === "none"){
|
||||
// If the server doesn't support captcha there's no use in checking
|
||||
// availability
|
||||
triggerDL();
|
||||
return;
|
||||
}
|
||||
if (recaptchaResponse !== "") {
|
||||
// Captcha already filled in. Use the saved captcha responsse to
|
||||
// download the file
|
||||
triggerDL(recaptchaResponse);
|
||||
|
||||
// Reset the key
|
||||
recaptchaResponse = "";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(apiEndpoint+"/file/"+t.viewer.currentFile+"/availability").then(resp => {
|
||||
return resp.json();
|
||||
}).then(resp => {
|
||||
let popupDiv = document.getElementById("captcha_popup");
|
||||
let popupTitle = document.getElementById("captcha_popup_title");
|
||||
let popupContent = document.getElementById("captcha_popup_content");
|
||||
|
||||
let showCaptcha = () => {
|
||||
// Load the recaptcha script with a load function
|
||||
let script = document.createElement("script");
|
||||
script.src = "https://www.google.com/recaptcha/api.js?onload=loadCaptcha&render=explicit";
|
||||
document.body.appendChild(script);
|
||||
|
||||
// Show the popup
|
||||
popupDiv.style.opacity = "1";
|
||||
popupDiv.style.visibility = "visible";
|
||||
}
|
||||
|
||||
if (resp.value === "file_rate_limited_captcha_required") {
|
||||
popupTitle.innerText = "Rate limiting enabled!";
|
||||
popupContent.innerText = "This file is using a suspicious "+
|
||||
"amount of bandwidth relative to its popularity. To "+
|
||||
"continue downloading this file you will have to "+
|
||||
"prove that you're a human first.";
|
||||
showCaptcha();
|
||||
} else if (resp.value === "virus_detected_captcha_required") {
|
||||
popupTitle.innerText = "Malware warning!";
|
||||
popupContent.innerText = "According to our scanning "+
|
||||
"systems this file may contain a virus of type '"+
|
||||
resp.extra+"'. You can continue downloading this file at "+
|
||||
"your own risk, but you will have to prove that you're a "+
|
||||
"human first.";
|
||||
showCaptcha();
|
||||
} else {
|
||||
console.warn("resp.value not valid: "+resp.value);
|
||||
triggerDL();
|
||||
}
|
||||
}).catch(e => {
|
||||
console.warn("fetch availability failed: "+e);
|
||||
triggerDL();
|
||||
});
|
||||
}
|
||||
|
||||
Toolbar.prototype.copyUrl = function() {let t = this;
|
||||
if(copyText(window.location.href)) {
|
||||
console.log('Text copied');
|
||||
t.spanCopyLink.innerText = "Copied!";
|
||||
t.btnCopyLink.classList.add("button_highlight")
|
||||
} else {
|
||||
console.log('Copying not supported');
|
||||
t.spanCopyLink.innerText = "Error!";
|
||||
alert("Your browser does not support copying text.");
|
||||
}
|
||||
|
||||
// Return to normal
|
||||
setTimeout(() => {
|
||||
t.spanCopyLink.innerText = "Copy";
|
||||
t.btnCopyLink.classList.remove("button_highlight")
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
Toolbar.prototype.setStats = function(file) {let t = this;
|
||||
t.spanViews.innerText = file.views
|
||||
t.spanDownloads.innerText = Math.round((file.bandwidth_used/file.size)*10)/10;
|
||||
t.spanSize.innerText = formatDataVolume(file.size, 3);
|
||||
}
|
||||
|
||||
|
||||
// Called by the google recaptcha script
|
||||
let recaptchaResponse = "";
|
||||
function loadCaptcha(){
|
||||
|
@@ -1,200 +1,199 @@
|
||||
class Viewer {
|
||||
constructor(type, viewToken, data) {let v = this;
|
||||
// Set defaults
|
||||
v.toolbar = null;
|
||||
v.listNavigator = null;
|
||||
v.detailsWindow = null;
|
||||
v.divFilepreview = null;
|
||||
v.currentFile = "";
|
||||
v.title = ""; // Contains either the file name or list title
|
||||
v.listId = "";
|
||||
v.viewToken = "";
|
||||
v.isList = false;
|
||||
v.isFile = false;
|
||||
v.initialized = false;
|
||||
function Viewer(type, viewToken, data) {let v = this;
|
||||
// Set defaults
|
||||
v.toolbar = null;
|
||||
v.listNavigator = null;
|
||||
v.detailsWindow = null;
|
||||
v.divFilepreview = null;
|
||||
v.currentFile = "";
|
||||
v.title = ""; // Contains either the file name or list title
|
||||
v.listId = "";
|
||||
v.viewToken = "";
|
||||
v.isList = false;
|
||||
v.isFile = false;
|
||||
v.initialized = false;
|
||||
|
||||
v.viewToken = viewToken;
|
||||
v.toolbar = new Toolbar(v);
|
||||
v.detailsWindow = new DetailsWindow(v);
|
||||
v.viewToken = viewToken;
|
||||
v.toolbar = new Toolbar(v);
|
||||
v.detailsWindow = new DetailsWindow(v);
|
||||
|
||||
v.divFilepreview = document.getElementById("filepreview");
|
||||
v.divFilepreview = document.getElementById("filepreview");
|
||||
|
||||
// On small screens the toolbar takes too much space, so it collapses
|
||||
// automatically
|
||||
if (v.divFilepreview.clientWidth > 600 && !v.toolbar.visible) {
|
||||
v.toolbar.toggle();
|
||||
}
|
||||
|
||||
// The close button only works if the window has an opener. So we hide
|
||||
// the button if it does not
|
||||
if (window.opener === null && window.history.length !== 1) {
|
||||
document.getElementById("button_close_file_viewer").remove()
|
||||
}
|
||||
|
||||
if (type === "file") {
|
||||
v.isFile = true;
|
||||
v.currentFile = data.id;
|
||||
v.title = data.name;
|
||||
v.setFile(data);
|
||||
} else if (type === "list") {
|
||||
v.isList = true;
|
||||
v.listId = data.id;
|
||||
v.title = data.title;
|
||||
v.listNavigator = new ListNavigator(v, data.data);
|
||||
}
|
||||
|
||||
v.renderSponsors();
|
||||
window.addEventListener("resize", e => { v.renderSponsors(e); });
|
||||
|
||||
// Register keyboard shortcuts
|
||||
document.addEventListener("keydown", e => { v.keyboardEvent(e); });
|
||||
|
||||
v.initialized = true;
|
||||
// On small screens the toolbar takes too much space, so it collapses
|
||||
// automatically
|
||||
if (v.divFilepreview.clientWidth > 600 && !v.toolbar.visible) {
|
||||
v.toolbar.toggle();
|
||||
}
|
||||
|
||||
setFile(file) {let v = this;
|
||||
v.currentFile = file.id;
|
||||
if (v.isList) {
|
||||
document.getElementById("file_viewer_headerbar_title").style.lineHeight = "1em";
|
||||
document.getElementById("file_viewer_list_title").innerText = this.title;
|
||||
document.getElementById("file_viewer_file_title").innerText = file.name;
|
||||
document.title = v.title + " ~ " + file.name + " ~ pixeldrain";
|
||||
// The close button only works if the window has an opener. So we hide
|
||||
// the button if it does not
|
||||
if (window.opener === null && window.history.length !== 1) {
|
||||
document.getElementById("button_close_file_viewer").remove()
|
||||
}
|
||||
|
||||
if (type === "file") {
|
||||
v.isFile = true;
|
||||
v.currentFile = data.id;
|
||||
v.title = data.name;
|
||||
v.setFile(data);
|
||||
} else if (type === "list") {
|
||||
v.isList = true;
|
||||
v.listId = data.id;
|
||||
v.title = data.title;
|
||||
v.listNavigator = new ListNavigator(v, data.data);
|
||||
}
|
||||
|
||||
v.renderSponsors();
|
||||
window.addEventListener("resize", e => { v.renderSponsors(e); });
|
||||
|
||||
// Register keyboard shortcuts
|
||||
document.addEventListener("keydown", e => { v.keyboardEvent(e); });
|
||||
|
||||
v.initialized = true;
|
||||
}
|
||||
|
||||
Viewer.prototype.setFile = function(file) {let v = this;
|
||||
v.currentFile = file.id;
|
||||
if (v.isList) {
|
||||
document.getElementById("file_viewer_headerbar_title").style.lineHeight = "1em";
|
||||
document.getElementById("file_viewer_list_title").innerText = this.title;
|
||||
document.getElementById("file_viewer_file_title").innerText = file.name;
|
||||
document.title = v.title + " ~ " + file.name + " ~ pixeldrain";
|
||||
} else {
|
||||
document.getElementById("file_viewer_file_title").innerText = file.name;
|
||||
document.title = file.name + " ~ pixeldrain";
|
||||
}
|
||||
|
||||
// Update the file details
|
||||
v.detailsWindow.setDetails(file);
|
||||
v.toolbar.setStats(file);
|
||||
|
||||
// Register a new view. We don't care what this returns becasue we can't
|
||||
// do anything about it anyway
|
||||
fetch(apiEndpoint+"/file/"+file.id+"/view",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/x-www-form-urlencoded"},
|
||||
body: "token="+v.viewToken
|
||||
}
|
||||
);
|
||||
|
||||
// Clear the canvas
|
||||
v.divFilepreview.innerHTML = "";
|
||||
|
||||
let nextItem = () => {
|
||||
if (v.listNavigator !== null) {
|
||||
v.listNavigator.nextItem();
|
||||
}
|
||||
};
|
||||
|
||||
if (
|
||||
file.mime_type.startsWith("image")
|
||||
) {
|
||||
new ImageViewer(v, file).render(v.divFilepreview);
|
||||
} else if (
|
||||
file.mime_type.startsWith("video") ||
|
||||
file.mime_type === "application/matroska" ||
|
||||
file.mime_type === "application/x-matroska"
|
||||
) {
|
||||
new VideoViewer(v, file, nextItem).render(v.divFilepreview);
|
||||
} else if (
|
||||
file.mime_type.startsWith("audio") ||
|
||||
file.mime_type === "application/ogg" ||
|
||||
file.name.endsWith(".mp3")
|
||||
) {
|
||||
new AudioViewer(v, file, nextItem).render(v.divFilepreview);
|
||||
} else if (
|
||||
file.mime_type === "application/pdf" ||
|
||||
file.mime_type === "application/x-pdf"
|
||||
) {
|
||||
new PDFViewer(v, file).render(v.divFilepreview);
|
||||
} else if (
|
||||
file.mime_type.startsWith("text") ||
|
||||
file.id === "demo"
|
||||
) {
|
||||
new TextViewer(v, file).render(v.divFilepreview);
|
||||
} else {
|
||||
new FileViewer(v, file).render(v.divFilepreview);
|
||||
}
|
||||
}
|
||||
|
||||
Viewer.prototype.renderSponsors = function() {
|
||||
let scale = 1;
|
||||
let scaleWidth = 1;
|
||||
let scaleHeight = 1;
|
||||
let minWidth = 728;
|
||||
let minHeight = 800;
|
||||
|
||||
if (window.innerWidth < minWidth) {
|
||||
scaleWidth = window.innerWidth/minWidth;
|
||||
}
|
||||
if (window.innerHeight < minHeight) {
|
||||
scaleHeight = window.innerHeight/minHeight;
|
||||
}
|
||||
scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
|
||||
|
||||
// Because of the scale transformation the automatic margins don't work
|
||||
// anymore. So we have to maunally calculate the margin. Where we take the
|
||||
// width of the viewport - the width of the ad to calculate the amount of
|
||||
// pixels around the ad. We multiply the ad size by the scale we calcualted
|
||||
// to account for the smaller size.
|
||||
let offset = (window.innerWidth - (minWidth*scale)) / 2
|
||||
if (offset < 0) {
|
||||
offset = 0
|
||||
}
|
||||
document.querySelector(".sponsors > iframe").style.marginLeft = offset+"px";
|
||||
|
||||
if (scale == 1) {
|
||||
document.querySelector(".sponsors > iframe").style.transform = "none";
|
||||
document.querySelector(".sponsors").style.height = "90px";
|
||||
} else {
|
||||
document.querySelector(".sponsors > iframe").style.transform = "scale("+scale+")";
|
||||
document.querySelector(".sponsors").style.height = (scale*90)+"px";
|
||||
}
|
||||
}
|
||||
|
||||
Viewer.prototype.keyboardEvent = function(evt) {let v = this;
|
||||
if (evt.ctrlKey || evt.altKey) {
|
||||
return // prevent custom shortcuts from interfering with system shortcuts
|
||||
}
|
||||
|
||||
switch (evt.keyCode) {
|
||||
case 65: // A or left arrow key go to previous file
|
||||
case 37:
|
||||
if (v.listNavigator != null) {
|
||||
v.listNavigator.previousItem();
|
||||
}
|
||||
break;
|
||||
case 68: // D or right arrow key go to next file
|
||||
case 39:
|
||||
if (v.listNavigator != null) {
|
||||
v.listNavigator.nextItem();
|
||||
}
|
||||
break;
|
||||
case 83:
|
||||
if (evt.shiftKey) {
|
||||
v.listNavigator.downloadList(); // SHIFT + S downloads all files in list
|
||||
} else {
|
||||
document.getElementById("file_viewer_file_title").innerText = file.name;
|
||||
document.title = file.name + " ~ pixeldrain";
|
||||
v.toolbar.download(); // S to download the current file
|
||||
}
|
||||
|
||||
// Update the file details
|
||||
v.detailsWindow.setDetails(file);
|
||||
v.toolbar.setStats(file);
|
||||
|
||||
// Register a new view. We don't care what this returns becasue we can't
|
||||
// do anything about it anyway
|
||||
fetch(apiEndpoint+"/file/"+file.id+"/view",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/x-www-form-urlencoded"},
|
||||
body: "token="+v.viewToken
|
||||
}
|
||||
);
|
||||
|
||||
// Clear the canvas
|
||||
v.divFilepreview.innerHTML = "";
|
||||
|
||||
let nextItem = () => {
|
||||
if (v.listNavigator !== null) {
|
||||
v.listNavigator.nextItem();
|
||||
}
|
||||
};
|
||||
|
||||
if (
|
||||
file.mime_type.startsWith("image")
|
||||
) {
|
||||
new ImageViewer(v, file).render(v.divFilepreview);
|
||||
} else if (
|
||||
file.mime_type.startsWith("video") ||
|
||||
file.mime_type === "application/matroska" ||
|
||||
file.mime_type === "application/x-matroska"
|
||||
) {
|
||||
new VideoViewer(v, file, nextItem).render(v.divFilepreview);
|
||||
} else if (
|
||||
file.mime_type.startsWith("audio") ||
|
||||
file.mime_type === "application/ogg" ||
|
||||
file.name.endsWith(".mp3")
|
||||
) {
|
||||
new AudioViewer(v, file, nextItem).render(v.divFilepreview);
|
||||
} else if (
|
||||
file.mime_type === "application/pdf" ||
|
||||
file.mime_type === "application/x-pdf"
|
||||
) {
|
||||
new PDFViewer(v, file).render(v.divFilepreview);
|
||||
} else if (
|
||||
file.mime_type.startsWith("text") ||
|
||||
file.id === "demo"
|
||||
) {
|
||||
new TextViewer(v, file).render(v.divFilepreview);
|
||||
} else {
|
||||
new FileViewer(v, file).render(v.divFilepreview);
|
||||
break;
|
||||
case 82: // R to toggle list shuffle
|
||||
if (v.listNavigator != null) {
|
||||
v.listNavigator.toggleShuffle();
|
||||
}
|
||||
break;
|
||||
case 67: // C to copy to clipboard
|
||||
v.toolbar.copyUrl();
|
||||
break;
|
||||
case 73: // I to open the details window
|
||||
v.detailsWindow.toggle();
|
||||
break;
|
||||
case 81: // Q to close the window
|
||||
window.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
renderSponsors() {
|
||||
let scale = 1;
|
||||
let scaleWidth = 1;
|
||||
let scaleHeight = 1;
|
||||
let minWidth = 728;
|
||||
let minHeight = 800;
|
||||
|
||||
if (window.innerWidth < minWidth) {
|
||||
scaleWidth = window.innerWidth/minWidth;
|
||||
}
|
||||
if (window.innerHeight < minHeight) {
|
||||
scaleHeight = window.innerHeight/minHeight;
|
||||
}
|
||||
scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
|
||||
|
||||
// Because of the scale transformation the automatic margins don't work
|
||||
// anymore. So we have to maunally calculate the margin. Where we take the
|
||||
// width of the viewport - the width of the ad to calculate the amount of
|
||||
// pixels around the ad. We multiply the ad size by the scale we calcualted
|
||||
// to account for the smaller size.
|
||||
let offset = (window.innerWidth - (minWidth*scale)) / 2
|
||||
if (offset < 0) {
|
||||
offset = 0
|
||||
}
|
||||
document.querySelector(".sponsors > iframe").style.marginLeft = offset+"px";
|
||||
|
||||
if (scale == 1) {
|
||||
document.querySelector(".sponsors > iframe").style.transform = "none";
|
||||
document.querySelector(".sponsors").style.height = "90px";
|
||||
} else {
|
||||
document.querySelector(".sponsors > iframe").style.transform = "scale("+scale+")";
|
||||
document.querySelector(".sponsors").style.height = (scale*90)+"px";
|
||||
}
|
||||
}
|
||||
|
||||
keyboardEvent(evt) {let v = this;
|
||||
if (evt.ctrlKey || evt.altKey) {
|
||||
return // prevent custom shortcuts from interfering with system shortcuts
|
||||
}
|
||||
|
||||
switch (evt.which) {
|
||||
case 65: // A or left arrow key go to previous file
|
||||
case 37:
|
||||
if (v.listNavigator != null) {
|
||||
v.listNavigator.previousItem();
|
||||
}
|
||||
break;
|
||||
case 68: // D or right arrow key go to next file
|
||||
case 39:
|
||||
if (v.listNavigator != null) {
|
||||
v.listNavigator.nextItem();
|
||||
}
|
||||
break;
|
||||
case 83:
|
||||
if (evt.shiftKey) {
|
||||
v.listNavigator.downloadList(); // SHIFT + S downloads all files in list
|
||||
} else {
|
||||
v.toolbar.download(); // S to download the current file
|
||||
}
|
||||
break;
|
||||
case 82: // R to toggle list shuffle
|
||||
if (v.listNavigator != null) {
|
||||
v.listNavigator.toggleShuffle();
|
||||
}
|
||||
break;
|
||||
case 67: // C to copy to clipboard
|
||||
v.toolbar.copyUrl();
|
||||
break;
|
||||
case 73: // I to open the details window
|
||||
v.detailsWindow.toggle();
|
||||
break;
|
||||
case 81: // Q to close the window
|
||||
window.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Against XSS attacks
|
||||
function escapeHTML(str) {
|
||||
|
@@ -1,35 +1,33 @@
|
||||
class AudioViewer {
|
||||
constructor(viewer, file, next) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
v.next = next;
|
||||
function AudioViewer(viewer, file, next) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
v.next = next;
|
||||
|
||||
v.container = document.createElement("div");
|
||||
v.container.classList = "image-container";
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container = document.createElement("div");
|
||||
v.container.classList = "image-container";
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
|
||||
v.icon = document.createElement("img");
|
||||
v.icon.src = "/res/img/mime/audio.png";
|
||||
v.container.appendChild(v.icon);
|
||||
v.icon = document.createElement("img");
|
||||
v.icon.src = "/res/img/mime/audio.png";
|
||||
v.container.appendChild(v.icon);
|
||||
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createTextNode(file.name));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createTextNode(file.name));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
|
||||
v.element = document.createElement("audio");
|
||||
v.element.autoplay = "autoplay";
|
||||
v.element.controls = "controls";
|
||||
v.element.style.width = "90%";
|
||||
v.element.addEventListener("ended", () => { v.next(); }, false);
|
||||
v.element = document.createElement("audio");
|
||||
v.element.autoplay = "autoplay";
|
||||
v.element.controls = "controls";
|
||||
v.element.style.width = "90%";
|
||||
v.element.addEventListener("ended", () => { v.next(); }, false);
|
||||
|
||||
v.source = document.createElement("source");
|
||||
v.source.src = apiEndpoint+"/file/"+v.file.id;
|
||||
v.element.appendChild(v.source);
|
||||
v.container.appendChild(v.element);
|
||||
}
|
||||
|
||||
render(parent) {let v = this;
|
||||
parent.appendChild(v.container);
|
||||
}
|
||||
v.source = document.createElement("source");
|
||||
v.source.src = apiEndpoint+"/file/"+v.file.id;
|
||||
v.element.appendChild(v.source);
|
||||
v.container.appendChild(v.element);
|
||||
}
|
||||
|
||||
AudioViewer.prototype.render = function(parent) {let v = this;
|
||||
parent.appendChild(v.container);
|
||||
}
|
||||
|
@@ -1,29 +1,27 @@
|
||||
class FileViewer {
|
||||
constructor(viewer, file, next) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
v.next = next;
|
||||
function FileViewer(viewer, file, next) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
v.next = next;
|
||||
|
||||
v.container = document.createElement("div");
|
||||
v.container.classList = "image-container";
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container = document.createElement("div");
|
||||
v.container.classList = "image-container";
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
|
||||
v.icon = document.createElement("img");
|
||||
v.icon.src = apiEndpoint+"/"+file.thumbnail_href;
|
||||
v.container.appendChild(v.icon);
|
||||
v.icon = document.createElement("img");
|
||||
v.icon.src = apiEndpoint+"/"+file.thumbnail_href;
|
||||
v.container.appendChild(v.icon);
|
||||
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createTextNode(file.name));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createTextNode("Type: "+file.mime_type));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createTextNode(
|
||||
"Press the 'Download' button in the menu to download this file"
|
||||
));
|
||||
}
|
||||
|
||||
render(parent) {let v = this;
|
||||
parent.appendChild(v.container);
|
||||
}
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createTextNode(file.name));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createTextNode("Type: "+file.mime_type));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createElement("br"));
|
||||
v.container.appendChild(document.createTextNode(
|
||||
"Press the 'Download' button in the menu to download this file"
|
||||
));
|
||||
}
|
||||
|
||||
FileViewer.prototype.render = function(parent) {let v = this;
|
||||
parent.appendChild(v.container);
|
||||
}
|
||||
|
@@ -1,90 +1,88 @@
|
||||
class ImageViewer {
|
||||
constructor(viewer, file) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
v.zoomed = false;
|
||||
v.x = 0;
|
||||
v.y = 0;
|
||||
v.dragging = false;
|
||||
function ImageViewer(viewer, file) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
v.zoomed = false;
|
||||
v.x = 0;
|
||||
v.y = 0;
|
||||
v.dragging = false;
|
||||
|
||||
v.container = document.createElement("dv");
|
||||
v.container.classList = "image-container";
|
||||
// v.container.style.lineHeight = "0";
|
||||
v.container = document.createElement("dv");
|
||||
v.container.classList = "image-container";
|
||||
// v.container.style.lineHeight = "0";
|
||||
|
||||
v.element = document.createElement("img");
|
||||
v.element.classList = "pannable center drop-shadow";
|
||||
v.element.src = apiEndpoint+"/file/"+v.file.id;
|
||||
v.element.addEventListener("dblclick", (e) => { return v.doubleclick(e); });
|
||||
v.element.addEventListener("doubletap", (e) => { return v.doubleclick(e); });
|
||||
v.element.addEventListener("mousedown", (e) => { return v.mousedown(e); });
|
||||
document.addEventListener("mousemove", (e) => { return v.mousemove(e); });
|
||||
document.addEventListener("mouseup", (e) => { return v.mouseup(e); });
|
||||
v.element = document.createElement("img");
|
||||
v.element.classList = "pannable center drop-shadow";
|
||||
v.element.src = apiEndpoint+"/file/"+v.file.id;
|
||||
v.element.addEventListener("dblclick", (e) => { return v.doubleclick(e); });
|
||||
v.element.addEventListener("doubletap", (e) => { return v.doubleclick(e); });
|
||||
v.element.addEventListener("mousedown", (e) => { return v.mousedown(e); });
|
||||
document.addEventListener("mousemove", (e) => { return v.mousemove(e); });
|
||||
document.addEventListener("mouseup", (e) => { return v.mouseup(e); });
|
||||
|
||||
v.container.appendChild(v.element);
|
||||
v.container.appendChild(v.element);
|
||||
}
|
||||
|
||||
ImageViewer.prototype.render = function(parent) {let v = this;
|
||||
parent.appendChild(v.container);
|
||||
}
|
||||
|
||||
ImageViewer.prototype.doubleclick = function(e) {let v = this;
|
||||
if (v.zoomed) {
|
||||
v.element.style.maxWidth = "100%";
|
||||
v.element.style.maxHeight = "100%";
|
||||
v.element.style.top = "50%";
|
||||
v.element.style.left = "auto";
|
||||
v.element.style.transform = "translateY(-50%)";
|
||||
v.container.style.overflow = "hidden";
|
||||
v.zoomed = false;
|
||||
} else {
|
||||
v.element.style.maxWidth = "none";
|
||||
v.element.style.maxHeight = "none";
|
||||
v.element.style.top = "0";
|
||||
v.element.style.left = "";
|
||||
v.element.style.transform = "none";
|
||||
v.container.style.overflow = "scroll";
|
||||
v.zoomed = true;
|
||||
}
|
||||
|
||||
render(parent) {let v = this;
|
||||
parent.appendChild(v.container);
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
doubleclick(e) {let v = this;
|
||||
if (v.zoomed) {
|
||||
v.element.style.maxWidth = "100%";
|
||||
v.element.style.maxHeight = "100%";
|
||||
v.element.style.top = "50%";
|
||||
v.element.style.left = "auto";
|
||||
v.element.style.transform = "translateY(-50%)";
|
||||
v.container.style.overflow = "hidden";
|
||||
v.zoomed = false;
|
||||
} else {
|
||||
v.element.style.maxWidth = "none";
|
||||
v.element.style.maxHeight = "none";
|
||||
v.element.style.top = "0";
|
||||
v.element.style.left = "";
|
||||
v.element.style.transform = "none";
|
||||
v.container.style.overflow = "scroll";
|
||||
v.zoomed = true;
|
||||
}
|
||||
ImageViewer.prototype.mousedown = function(e) {let v = this;
|
||||
if (!v.dragging && e.which === 1 && v.zoomed) {
|
||||
v.x = e.pageX;
|
||||
v.y = e.pageY;
|
||||
v.dragging = true;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ImageViewer.prototype.mousemove = function(e) {let v = this;
|
||||
if (v.dragging) {
|
||||
v.container.scrollLeft = v.container.scrollLeft - (e.pageX - v.x);
|
||||
v.container.scrollTop = v.container.scrollTop - (e.pageY - v.y);
|
||||
|
||||
v.x = e.pageX;
|
||||
v.y = e.pageY;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
mousedown(e) {let v = this;
|
||||
if (!v.dragging && e.which === 1 && v.zoomed) {
|
||||
v.x = e.pageX;
|
||||
v.y = e.pageY;
|
||||
v.dragging = true;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ImageViewer.prototype.mouseup = function(e) {let v = this;
|
||||
if (v.dragging) {
|
||||
v.dragging = false;
|
||||
|
||||
mousemove(e) {let v = this;
|
||||
if (v.dragging) {
|
||||
v.container.scrollLeft = v.container.scrollLeft - (e.pageX - v.x);
|
||||
v.container.scrollTop = v.container.scrollTop - (e.pageY - v.y);
|
||||
|
||||
v.x = e.pageX;
|
||||
v.y = e.pageY;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mouseup(e) {let v = this;
|
||||
if (v.dragging) {
|
||||
v.dragging = false;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,13 @@
|
||||
class PDFViewer {
|
||||
constructor(viewer, file) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
function PDFViewer(viewer, file) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
|
||||
v.container = document.createElement("iframe");
|
||||
v.container.classList = "image-container";
|
||||
v.container.style.border = "none";
|
||||
v.container.src = "/res/misc/pdf-viewer/web/viewer.html?file="+apiEndpoint+"/file/"+file.id;
|
||||
}
|
||||
|
||||
render(parent) {let v = this;
|
||||
parent.appendChild(v.container);
|
||||
}
|
||||
v.container = document.createElement("iframe");
|
||||
v.container.classList = "image-container";
|
||||
v.container.style.border = "none";
|
||||
v.container.src = "/res/misc/pdf-viewer/web/viewer.html?file="+apiEndpoint+"/file/"+file.id;
|
||||
}
|
||||
|
||||
PDFViewer.prototype.render = function(parent) {let v = this;
|
||||
parent.appendChild(v.container);
|
||||
}
|
||||
|
@@ -1,58 +1,56 @@
|
||||
class TextViewer {
|
||||
constructor(viewer, file) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
v.pre = null;
|
||||
v.prettyprint = null;
|
||||
function TextViewer(viewer, file) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
v.pre = null;
|
||||
v.prettyprint = null;
|
||||
|
||||
v.container = document.createElement("div");
|
||||
v.container.classList = "text-container";
|
||||
v.container = document.createElement("div");
|
||||
v.container.classList = "text-container";
|
||||
|
||||
if (file.name.endsWith(".md") || file.name.endsWith(".markdown") || file.id === "demo") {
|
||||
v.getMarkdown();
|
||||
} else {
|
||||
v.getText();
|
||||
}
|
||||
}
|
||||
|
||||
getText() {let v = this;
|
||||
v.pre = document.createElement("pre");
|
||||
v.pre.classList = "pre-container prettyprint linenums";
|
||||
v.pre.innerText = "Loading...";
|
||||
v.container.appendChild(v.pre);
|
||||
|
||||
if (v.file.size > 1<<22) { // File larger than 4 MiB
|
||||
v.pre.innerText = "File is too large to view online.\nPlease download and view it locally.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(apiEndpoint+"/file/"+v.file.id).then(resp => {
|
||||
if (!resp.ok) { return Promise.reject(resp.status); }
|
||||
return resp.text();
|
||||
}).then(resp => {
|
||||
v.pre.innerText = resp;
|
||||
|
||||
// Load prettyprint script
|
||||
v.prettyprint = document.createElement("script");
|
||||
v.prettyprint.src = "https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=desert";
|
||||
v.container.appendChild(v.prettyprint);
|
||||
}).catch(err => {
|
||||
v.pre.innerText = "Error loading file: "+err;
|
||||
});
|
||||
}
|
||||
|
||||
getMarkdown() {let v = this;
|
||||
fetch("/u/"+v.file.id+"/preview").then(resp => {
|
||||
if (!resp.ok) { return Promise.reject(resp.status); }
|
||||
return resp.text();
|
||||
}).then(resp => {
|
||||
v.container.innerHTML = resp;
|
||||
}).catch(err => {
|
||||
v.container.innerText = "Error loading file: "+err;
|
||||
});
|
||||
}
|
||||
|
||||
render(parent) {let v = this;
|
||||
parent.appendChild(v.container);
|
||||
if (file.name.endsWith(".md") || file.name.endsWith(".markdown") || file.id === "demo") {
|
||||
v.getMarkdown();
|
||||
} else {
|
||||
v.getText();
|
||||
}
|
||||
}
|
||||
|
||||
TextViewer.prototype.getText = function() {let v = this;
|
||||
v.pre = document.createElement("pre");
|
||||
v.pre.classList = "pre-container prettyprint linenums";
|
||||
v.pre.innerText = "Loading...";
|
||||
v.container.appendChild(v.pre);
|
||||
|
||||
if (v.file.size > 1<<22) { // File larger than 4 MiB
|
||||
v.pre.innerText = "File is too large to view online.\nPlease download and view it locally.";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(apiEndpoint+"/file/"+v.file.id).then(resp => {
|
||||
if (!resp.ok) { return Promise.reject(resp.status); }
|
||||
return resp.text();
|
||||
}).then(resp => {
|
||||
v.pre.innerText = resp;
|
||||
|
||||
// Load prettyprint script
|
||||
v.prettyprint = document.createElement("script");
|
||||
v.prettyprint.src = "https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=desert";
|
||||
v.container.appendChild(v.prettyprint);
|
||||
}).catch(err => {
|
||||
v.pre.innerText = "Error loading file: "+err;
|
||||
});
|
||||
}
|
||||
|
||||
TextViewer.prototype.getMarkdown = function() {let v = this;
|
||||
fetch("/u/"+v.file.id+"/preview").then(resp => {
|
||||
if (!resp.ok) { return Promise.reject(resp.status); }
|
||||
return resp.text();
|
||||
}).then(resp => {
|
||||
v.container.innerHTML = resp;
|
||||
}).catch(err => {
|
||||
v.container.innerText = "Error loading file: "+err;
|
||||
});
|
||||
}
|
||||
|
||||
TextViewer.prototype.render = function(parent) {let v = this;
|
||||
parent.appendChild(v.container);
|
||||
}
|
||||
|
@@ -1,26 +1,24 @@
|
||||
class VideoViewer {
|
||||
constructor(viewer, file, next) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
v.next = next;
|
||||
function VideoViewer(viewer, file, next) {let v = this;
|
||||
v.viewer = viewer;
|
||||
v.file = file;
|
||||
v.next = next;
|
||||
|
||||
v.vidContainer = document.createElement("div");
|
||||
v.vidContainer.classList = "image-container";
|
||||
v.vidContainer = document.createElement("div");
|
||||
v.vidContainer.classList = "image-container";
|
||||
|
||||
v.vidElement = document.createElement("video");
|
||||
v.vidElement.autoplay = "autoplay";
|
||||
v.vidElement.controls = "controls";
|
||||
v.vidElement.classList = "center drop-shadow";
|
||||
v.vidElement.addEventListener("ended", () => { v.next(); }, false);
|
||||
v.vidElement = document.createElement("video");
|
||||
v.vidElement.autoplay = "autoplay";
|
||||
v.vidElement.controls = "controls";
|
||||
v.vidElement.classList = "center drop-shadow";
|
||||
v.vidElement.addEventListener("ended", () => { v.next(); }, false);
|
||||
|
||||
v.videoSource = document.createElement("source");
|
||||
v.videoSource.src = apiEndpoint+"/file/"+v.file.id;
|
||||
v.videoSource = document.createElement("source");
|
||||
v.videoSource.src = apiEndpoint+"/file/"+v.file.id;
|
||||
|
||||
v.vidElement.appendChild(v.videoSource);
|
||||
v.vidContainer.appendChild(v.vidElement);
|
||||
}
|
||||
|
||||
render(parent) {let v = this;
|
||||
parent.appendChild(v.vidContainer);
|
||||
}
|
||||
v.vidElement.appendChild(v.videoSource);
|
||||
v.vidContainer.appendChild(v.vidElement);
|
||||
}
|
||||
|
||||
VideoViewer.prototype.render = function(parent) {let v = this;
|
||||
parent.appendChild(v.vidContainer);
|
||||
}
|
||||
|
@@ -1,72 +1,70 @@
|
||||
class UploadProgressBar {
|
||||
constructor(uploadManager, queueDiv, file){
|
||||
this.uploadManager = uploadManager;
|
||||
this.file = file;
|
||||
this.name = file.name;
|
||||
function UploadProgressBar(uploadManager, queueDiv, file){let upb = this;
|
||||
upb.uploadManager = uploadManager;
|
||||
upb.file = file;
|
||||
upb.name = file.name;
|
||||
|
||||
this.uploadDiv = document.createElement("a");
|
||||
this.uploadDiv.classList.add("file_button");
|
||||
this.uploadDiv.style.opacity = "0";
|
||||
this.uploadDiv.innerText = "Queued\n" + this.file.name;
|
||||
queueDiv.appendChild(this.uploadDiv);
|
||||
upb.uploadDiv = document.createElement("a");
|
||||
upb.uploadDiv.classList.add("file_button");
|
||||
upb.uploadDiv.style.opacity = "0";
|
||||
upb.uploadDiv.innerText = "Queued\n" + upb.file.name;
|
||||
queueDiv.appendChild(upb.uploadDiv);
|
||||
|
||||
// Start uploading the file
|
||||
let that = this;
|
||||
this.uploadManager.addFile(
|
||||
this.file,
|
||||
this.name,
|
||||
function(progress) { that.onProgress(progress); },
|
||||
function(id) { that.onFinished(id); },
|
||||
function(val, msg) { that.onFailure(val, msg); }
|
||||
);
|
||||
// Start uploading the file
|
||||
upb.uploadManager.addFile(
|
||||
upb.file,
|
||||
upb.name,
|
||||
function(progress) { upb.onProgress(progress); },
|
||||
function(id) { upb.onFinished(id); },
|
||||
function(val, msg) { upb.onFailure(val, msg); }
|
||||
);
|
||||
|
||||
// Browsers don't render the transition if the opacity is set and
|
||||
// updated in the same frame. So we have to wait a frame (or more)
|
||||
// before changing the opacity to make sure the transition triggers
|
||||
var d = this.uploadDiv // `this` stops working after constructor ends
|
||||
window.setTimeout(function(){d.style.opacity = "1";}, 100)
|
||||
}
|
||||
|
||||
onProgress(progress){
|
||||
this.uploadDiv.innerText = "Uploading... " + Math.round(progress*1000)/10 + "%\n" + this.name
|
||||
this.uploadDiv.style.background = 'linear-gradient('
|
||||
+'to right, '
|
||||
+'var(--file_background_color) 0%, '
|
||||
+'var(--highlight_color) '+ ((progress*100)) +'%, '
|
||||
+'var(--file_background_color) '+ ((progress*100)+1) +'%)'
|
||||
}
|
||||
onFinished(id){
|
||||
console.log("Upload finished: "+this.file.name+" "+id);
|
||||
|
||||
this.uploadDiv.style.background = 'var(--file_background_color)'
|
||||
this.uploadDiv.href = '/u/'+id
|
||||
this.uploadDiv.target= "_blank"
|
||||
|
||||
let fileImg = document.createElement("img")
|
||||
fileImg.src = apiEndpoint+'/file/'+id+'/thumbnail'
|
||||
fileImg.alt = this.file.name
|
||||
|
||||
let linkSpan = document.createElement("span")
|
||||
linkSpan.style.color = "var(--highlight_color)"
|
||||
linkSpan.innerText = domainURL()+"/u/"+id
|
||||
|
||||
this.uploadDiv.innerHTML = "" // Remove uploading progress
|
||||
this.uploadDiv.appendChild(fileImg)
|
||||
this.uploadDiv.appendChild(document.createTextNode(this.file.name))
|
||||
this.uploadDiv.appendChild(document.createElement("br"))
|
||||
this.uploadDiv.appendChild(linkSpan)
|
||||
}
|
||||
onFailure(error) {
|
||||
this.uploadDiv.innerHTML = "" // Remove uploading progress
|
||||
this.uploadDiv.style.background = 'var(--danger_color)'
|
||||
this.uploadDiv.appendChild(document.createTextNode(this.file.name))
|
||||
this.uploadDiv.appendChild(document.createElement("br"))
|
||||
this.uploadDiv.appendChild(document.createTextNode("Upload failed after three tries:"))
|
||||
this.uploadDiv.appendChild(document.createElement("br"))
|
||||
this.uploadDiv.appendChild(document.createTextNode(error))
|
||||
}
|
||||
// Browsers don't render the transition if the opacity is set and
|
||||
// updated in the same frame. So we have to wait a frame (or more)
|
||||
// before changing the opacity to make sure the transition triggers
|
||||
var d = this.uploadDiv // `this` stops working after constructor ends
|
||||
window.setTimeout(function(){d.style.opacity = "1";}, 100)
|
||||
}
|
||||
|
||||
UploadProgressBar.prototype.onProgress = function(progress){
|
||||
this.uploadDiv.innerText = "Uploading... " + Math.round(progress*1000)/10 + "%\n" + this.name
|
||||
this.uploadDiv.style.background = 'linear-gradient('
|
||||
+'to right, '
|
||||
+'var(--file_background_color) 0%, '
|
||||
+'var(--highlight_color) '+ ((progress*100)) +'%, '
|
||||
+'var(--file_background_color) '+ ((progress*100)+1) +'%)'
|
||||
}
|
||||
UploadProgressBar.prototype.onFinished = function(id){
|
||||
console.log("Upload finished: "+this.file.name+" "+id);
|
||||
|
||||
this.uploadDiv.style.background = 'var(--file_background_color)'
|
||||
this.uploadDiv.href = '/u/'+id
|
||||
this.uploadDiv.target= "_blank"
|
||||
|
||||
let fileImg = document.createElement("img")
|
||||
fileImg.src = apiEndpoint+'/file/'+id+'/thumbnail'
|
||||
fileImg.alt = this.file.name
|
||||
|
||||
let linkSpan = document.createElement("span")
|
||||
linkSpan.style.color = "var(--highlight_color)"
|
||||
linkSpan.innerText = domainURL()+"/u/"+id
|
||||
|
||||
this.uploadDiv.innerHTML = "" // Remove uploading progress
|
||||
this.uploadDiv.appendChild(fileImg)
|
||||
this.uploadDiv.appendChild(document.createTextNode(this.file.name))
|
||||
this.uploadDiv.appendChild(document.createElement("br"))
|
||||
this.uploadDiv.appendChild(linkSpan)
|
||||
}
|
||||
UploadProgressBar.prototype.onFailure = function(error) {
|
||||
this.uploadDiv.innerHTML = "" // Remove uploading progress
|
||||
this.uploadDiv.style.background = 'var(--danger_color)'
|
||||
this.uploadDiv.appendChild(document.createTextNode(this.file.name))
|
||||
this.uploadDiv.appendChild(document.createElement("br"))
|
||||
this.uploadDiv.appendChild(document.createTextNode("Upload failed after three tries:"))
|
||||
this.uploadDiv.appendChild(document.createElement("br"))
|
||||
this.uploadDiv.appendChild(document.createTextNode(error))
|
||||
}
|
||||
|
||||
|
||||
let uploader = null;
|
||||
let shareTitle = "";
|
||||
let shareLink = "";
|
||||
@@ -76,6 +74,10 @@ function handleUploads(files) {
|
||||
uploader = new UploadManager(apiEndpoint, uploadsFinished);
|
||||
}
|
||||
|
||||
if (files.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
new UploadProgressBar(
|
||||
uploader,
|
||||
@@ -143,13 +145,10 @@ function createList(title, anonymous) {
|
||||
}
|
||||
|
||||
function hideShareButtons() {
|
||||
document.getElementById("instruction_2").style.display = "";
|
||||
document.getElementById("instruction_3").style.display = "none";
|
||||
document.getElementById("instruction_3_after").style.display = "none";
|
||||
}
|
||||
|
||||
function showShareButtons() {
|
||||
document.getElementById("instruction_3").style.display = "";
|
||||
document.getElementById("instruction_3_after").style.display = "";
|
||||
|
||||
if (window.navigator && window.navigator.share) {
|
||||
@@ -350,20 +349,19 @@ btnCopyMarkdown.addEventListener("click", function(){
|
||||
/*
|
||||
* Keyboard shortcuts
|
||||
*/
|
||||
|
||||
document.addEventListener("keydown", function(event){
|
||||
if (event.ctrlKey || event.altKey) {
|
||||
return // prevent custom shortcuts from interfering with system shortcuts
|
||||
}
|
||||
if (event.which === 67 && !uploader.uploading()) { // c
|
||||
if (event.keyCode === 67) { // c
|
||||
// Copy links to clipboard
|
||||
copyLink();
|
||||
} else if (event.which === 85) { // u
|
||||
document.getElementById("btn_copy_link").click();
|
||||
} else if (event.keyCode === 85) { // u
|
||||
// Click the upload button
|
||||
document.getElementById("file_input_field").click();
|
||||
} else if (event.which === 84) { // t
|
||||
} else if (event.keyCode === 84) { // t
|
||||
// Click the text button
|
||||
document.getElementById("upload_text_button").click();
|
||||
}
|
||||
console.log(event.which)
|
||||
console.log(event.keyCode)
|
||||
});
|
||||
|
@@ -23,7 +23,7 @@ function uploadText() {
|
||||
|
||||
// Upload the file when ctrl + s is pressed
|
||||
document.addEventListener("keydown", function(event) {
|
||||
if (event.ctrlKey && (event.which === 83)) {
|
||||
if (event.ctrlKey && (event.keyCode === 83)) {
|
||||
event.preventDefault();
|
||||
uploadText();
|
||||
return false;
|
||||
|
@@ -245,23 +245,6 @@ hr{
|
||||
margin: 16px 16px 16px 16px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar{
|
||||
width: 1em; /* for vertical scrollbars */
|
||||
height: 1em; /* for horizontal scrollbars */
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--scrollbar_background_color);
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: var(--scrollbar_foreground_color);
|
||||
border-radius: 0.5em;
|
||||
border: 0.22em solid var(--scrollbar_background_color);
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: var(--scrollbar_hover_color);
|
||||
}
|
||||
::-webkit-scrollbar-corner{background: var(--scrollbar_background_color);}
|
||||
|
||||
a {color: var(--highlight_color); text-decoration: none;}
|
||||
a:hover {color: var(--highlight_color); text-decoration: underline;}
|
||||
|
||||
@@ -477,3 +460,66 @@ input[type=file]{
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/* Webkit Scrollbars */
|
||||
|
||||
::-webkit-scrollbar{
|
||||
width: 18px; /* for vertical scrollbars */
|
||||
height: 18px; /* for horizontal scrollbars */
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--scrollbar_background_color);
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: var(--scrollbar_foreground_color);
|
||||
border-radius: 10px;
|
||||
border: 5px solid var(--scrollbar_background_color);
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: var(--scrollbar_hover_color);
|
||||
}
|
||||
::-webkit-scrollbar-corner{
|
||||
background-color: var(--scrollbar_background_color);
|
||||
}
|
||||
::-webkit-scrollbar-button:single-button {
|
||||
background-color: var(--scrollbar_background_color);
|
||||
display: block;
|
||||
border-style: solid;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
::-webkit-scrollbar-button:single-button:vertical:decrement {
|
||||
border-width: 0 8px 8px 8px;
|
||||
border-color: transparent transparent var(--scrollbar_foreground_color) transparent;
|
||||
}
|
||||
::-webkit-scrollbar-button:single-button:vertical:decrement:hover {
|
||||
border-color: transparent transparent var(--scrollbar_hover_color) transparent;
|
||||
}
|
||||
::-webkit-scrollbar-button:single-button:vertical:increment {
|
||||
border-width: 8px 8px 0 8px;
|
||||
border-color: var(--scrollbar_foreground_color) transparent transparent transparent;
|
||||
}
|
||||
::-webkit-scrollbar-button:vertical:single-button:increment:hover {
|
||||
border-color: var(--scrollbar_hover_color) transparent transparent transparent;
|
||||
}
|
||||
::-webkit-scrollbar-button:single-button:horizontal:decrement {
|
||||
border-width: 8px 8px 8px 0px;
|
||||
border-color: transparent var(--scrollbar_foreground_color) transparent transparent;
|
||||
}
|
||||
::-webkit-scrollbar-button:single-button:horizontal:decrement:hover {
|
||||
border-color: transparent var(--scrollbar_hover_color) transparent transparent;
|
||||
}
|
||||
::-webkit-scrollbar-button:single-button:horizontal:increment {
|
||||
border-width: 8px 0px 8px 8px;
|
||||
border-color: transparent transparent transparent var(--scrollbar_foreground_color);
|
||||
}
|
||||
::-webkit-scrollbar-button:horizontal:single-button:increment:hover {
|
||||
border-color: transparent transparent transparent var(--scrollbar_hover_color);
|
||||
}
|
||||
|
||||
/* Firefox Scrollbar */
|
||||
|
||||
* {
|
||||
/* scrollbar-color: var(--scrollbar_foreground_color) var(--scrollbar_background_color); */
|
||||
scrollbar-color: dark;
|
||||
}
|
||||
|
@@ -48,6 +48,12 @@
|
||||
.file_viewer > .file_viewer_headerbar > .button_home::after {
|
||||
content: "pixeldrain";
|
||||
}
|
||||
.file_viewer > .file_viewer_headerbar > .button_home > svg {
|
||||
height: 1.7em;
|
||||
width: 1.7em;
|
||||
margin: -0.25em;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
@media (max-width: 500px) {
|
||||
.file_viewer > .file_viewer_headerbar > .button_home::after {
|
||||
content: "pd";
|
||||
|
@@ -24,9 +24,7 @@
|
||||
<div id="file_viewer_headerbar" class="highlight_1 file_viewer_headerbar">
|
||||
<button id="btn_toggle_toolbar" class="button_toggle_toolbar">☰</button>
|
||||
<a href="/" id="button_home" class="button button_home">
|
||||
<img src="{{template `pixeldrain_icon.png`}}"
|
||||
alt="Back to the Home page"
|
||||
style="height: 1.5em; margin: -0.2em; margin-right: 0.2em;"/>
|
||||
{{template `pixeldrain.svg` .}}
|
||||
</a>
|
||||
<div id="file_viewer_headerbar_title" class="file_viewer_headerbar_title">
|
||||
<div id="file_viewer_list_title"></div>
|
||||
@@ -153,8 +151,9 @@
|
||||
|
||||
<script src="/res/script/Chart.min.js"></script>
|
||||
<script>
|
||||
var apiEndpoint = '{{.APIEndpoint}}';
|
||||
var captchaKey = '{{.Other.CaptchaKey}}';
|
||||
'use strict';
|
||||
let apiEndpoint = '{{.APIEndpoint}}';
|
||||
let captchaKey = '{{.Other.CaptchaKey}}';
|
||||
|
||||
{{template `util.js`}}
|
||||
{{template `Toolbar.js`}}
|
||||
|
@@ -64,14 +64,14 @@
|
||||
be placed in your web browser. More information on the
|
||||
<a href="/about">about</a> page
|
||||
<p>
|
||||
<div id="instruction_2" class="instruction_highlight" style="display: none">
|
||||
<div id="instruction_2" class="instruction_highlight">
|
||||
<div class="limit_width">
|
||||
<span class="big_number">2</span><span class="instruction_text">Wait for the files to finish uploading</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="uploads_queue"></div>
|
||||
|
||||
<div id="instruction_3" class="instruction_highlight" style="display: none">
|
||||
<div id="instruction_3" class="instruction_highlight">
|
||||
<div class="limit_width"><span class="big_number">3</span><span class="instruction_text">Share the files</span></div>
|
||||
</div>
|
||||
<div id="instruction_3_after" style="display: none">
|
||||
@@ -150,10 +150,11 @@
|
||||
{{template "page_bottom"}}
|
||||
|
||||
<script>
|
||||
let apiEndpoint = '{{.APIEndpoint}}';
|
||||
{{template "util.js"}}
|
||||
{{template "UploadManager.js"}}
|
||||
{{template "homepage.js"}}
|
||||
'use strict';
|
||||
let apiEndpoint = '{{.APIEndpoint}}';
|
||||
{{template "util.js"}}
|
||||
{{template "UploadManager.js"}}
|
||||
{{template "homepage.js"}}
|
||||
</script>
|
||||
|
||||
{{template "analytics"}}
|
||||
|
Reference in New Issue
Block a user