diff --git a/res/include/img/icons/pixeldrain.svg b/res/include/img/icons/pixeldrain.svg
new file mode 100644
index 0000000..ad45108
--- /dev/null
+++ b/res/include/img/icons/pixeldrain.svg
@@ -0,0 +1,3 @@
+
diff --git a/res/include/script/dependencies/UploadManager.js b/res/include/script/dependencies/UploadManager.js
index 7e45758..7492e52 100644
--- a/res/include/script/dependencies/UploadManager.js
+++ b/res/include/script/dependencies/UploadManager.js
@@ -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);
+}
diff --git a/res/include/script/file_viewer/DetailsWindow.js b/res/include/script/file_viewer/DetailsWindow.js
index df8a5c9..f2d0a12 100644
--- a/res/include/script/file_viewer/DetailsWindow.js
+++ b/res/include/script/file_viewer/DetailsWindow.js
@@ -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 = "
"
- + "Name | | " + escapeHTML(file.name) + " |
"
- + "URL | | "+domainURL()+"/u/" + file.id + " |
"
- + "Mime Type | | " + escapeHTML(file.mime_type) + " |
"
- + "ID | | " + file.id + " |
"
- + "Size | | " + formatDataVolume(file.size, 4) + " |
"
- + "Bandwidth | | " + formatDataVolume(file.bandwidth_used, 4) + " |
"
- + "Upload Date | | " + file.date_upload + " |
"
- + "Description | | " + escapeHTML(desc) + " |
"
- + "
";
-
- 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 = ""
+ + "Name | | " + escapeHTML(file.name) + " |
"
+ + "URL | | "+domainURL()+"/u/" + file.id + " |
"
+ + "Mime Type | | " + escapeHTML(file.mime_type) + " |
"
+ + "ID | | " + file.id + " |
"
+ + "Size | | " + formatDataVolume(file.size, 4) + " |
"
+ + "Bandwidth | | " + formatDataVolume(file.bandwidth_used, 4) + " |
"
+ + "Upload Date | | " + file.date_upload + " |
"
+ + "Description | | " + escapeHTML(desc) + " |
"
+ + "
";
+
+ 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
+ }
+ }
+ ]
+ }
+ }
+ }
+ );
+}
diff --git a/res/include/script/file_viewer/ListNavigator.js b/res/include/script/file_viewer/ListNavigator.js
index bc17efe..29d9451 100644
--- a/res/include/script/file_viewer/ListNavigator.js
+++ b/res/include/script/file_viewer/ListNavigator.js
@@ -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 = "
"
+ + 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 = "
"
- + escapeHTML(name);
-
- navigatorItems[i].innerHTML = itemHtml;
- }
- }
-};
// Misc function, don't really know where else to put it
diff --git a/res/include/script/file_viewer/Toolbar.js b/res/include/script/file_viewer/Toolbar.js
index 9223a38..12d0e56 100644
--- a/res/include/script/file_viewer/Toolbar.js
+++ b/res/include/script/file_viewer/Toolbar.js
@@ -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(){
diff --git a/res/include/script/file_viewer/Viewer.js b/res/include/script/file_viewer/Viewer.js
index 6b20f41..00f7f31 100644
--- a/res/include/script/file_viewer/Viewer.js
+++ b/res/include/script/file_viewer/Viewer.js
@@ -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) {
diff --git a/res/include/script/file_viewer/viewer_scripts/AudioViewer.js b/res/include/script/file_viewer/viewer_scripts/AudioViewer.js
index 371e74f..7e638ae 100644
--- a/res/include/script/file_viewer/viewer_scripts/AudioViewer.js
+++ b/res/include/script/file_viewer/viewer_scripts/AudioViewer.js
@@ -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);
}
diff --git a/res/include/script/file_viewer/viewer_scripts/FileViewer.js b/res/include/script/file_viewer/viewer_scripts/FileViewer.js
index 46b22d9..bc5ae72 100644
--- a/res/include/script/file_viewer/viewer_scripts/FileViewer.js
+++ b/res/include/script/file_viewer/viewer_scripts/FileViewer.js
@@ -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);
}
diff --git a/res/include/script/file_viewer/viewer_scripts/ImageViewer.js b/res/include/script/file_viewer/viewer_scripts/ImageViewer.js
index 72f3893..50d3f4c 100644
--- a/res/include/script/file_viewer/viewer_scripts/ImageViewer.js
+++ b/res/include/script/file_viewer/viewer_scripts/ImageViewer.js
@@ -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;
}
}
diff --git a/res/include/script/file_viewer/viewer_scripts/PDFViewer.js b/res/include/script/file_viewer/viewer_scripts/PDFViewer.js
index 3fda0e0..17fb34a 100644
--- a/res/include/script/file_viewer/viewer_scripts/PDFViewer.js
+++ b/res/include/script/file_viewer/viewer_scripts/PDFViewer.js
@@ -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);
}
diff --git a/res/include/script/file_viewer/viewer_scripts/TextViewer.js b/res/include/script/file_viewer/viewer_scripts/TextViewer.js
index f1d18f7..2843d12 100644
--- a/res/include/script/file_viewer/viewer_scripts/TextViewer.js
+++ b/res/include/script/file_viewer/viewer_scripts/TextViewer.js
@@ -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);
+}
diff --git a/res/include/script/file_viewer/viewer_scripts/VideoViewer.js b/res/include/script/file_viewer/viewer_scripts/VideoViewer.js
index 6ef4c28..ef164d3 100644
--- a/res/include/script/file_viewer/viewer_scripts/VideoViewer.js
+++ b/res/include/script/file_viewer/viewer_scripts/VideoViewer.js
@@ -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);
}
diff --git a/res/include/script/homepage.js b/res/include/script/homepage.js
index df5d158..149866b 100644
--- a/res/include/script/homepage.js
+++ b/res/include/script/homepage.js
@@ -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)
});
diff --git a/res/include/script/textupload.js b/res/include/script/textupload.js
index 58f6e8f..e50cb4f 100644
--- a/res/include/script/textupload.js
+++ b/res/include/script/textupload.js
@@ -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;
diff --git a/res/include/style/layout.css b/res/include/style/layout.css
index 049b76d..761c255 100644
--- a/res/include/style/layout.css
+++ b/res/include/style/layout.css
@@ -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;
+}
diff --git a/res/include/style/viewer.css b/res/include/style/viewer.css
index b5ce6eb..8c3b44f 100644
--- a/res/include/style/viewer.css
+++ b/res/include/style/viewer.css
@@ -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";
diff --git a/res/template/file_viewer.html b/res/template/file_viewer.html
index c276be8..0503cfa 100644
--- a/res/template/file_viewer.html
+++ b/res/template/file_viewer.html
@@ -24,9 +24,7 @@