Embed resources into templates

This commit is contained in:
2019-12-23 23:56:57 +01:00
parent 269bf7eed1
commit 7b5723705c
87 changed files with 12669 additions and 7216 deletions

View File

@@ -0,0 +1,229 @@
/* global Viewer */
var ListNavigator = {
length: 0,
position: 0,
data: [],
history: [],
shuffle: false,
nextItem: function(){
if(!Viewer.isList){
return;
}
if(this.shuffle){
this.randItem();
return;
}
if(this.position >= this.length){
this.position = 0;
}else{
this.position++;
}
this.setItem(this.position);
},
previousItem: function(){
if(!Viewer.isList){
return;
}
if(this.position === 0){
this.position = this.length - 1;
}else{
this.position--;
}
this.setItem(this.position);
},
randItem: function(){
if(!Viewer.isList){
return;
}
// Avoid viewing the same file multiple times
var rand;
do {
rand = Math.round(Math.random() * this.length);
console.log("rand is " + rand);
} while(this.inHistory(rand));
this.setItem(rand);
},
setItem: function(index){
if(index >= this.length){
this.position = 0;
}else{
this.position = index;
}
// Set the URL hash
location.hash = "item=" + this.position;
Viewer.setFile(this.data[this.position]);
this.addToHistory(index);
$("#list_navigator").find("*").removeClass("file_button_selected");
var selectedItem = $("#list_navigator div").eq(this.position);
selectedItem.addClass("file_button_selected");
var itemWidth = selectedItem.outerWidth(true);
// This centers the scroll bar exactly on the selected item
$("#list_navigator").animate(
{scrollLeft: ((this.position * itemWidth) + (itemWidth / 2)) - ($("#list_navigator").width() / 2)},
{duration: 1000, queue: false}
);
this.loadThumbnails(index);
},
addToHistory: function(index){
if(this.history.length >= (this.length - 6)){
this.history.shift();
}
this.history.push(index);
},
inHistory: function(index){
var i = $.inArray(index, this.history); // Returns -1 when the item is not found
return (i !== -1); // Return false when it's not in the array
},
toggleShuffle: function(){
this.shuffle = !this.shuffle; // :P
if(this.shuffle){
$("#btnShuffle > span").html(" Shuffle ☑"); // Check icon
$("#btnShuffle").addClass("button_highlight");
}else{
$("#btnShuffle > span").html(" Shuffle ☐"); // Empty checkbox
$("#btnShuffle").removeClass("button_highlight");
}
},
loadThumbnails: function(index){
var startPos = +index - 50;
var 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 >= this.length){
endPos = this.length - 1;
}
console.log(endPos);
var navigatorItems = document.getElementById("list_navigator").children
for (i = startPos; i <= endPos; i++){
if (navigatorItems[i].innerHTML.includes("list_item_thumbnail")) {
continue; // Thumbnail already loaded
}
var thumb = "/api/file/" + this.data[i].id + "/thumbnail?width=48&height=48";
var name = this.data[i].name;
var itemHtml = "<img src=\"" + thumb + "\" "
+ "class=\"list_item_thumbnail\" alt=\"" + escapeHTML(name) + "\"/>"
+ escapeHTML(name);
navigatorItems[i].innerHTML = itemHtml;
}
},
init: function(data){
this.data = data;
this.length = data.length;
var listHTML = "";
data.forEach(function(item, i){
var filename;
if(item.name !== "null"){
filename = item.name;
}else{
filename = "Removed File";
}
listHTML += "<div class=\"file_button list_item\" "
+ "onClick=\"ListNavigator.setItem('" + i + "')\">"
+ escapeHTML(filename) + "<br>"
+ "</div>";
});
document.getElementById("list_navigator").innerHTML = listHTML;
var btnLastItem = document.createElement("button");
btnLastItem.innerText = "◀";
btnLastItem.setAttribute("id", "button_last_item");
btnLastItem.setAttribute("class", "button_highlight");
btnLastItem.setAttribute("onClick", "ListNavigator.previousItem();");
var btnNextItem = document.createElement("button");
btnNextItem.innerText = "▶";
btnNextItem.setAttribute("id", "button_next_item");
btnNextItem.setAttribute("class", "button_highlight");
btnNextItem.setAttribute("onClick", "ListNavigator.nextItem();");
var headerbar = document.getElementById("list_navigator_buttons");
headerbar.appendChild(btnLastItem);
headerbar.appendChild(btnNextItem);
// Add the list download button to the toolbar
var btnDownloadList = document.createElement("button");
btnDownloadList.setAttribute("id", "btnDownloadList");
btnDownloadList.setAttribute("class", "toolbar_button button_full_width");
btnDownloadList.setAttribute("onClick", "Toolbar.downloadList();");
var btnDownloadListImg = document.createElement("img");
btnDownloadListImg.setAttribute("src", "{{template `floppy_small.png`}}");
btnDownloadListImg.setAttribute("alt", "Download List");
var btnDownloadListText = document.createElement("span");
btnDownloadListText.innerHTML = "&nbsp;All Files";
btnDownloadList.appendChild(btnDownloadListImg);
btnDownloadList.appendChild(btnDownloadListText);
document.getElementById("btnDownload").after(btnDownloadList);
// Add the shuffle button to the toolbar
var btnShuffle = document.createElement("button");
btnShuffle.setAttribute("id", "btnShuffle");
btnShuffle.setAttribute("class", "toolbar_button button_full_width");
btnShuffle.setAttribute("onClick", "ListNavigator.toggleShuffle();");
var btnShuffleImg = document.createElement("img");
btnShuffleImg.setAttribute("src", "{{template `shuffle_small.png`}}");
btnShuffleImg.setAttribute("alt", "Shuffle playback order");
var btnShuffleText = document.createElement("span");
btnShuffleText.innerHTML = "&nbsp;Shuffle&nbsp;&#x2610;";
btnShuffle.appendChild(btnShuffleImg);
btnShuffle.appendChild(btnShuffleText);
document.getElementById("btnShare").after(btnShuffle);
// Make the navigator visible
document.getElementById("list_navigator").style.display = "inline-block";
// Skip to the file defined in the link hash
if(Number.isInteger(parseInt(getHashValue("item")))){
this.setItem(parseInt(getHashValue("item")));
}else{
this.setItem(0);
}
}
};
// Misc function, don't really know where else to put it
function getHashValue(key) {
var matches = location.hash.match(new RegExp(key + '=([^&]*)'));
return matches ? matches[1] : null;
}

View File

@@ -0,0 +1,343 @@
/*
* Time for a more Java-like approach.
*
* Feel free to use this of course
*
* Made by Fornax
*/
/* global Viewer */
var Toolbar = {
visible: false,
toggle: function () {
if (this.visible) {
if (Sharebar.visible) {
Sharebar.toggle();
}
document.getElementById("toolbar").style.left = "-8em";
document.getElementById("filepreview").style.left = "0px";
document.getElementById("button_toggle_toolbar").classList.remove("button_highlight");
this.visible = false;
} else {
document.getElementById("toolbar").style.left = "0px";
document.getElementById("filepreview").style.left = "8em";
document.getElementById("button_toggle_toolbar").classList.add("button_highlight");
this.visible = true;
}
},
download: function () {
var triggerDL = function(){
document.getElementById("download_frame").src = "/api/file/" + Viewer.currentFile + "?download";
}
if (captchaKey === "a"){
// If the server doesn't support captcha there's no use in checking
// availability
triggerDL();
return;
}
$.getJSON(
apiEndpoint + "/file/" + Viewer.currentFile + "/availability"
).done(function(data){
if(data.success === true){
// Downloading is allowed, start the download
triggerDL();
}
}).fail(function(data){
if(data.responseJSON.success === false) {
var popupDiv = document.getElementById("captcha_popup");
var popupTitle = document.getElementById("captcha_popup_title");
var popupContent = document.getElementById("captcha_popup_content");
var popupCaptcha = document.getElementById("captcha_popup_captcha");
if(data.responseJSON.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.";
}else if(data.responseJSON.value === "virus_detected_captcha_required"){
popupTitle.innerText = "Malware warning!";
popupContent.innerText = "According to our scanning "+
"systems this file may contain a virus of type '"+
data.responseJSON.extra+"'. You can continue "+
"downloading this file at your own risk, but you will "+
"have to prove that you're a human first.";
}
// Load the recaptcha script with a load function
$.getScript("https://www.google.com/recaptcha/api.js?onload=loadCaptcha&render=explicit");
popupDiv.style.opacity = "1";
popupDiv.style.visibility = "visible";
}else{
// No JSON, try download anyway
triggerDL();
}
});
},
downloadList: function(){
if(!Viewer.isList){
return;
}
document.getElementById("download_frame").src = "/api/list/" + Viewer.listId + "/zip";
},
copyUrl: function () {
if(copyText(window.location.href)) {
console.log('Text copied');
$("#btnCopy>span").text("Copied!");
document.getElementById("btnCopy").classList.add("button_highlight")
} else {
console.log('Copying not supported');
$("#btnCopy>span").text("Error!");
alert("Your browser does not support copying text.");
}
// Return to normal
setTimeout(function(){
$("#btnCopy>span").text("Copy");
document.getElementById("btnCopy").classList.remove("button_highlight")
}, 60000);
},
setStats: function(views, downloads){
document.getElementById("stat_views").innerText = views
document.getElementById("stat_downloads").innerText = Math.round(downloads*10)/10;
}
};
var Sharebar = {
visible: false,
toggle: function(){
if (navigator.share) {
navigator.share({
title: Viewer.title,
text: "Download " + Viewer.title + " here",
url: window.location.href
});
return;
}
if (!Toolbar.visible){
Toolbar.toggle();
}
if(this.visible){
document.getElementById("sharebar").style.left = "-8em";
document.getElementById("btnShare").classList.remove("button_highlight")
this.visible = false;
}else{
document.getElementById("sharebar").style.left = "8em";
document.getElementById("btnShare").classList.add("button_highlight")
this.visible = true;
}
}
};
function copyText(text) {
// Create a textarea to copy the text from
var ta = document.createElement("textarea");
ta.setAttribute("readonly", "readonly")
ta.style.position = "absolute";
ta.style.left = "-9999px";
ta.value = text; // Put the text in the textarea
// Add the textarea to the DOM so it can be seleted by the user
document.body.appendChild(ta);
ta.select(); // Select the contents of the textarea
var success = document.execCommand("copy"); // Copy the selected text
document.body.removeChild(ta); // Remove the textarea
return success;
}
function loadCaptcha(){
grecaptcha.render("captcha_popup_captcha", {
sitekey: captchaKey,
theme: "dark",
callback: function(token){
document.getElementById("download_frame").src = "/api/file/" + Viewer.currentFile +
"?download&recaptcha_response="+token;
setTimeout(function(){
var popupDiv = document.getElementById("captcha_popup");
popupDiv.style.opacity = "0";
popupDiv.style.visibility = "hidden";
}, 1000)
}
});
}
var DetailsWindow = {
visible: false,
fileID: "",
graph: 0,
popupDiv: document.getElementById("details_popup"),
detailsButton: document.getElementById("btnDetails"),
toggle: function () {
if (this.visible) {
this.popupDiv.style.opacity = "0"
this.popupDiv.style.visibility = "hidden"
this.detailsButton.classList.remove("button_highlight")
this.visible = false;
} else {
this.popupDiv.style.opacity = "1"
this.popupDiv.style.visibility = "visible"
this.detailsButton.classList.add("button_highlight")
this.visible = true;
// This is a workaround for a chrome bug which makes it so hidden
// windows can't be scrolled after they are shown
this.popupDiv.focus();
if (this.graph === 0) {
this.renderGraph();
}
this.updateGraph(this.fileID);
}
},
setDetails: function (file) {
var that = this;
if (Viewer.isList) {
// Lists give incomplete file information, so we have to request
// more details in the background. File descriptions only exist in
// lists, so for that we use the data provided in the page source
$.ajax({
dataType: "json",
url: apiEndpoint + "/file/" + file.id + "/info",
success: function(data){
that.fileID = data.id;
$("#info_file_details").html(
"<table>"
+ "<tr><td>Name<td><td>" + escapeHTML(data.name) + "</td></tr>"
+ "<tr><td>URL<td><td><a href=\"/u/" + data.id + "\">/u/" + data.id + "</a></td></tr>"
+ "<tr><td>Mime Type<td><td>" + escapeHTML(data.mime_type) + "</td></tr>"
+ "<tr><td>ID<td><td>" + data.id + "</td></tr>"
+ "<tr><td>Size<td><td class=\"bytecounter\">" + data.size + "</td></tr>"
+ "<tr><td>Bandwidth<td><td class=\"bytecounter\">" + data.bandwidth_used + "</td></tr>"
+ "<tr><td>Upload Date<td><td>" + data.date_upload + "</td></tr>"
+ "<tr><td>Description<td><td>" + escapeHTML(file.description) + "</td></tr>"
+ "</table>"
);
Toolbar.setStats(data.views, data.bandwidth_used/data.size);
if(that.visible) {
that.updateGraph(that.fileID);
}
}
});
} else {
this.fileID = file.id;
$("#info_file_details").html(
"<table>"
+ "<tr><td>Name<td><td>" + escapeHTML(file.name) + "</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 class=\"bytecounter\">" + file.size + "</td></tr>"
+ "<tr><td>Bandwidth<td><td class=\"bytecounter\">" + file.bandwidth_used + "</td></tr>"
+ "<tr><td>Upload Date<td><td>" + file.date_upload + "</td></tr>"
+ "</table>"
);
Toolbar.setStats(file.views, file.bandwidth_used/file.size);
if(this.visible) {
this.updateGraph(file.id);
}
}
},
updateGraph: function(fileID) {
var that = this;
console.log("updating graph "+fileID);
$.get(apiEndpoint+"/file/" + fileID + "/timeseries?interval=60?days=14", function(response){
console.log(response);
if (response.success) {
that.graph.data.labels = response.labels;
that.graph.data.datasets[0].data = response.downloads;
that.graph.data.datasets[1].data = response.views;
that.graph.update();
}
});
},
renderGraph: function() {
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;
this.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
}
}
]
}
}
}
);
}
};

View File

@@ -0,0 +1,106 @@
/* global ListNavigator, Toolbar, DetailsWindow */
var Viewer = {
currentFile: "",
title: "", // Contains either the file name or list title
listId: "",
isList: false,
isFile: false,
initialized: false,
init: function(type, data){
if(this.initialized){
return;
}
// On small screens the toolbar takes too much space, so it collapses automatically
if($("#filepreview").width() > 500 && !Toolbar.visible){
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) {
$("#button_close_file_viewer").remove();
}
if(type === "file"){
this.isFile = true;
this.currentFile = data.id;
this.title = data.name;
this.setFile(data);
} else if (type === "list") {
this.isList = true;
this.listId = data.id;
this.title = data.title;
ListNavigator.init(data.data);
}
this.initialized = true;
},
setFile: function(file){
this.currentFile = file.id;
var title = "";
if (this.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 = this.title + " ~ " + file.name + " ~ PixelDrain";
} else {
document.getElementById("file_viewer_file_title").innerText = file.name;
document.title = file.name + " ~ PixelDrain";
}
$.get("/u/" + file.id + "/preview", function(response){
$("#filepreview").html(response);
});
DetailsWindow.setDetails(file);
}
};
// Against XSS attacks
function escapeHTML(str) {
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
// Register keyboard shortcuts
document.addEventListener("keydown", function(event){
if (event.ctrlKey || event.altKey) {
return // prevent custom shortcuts from interfering with system shortcuts
}
switch (event.which) {
case 65: // A or left arrow key go to previous file
case 37:
ListNavigator.previousItem();
break;
case 68: // D or right arrow key go to next file
case 39:
ListNavigator.nextItem();
break;
case 83:
if (event.shiftKey) {
Toolbar.downloadList(); // SHIFT + S downloads all files in list
} else {
Toolbar.download(); // S to download the current file
}
break;
case 82: // R to toggle list shuffle
ListNavigator.toggleShuffle();
break;
case 67: // C to copy to clipboard
Toolbar.copyUrl();
break;
case 73: // I to open the details window
DetailsWindow.toggle();
break;
case 81: // Q to close the window
window.close();
break;
}
});

View File

@@ -0,0 +1,385 @@
var FinishedUpload = /** @class */ (function () {
function FinishedUpload() {
}
return FinishedUpload;
}());
var uploader = null;
var finishedUploads = new Array();
var totalUploads = 0;
var queueDiv = document.getElementById("uploads_queue");
var UploadProgressBar = /** @class */ (function () {
function UploadProgressBar(file) {
this.file = file;
this.name = file.name;
this.queueNum = totalUploads;
this.uploadDiv = document.createElement("a");
totalUploads++;
this.uploadDiv.classList.add("file_button");
this.uploadDiv.style.opacity = "0";
this.uploadDiv.innerText = "Queued\n" + this.file.name;
queueDiv.appendChild(this.uploadDiv);
// 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.file.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) {
finishedUploads[this.queueNum] = {
id: id,
name: this.file.name
};
this.uploadDiv.style.background = 'var(--file_background_color)';
this.uploadDiv.href = '/u/' + id;
this.uploadDiv.target = "_blank";
var fileImg = document.createElement("img");
fileImg.src = apiEndpoint + '/file/' + id + '/thumbnail';
fileImg.alt = this.file.name;
var linkSpan = document.createElement("span");
linkSpan.style.color = "var(--highlight_color)";
linkSpan.innerText = window.location.hostname + "/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));
};
return UploadProgressBar;
}());
function handleUploads(files) {
if (uploader === null) {
uploader = new UploadManager();
}
for (var i = 0; i < files.length; i++) {
uploader.uploadFile(new UploadProgressBar(files.item(i)));
}
}
// List creation
function createList(title, anonymous) {
if (uploader.uploading()) {
var cont = confirm("Some files have not finished uploading yet. Creating a list now " +
"will exclude those files.\n\nContinue?");
if (!cont) {
return;
}
}
var postData = {
"title": title,
"anonymous": anonymous,
"files": new Array()
};
for (var i = 0; i < finishedUploads.length; i++) {
postData.files.push({
"id": finishedUploads[i].id
});
}
var xhr = new XMLHttpRequest();
xhr.open("POST", apiEndpoint + "/list");
xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) {
return;
}
var resp = JSON.parse(xhr.response);
if (xhr.status < 400) {
// Request is a success
var div = document.createElement("div");
div.className = "file_button";
div.innerHTML = '<img src="' + apiEndpoint + '/list/' + resp.id + '/thumbnail"/>'
+ "List creation finished!<br/>"
+ title + "<br/>"
+ '<a href="/l/' + resp.id + '" target="_blank">' + window.location.hostname + '/l/' + resp.id + '</a>';
document.getElementById("uploads_queue").appendChild(div);
window.open('/l/' + resp.id, '_blank');
}
else {
console.log("status: " + xhr.status + " response: " + xhr.response);
var div = document.createElement("div");
div.className = "file_button";
div.innerHTML = "List creation failed<br/>"
+ "The server responded with:<br/>"
+ resp.message;
document.getElementById("uploads_queue").append(div);
}
};
xhr.send(JSON.stringify(postData));
}
// Form upload handlers
// Relay click event to hidden file field
document.getElementById("select_file_button").onclick = function () {
document.getElementById("file_input_field").click();
};
document.getElementById("file_input_field").onchange = function (evt) {
handleUploads(evt.target.files);
// This resets the file input field
document.getElementById("file_input_field").nodeValue = "";
};
/*
* Drag 'n Drop upload handlers
*/
document.ondragover = function (e) {
e.preventDefault();
e.stopPropagation();
};
document.ondragenter = function (e) {
e.preventDefault();
e.stopPropagation();
};
document.addEventListener('drop', function (e) {
if (e.dataTransfer && e.dataTransfer.files.length > 0) {
e.preventDefault();
e.stopPropagation();
handleUploads(e.dataTransfer.files);
}
});
function copyText(text) {
// Create a textarea to copy the text from
var ta = document.createElement("textarea");
ta.setAttribute("readonly", "readonly");
ta.style.position = "absolute";
ta.style.left = "-9999px";
ta.value = text; // Put the text in the textarea
// Add the textarea to the DOM so it can be seleted by the user
document.body.appendChild(ta);
ta.select(); // Select the contents of the textarea
var success = document.execCommand("copy"); // Copy the selected text
document.body.removeChild(ta); // Remove the textarea
return success;
}
// Create list button
document.getElementById("btn_create_list").addEventListener("click", function (evt) {
var title = prompt("You are creating a list containing " + finishedUploads.length + " files.\n"
+ "What do you want to call it?", "My New Album");
if (title === null) {
return;
}
createList(title, false);
});
var btnCopyLinks = document.getElementById("btn_copy_links");
btnCopyLinks.addEventListener("click", function () {
var text = "";
// Add the text to the textarea
for (var i = 0; i < finishedUploads.length; i++) {
// Example: https://pixeldrain.com/u/abcd1234: Some_file.png
text += window.location.protocol + "//" + window.location.hostname + "/u/" + finishedUploads[i].id +
" " + finishedUploads[i].name + "\n";
}
var defaultButtonText = btnCopyLinks.innerHTML;
// Copy the selected text
if (copyText(text)) {
btnCopyLinks.classList.add("button_highlight");
btnCopyLinks.innerHTML = "Links copied to clipboard!";
// Return to normal
setTimeout(function () {
btnCopyLinks.innerHTML = defaultButtonText;
btnCopyLinks.classList.remove("button_highlight");
}, 60000);
}
else {
btnCopyLinks.classList.add("button_red");
btnCopyLinks.innerHTML = "Copying links failed";
setTimeout(function () {
btnCopyLinks.innerHTML = defaultButtonText;
btnCopyLinks.classList.remove("button_red");
}, 60000);
}
});
var btnCopyBBCode = document.getElementById("btn_copy_bbcode");
btnCopyBBCode.addEventListener("click", function () {
var text = "";
// Add the text to the textarea
for (var i = 0; i < finishedUploads.length; i++) {
// Example: [url=https://pixeldrain.com/u/abcd1234]Some_file.png[/url]
text += "[url=" + window.location.protocol + "//" + window.location.hostname +
"/u/" + finishedUploads[i].id + "]" +
finishedUploads[i].name + "[/url]\n";
}
var defaultButtonText = btnCopyBBCode.innerHTML;
// Copy the selected text
if (copyText(text)) {
btnCopyBBCode.classList.add("button_highlight");
btnCopyBBCode.innerHTML = "BBCode copied to clipboard!";
// Return to normal
setTimeout(function () {
btnCopyBBCode.innerHTML = defaultButtonText;
btnCopyBBCode.classList.remove("button_highlight");
}, 60000);
}
else {
btnCopyBBCode.classList.add("button_red");
btnCopyBBCode.innerHTML = "Copying links failed";
setTimeout(function () {
btnCopyBBCode.innerHTML = defaultButtonText;
btnCopyBBCode.classList.remove("button_red");
}, 60000);
}
});
var Cookie;
(function (Cookie) {
function read(name) {
var result = new RegExp('(?:^|; )' + encodeURIComponent(name) + '=([^;]*)').exec(document.cookie);
return result ? result[1] : null;
}
Cookie.read = read;
function write(name, value, days) {
if (!days) {
days = 365 * 20;
}
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
var expires = "; expires=" + date.toUTCString();
document.cookie = name + "=" + value + expires + "; path=/";
}
Cookie.write = write;
function remove(name) {
write(name, "", -1);
}
Cookie.remove = remove;
})(Cookie || (Cookie = {}));
var UploadManager = /** @class */ (function () {
function UploadManager() {
this.uploadQueue = new Array();
this.uploadThreads = new Array();
this.maxThreads = 3;
}
UploadManager.prototype.uploadFile = function (file) {
console.debug("Adding upload to queue");
this.uploadQueue.push(file);
if (this.uploadThreads.length < this.maxThreads) {
console.debug("Starting upload thread");
var thread_1 = new UploadWorker(this);
this.uploadThreads.push(thread_1);
setTimeout(function () { thread_1.start(); }, 0); // Start a new upload thread
}
else {
for (var i = 0; i < this.uploadThreads.length; i++) {
this.uploadThreads[i].start();
}
}
};
UploadManager.prototype.uploading = function () {
for (var i = 0; i < this.uploadThreads.length; i++) {
if (this.uploadThreads[i].isUploading()) {
return true;
}
}
return false;
};
UploadManager.prototype.grabFile = function () {
if (this.uploadQueue.length > 0) {
return this.uploadQueue.shift();
}
else {
return undefined;
}
};
return UploadManager;
}());
var UploadWorker = /** @class */ (function () {
function UploadWorker(manager) {
this.tries = 0;
this.uploading = false;
this.manager = manager;
}
UploadWorker.prototype.isUploading = function () { return this.uploading; };
UploadWorker.prototype.start = function () {
if (!this.uploading) {
this.newFile();
}
};
UploadWorker.prototype.newFile = function () {
var file = this.manager.grabFile();
if (file === undefined) { // No more files in the queue. We're finished
this.uploading = false;
console.debug("No files left in queue");
return; // Stop the thread
}
this.uploading = true;
this.tries = 0;
this.upload(file);
};
UploadWorker.prototype.upload = function (file) {
console.debug("Starting upload of " + file.name);
var that = this; // jquery changes the definiton of "this"
var formData = new FormData();
formData.append("name", file.name);
formData.append('file', file.file);
var xhr = new XMLHttpRequest();
xhr.open("POST", apiEndpoint + "/file");
xhr.timeout = 21600000; // 6 hours, to account for slow connections
// Update progess bar on progress
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
file.onProgress(evt.loaded / evt.total);
}
});
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) {
return;
}
console.log("status: " + xhr.status);
if (xhr.status >= 100 && xhr.status < 400) {
var resp = JSON.parse(xhr.response);
// Request is a success
file.onFinished(resp.id);
that.setHistoryCookie(resp.id);
that.newFile(); // Continue uploading on this thread
}
else {
var value, message;
if (xhr.status >= 400) {
var resp = JSON.parse(xhr.response);
value = resp.value;
message = resp.message;
}
console.log("Upload error. status: " + xhr.status + " response: " + xhr.response);
if (that.tries === 3) {
file.onFailure(value, message);
setTimeout(function () { that.newFile(); }, 2000); // Try to continue
return; // Upload failed
}
// Try again
that.tries++;
setTimeout(function () { that.upload(file); }, that.tries * 5000);
}
};
xhr.send(formData);
};
UploadWorker.prototype.setHistoryCookie = function (id) {
// Make sure the user is not logged in, for privacy. This keeps the
// files uploaded while logged in and anonymously uploaded files
// separated
if (Cookie.read("pd_auth_key") !== null) {
return;
}
var uc = Cookie.read("pduploads");
// First upload in this browser
if (uc === null) {
Cookie.write("pduploads", id + ".", undefined);
return;
}
if (uc.length > 2000) {
// Cookie is becoming too long, drop the oldest two files
uc = uc.substring(uc.indexOf(".") + 1).substring(uc.indexOf(".") + 1);
}
Cookie.write("pduploads", uc + id + ".", undefined);
};
return UploadWorker;
}());

View File

@@ -0,0 +1,187 @@
var uploader = null;
var TextUpload = /** @class */ (function () {
function TextUpload(file, name) {
this.file = file;
this.name = name;
}
TextUpload.prototype.onProgress = function (progress) { return; };
TextUpload.prototype.onFinished = function (id) {
setTimeout(window.location.href = "/u/" + id, 100);
};
TextUpload.prototype.onFailure = function (response, error) {
alert("File upload failed! The server told us this: " + response);
};
return TextUpload;
}());
function uploadText() {
var text = $("#textarea").val();
var blob = new Blob([text], { type: "text/plain" });
var filename = prompt("What do you want to call this piece of textual art?\n\n"
+ "Please add your own file extension, if you want.", "Pixeldrain_Text_File.txt");
if (filename === null) {
return;
}
if (uploader === null) {
uploader = new UploadManager();
}
uploader.uploadFile(new TextUpload(blob, filename));
}
/**
* Prevent the Tab key from moving the cursor outside of the text area
*/
$(document).delegate('#textarea', 'keydown', function (e) {
var keyCode = e.keyCode || e.which;
if (keyCode === 9) {
e.preventDefault();
var start = $(this).get(0).selectionStart;
var end = $(this).get(0).selectionEnd;
// set textarea value to: text before caret + tab + text after caret
$(this).val($(this).val().substring(0, start)
+ "\t"
+ $(this).val().substring(end));
// put caret at right position again
$(this).get(0).selectionStart =
$(this).get(0).selectionEnd = start + 1;
}
});
// Upload the file when ctrl + s is pressed
$(document).bind('keydown', function (e) {
if (e.ctrlKey && (e.which === 83)) {
e.preventDefault();
uploadText();
return false;
}
});
var Cookie;
(function (Cookie) {
function read(name) {
var result = new RegExp('(?:^|; )' + encodeURIComponent(name) + '=([^;]*)').exec(document.cookie);
return result ? result[1] : null;
}
Cookie.read = read;
function write(name, value, days) {
if (!days) {
days = 365 * 20;
}
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
var expires = "; expires=" + date.toUTCString();
document.cookie = name + "=" + value + expires + "; path=/";
}
Cookie.write = write;
function remove(name) {
write(name, "", -1);
}
Cookie.remove = remove;
})(Cookie || (Cookie = {}));
var UploadManager = /** @class */ (function () {
function UploadManager() {
this.uploadQueue = new Array();
this.uploadThreads = new Array();
this.maxThreads = 3;
}
UploadManager.prototype.uploadFile = function (file) {
console.debug("Adding upload to queue");
this.uploadQueue.push(file);
if (this.uploadThreads.length < this.maxThreads) {
console.debug("Starting upload thread");
var thread_1 = new UploadWorker(this);
this.uploadThreads.push(thread_1);
setTimeout(function () { thread_1.start(); }, 0); // Start a new upload thread
}
else {
for (var i = 0; i < this.uploadThreads.length; i++) {
this.uploadThreads[i].start();
}
}
};
UploadManager.prototype.grabFile = function () {
if (this.uploadQueue.length > 0) {
return this.uploadQueue.shift();
}
else {
return undefined;
}
};
return UploadManager;
}());
var UploadWorker = /** @class */ (function () {
function UploadWorker(manager) {
this.tries = 0;
this.uploading = false;
this.manager = manager;
}
UploadWorker.prototype.start = function () {
if (!this.uploading) {
this.newFile();
}
};
UploadWorker.prototype.newFile = function () {
var file = this.manager.grabFile();
if (file === undefined) {
this.uploading = false;
console.debug("No files left in queue");
return; // Stop the thread
}
this.uploading = true;
this.tries = 0;
this.upload(file);
};
UploadWorker.prototype.upload = function (file) {
console.debug("Starting upload of " + file.name);
var formData = new FormData();
formData.append('file', file.file);
formData.append("name", file.name);
var that = this; // jquery changes the definiton of "this"
$.ajax({
url: "/api/file",
data: formData,
cache: false,
crossDomain: false,
contentType: false,
processData: false,
type: 'POST',
xhr: function () {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
file.onProgress(evt.loaded / evt.total);
}
}, false);
return xhr;
},
success: function (data) {
file.onFinished(data.id);
that.setHistoryCookie(data.id);
console.log("Done: " + data.id);
that.newFile(); // Continue uploading on this thread
},
error: function (xhr, status, error) {
console.log("status: " + status + " error: " + error);
if (that.tries === 3) {
alert("Upload failed: " + status);
file.onFailure(status, error);
setTimeout(function () { that.newFile(); }, 2000); // Try to continue
return; // Upload failed
}
// Try again
that.tries++;
setTimeout(function () { that.upload(file); }, that.tries * 3000);
}
});
};
UploadWorker.prototype.setHistoryCookie = function (id) {
var uc = Cookie.read("pduploads");
// First upload in this browser
if (uc === null) {
Cookie.write("pduploads", id + ".", undefined);
return;
}
if (uc.length > 2000) {
// Cookie is becoming too long, drop the oldest two files
uc = uc.substring(uc.indexOf(".") + 1).substring(uc.indexOf(".") + 1);
}
Cookie.write("pduploads", uc + id + ".", undefined);
};
return UploadWorker;
}());

View File

@@ -0,0 +1,22 @@
/*
Created on : Oct 21, 2015, 1:15:03 PM
Author : Fornax
*/
.uploadQueueSideBar{
}
.uploadQueueToggleButton{
}
.uploadNotification{
position: fixed;
background-color: #333;
border: 2px #555 outset;
height: 100px;
width: 200px;
right: 10px;
bottom: 10px;
}

View File

@@ -0,0 +1,14 @@
/*
* Made by Fornax
*/
$(document).ready(function () {
// Add the stylesheet
$("head").append('<link rel="stylesheet" type="text/css" href="/res/script/embedupload.css">');
});
var ModularUploader = {
doUpload: function(){
}
};

View File

@@ -0,0 +1,52 @@
var uploads;
$(document).ready(function () {
var uploadString = $.cookie("pduploads");
uploadString = uploadString.slice(0, -1);
uploads = uploadString.split(".");
uploads.reverse();
var timeout = 250;
var itemcount = 0;
$.each(uploads, function (nr, id) {
setTimeout(function () {
$.ajax({
type: "GET",
dataType: "json",
url: apiEndpoint + "/file/" + id + "/info",
async: true,
success: function(data) {
historyAddItem(data);
},
error: function(data) {
historyAddItem(data.responseJSON);
}
});
}, timeout);
timeout = timeout + 100;
itemcount++;
if (itemcount > 1000) {
return false;
}
});
});
function historyAddItem(json) {
if(!json.success){return;}
var date = new Date(json.date_upload);
var uploadItem = '<a href="/u/'+ json.id +'" target="_blank" class="file_button">'
+ '<img src="'+ apiEndpoint + json.thumbnail_href + '?width=80&height=80"'
+ "alt=\"" + json.name + "\" />"
+ '<span style="color: var(--highlight_color);">'+json.name+'</span>'
+ "<br/>"
+ date.getFullYear() + "-"
+ ("00" + (date.getMonth() + 1)).slice(-2) + "-"
+ ("00" + date.getDate()).slice(-2)
+ "</a>";
$("#uploadedFiles").append($(uploadItem).hide().fadeIn(500));
}

View File

@@ -0,0 +1,25 @@
var listItems = new Array();
function addToList(id, desc){
var listEntry = {id: id, desc: desc};
listItems.push(listEntry);
}
function openList(){
var arrayLength = listItems.length;
var url = "/u/"
for (var i = 0; i < arrayLength; i++) {
if (i != 0) {
url = url + ","
}
url = url + listItems[i]["id"]
}
window.open(url)
}
$("#btnOpenAsList").click(function (evt) {
openList();
});

107
res/include/script/paste.js Normal file
View File

@@ -0,0 +1,107 @@
/**
* Made by Fornax
* Use if you need to
*/
function uploadText() {
var text = $("#textarea").val();
if(!text.endsWith("\n")){
text += "\n";
}
var blob = new Blob([text], {type: "text/plain"});
startFileUpload(blob);
}
/*
* Upload functions
*/
function startFileUpload(blob) {
formData = new FormData();
formData.append('file', blob);
var filename = prompt("What do you want to call this piece of textual art?\n\n"
+ "Please add your own file extension, if you want.",
"Pixeldrain_Text_File.txt");
if(filename === null){
return;
}
formData.append("name", filename);
jQuery.ajax({
url: "/api/file",
data: formData,
cache: false,
crossDomain: true,
contentType: false,
processData: false,
type: 'POST',
success: function (data) {
fileUploadComplete(data);
}
});
}
function fileUploadComplete(json) {
if (json.success) {
setHistoryCookie(json.id)
setTimeout(window.location.href = "/u/" + json.id, 100);
} else {
alert("File upload failed! The server told us this: " + json.message);
}
}
function setHistoryCookie(id){
uc = Cookie.get("pduploads");
// First upload in this browser
if (uc === null) {
Cookie.set("pduploads", id + ".");
return;
}
if (uc.length > 2000){
// Cookie is becoming too long, drop the oldest two files
uc = uc.substring(
uc.indexOf(".") + 1
).substring(
uc.indexOf(".") + 1
);
}
Cookie.set("pduploads", uc + id + ".");
}
/**
* Prevent the Tab key from moving the cursor outside of the text area
*/
$(document).delegate('#textarea', 'keydown', function (e) {
var keyCode = e.keyCode || e.which;
if (keyCode === 9) {
e.preventDefault();
var start = $(this).get(0).selectionStart;
var end = $(this).get(0).selectionEnd;
// set textarea value to: text before caret + tab + text after caret
$(this).val($(this).val().substring(0, start)
+ "\t"
+ $(this).val().substring(end));
// put caret at right position again
$(this).get(0).selectionStart =
$(this).get(0).selectionEnd = start + 1;
}
});
// Upload the file when ctrl + s is pressed
$(document).bind('keydown', function (e) {
if (e.ctrlKey && (e.which === 83)) {
e.preventDefault();
uploadText();
return false;
}
});