diff --git a/Makefile b/Makefile index 3fb9420..c8708ae 100644 --- a/Makefile +++ b/Makefile @@ -12,4 +12,5 @@ deps: backgroundrun: go run main.go backgroundts: - tsc --watch --project res/static/res/typescript/home + tsc --watch --project res/static/res/typescript/home + --project res/static/res/typescript/textupload diff --git a/res/static/res/script/compiled/home.js b/res/static/res/script/compiled/home.js index 3dfd364..7aff8f3 100644 --- a/res/static/res/script/compiled/home.js +++ b/res/static/res/script/compiled/home.js @@ -4,10 +4,11 @@ var totalUploads = 0; var UploadProgressBar = /** @class */ (function () { function UploadProgressBar(file) { this.file = file; + this.name = file.name; this.queueNum = totalUploads; totalUploads++; this.uploadDiv = document.createElement("a"); - this.uploadDiv.setAttribute("class", "uploadItem"); + this.uploadDiv.setAttribute("class", "file_button"); this.uploadDiv.innerText = "Queued\n" + this.file.name; this.uploadDivJQ = $(this.uploadDiv); $("#uploads_queue").append(this.uploadDivJQ.hide().fadeIn('slow')); @@ -25,7 +26,7 @@ var UploadProgressBar = /** @class */ (function () { this.uploadDiv.setAttribute('style', 'background: #111'); this.uploadDiv.setAttribute('href', '/u/' + id); this.uploadDiv.setAttribute("target", "_blank"); - this.uploadDivJQ.html('' + this.file.name + '' + this.uploadDivJQ.html('' + this.file.name + '' + this.file.name + '
' + '' + window.location.hostname + '/u/' + id + ''); }; @@ -153,10 +154,10 @@ var UploadWorker = /** @class */ (function () { this.upload(file); }; UploadWorker.prototype.upload = function (file) { - console.debug("Starting upload of " + file.file.name); + console.debug("Starting upload of " + file.name); var formData = new FormData(); formData.append('file', file.file); - formData.append("name", file.file.name); + formData.append("name", file.name); var that = this; // jquery changes the definiton of "this" $.ajax({ url: "/api/file", diff --git a/res/static/res/script/compiled/textupload.js b/res/static/res/script/compiled/textupload.js new file mode 100644 index 0000000..bb32512 --- /dev/null +++ b/res/static/res/script/compiled/textupload.js @@ -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; +}()); diff --git a/res/static/res/script/history.js b/res/static/res/script/history.js index 1bbcc18..e73752d 100644 --- a/res/static/res/script/history.js +++ b/res/static/res/script/history.js @@ -38,10 +38,9 @@ $(document).ready(function () { function historyAddItem(json) { if(!json.success){ - var uploadItem = "
" + var uploadItem = "
" + "" + + "alt=\"File has expired\" />" + "File has expired" + "
"; @@ -52,16 +51,13 @@ function historyAddItem(json) { var date = new Date(json.date_upload * 1000); - var uploadItem = "
" - + "" - + "" - + json.file_name - + "" + var uploadItem = '' + + '" + + ''+json.file_name+'' + "
" + date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() - + "
"; + + ""; $("#uploadedFiles").append($(uploadItem).hide().fadeIn(400)); } \ No newline at end of file diff --git a/res/static/res/script/listmaker.js b/res/static/res/script/listmaker.js index b7b1e4e..4d8a00d 100644 --- a/res/static/res/script/listmaker.js +++ b/res/static/res/script/listmaker.js @@ -49,7 +49,7 @@ function createList(){ function listCreated(response){ if(response.success){ - resultString = "
List creation finished!
" + resultString = "
List creation finished!
" + "Your List URL:
" + ""+window.location.hostname+"/l/" + response.id + "" + "
"; @@ -59,7 +59,7 @@ function listCreated(response){ ); window.open('/l/'+response.id, '_blank'); }else{ - resultString = "
List creation failed
" + resultString = "
List creation failed
" + "The server responded with this:
" + response.type + ": " + response.value + "
"; diff --git a/res/static/res/style/history.css b/res/static/res/style/history.css deleted file mode 100644 index c7bdb21..0000000 --- a/res/static/res/style/history.css +++ /dev/null @@ -1,34 +0,0 @@ -.uploadedFiles{ - position: relative; - width: 100%; - margin: 0; - height: auto; - display: inline-block; -} - -.uploadItem, .uploadItem:hover{ - position: relative; - box-sizing: border-box; - width: 322px; - max-width: 90%; - height: 60px; - float: left; - margin: 3px; - padding: 0; - border: 1px #555 solid; - overflow: hidden; - background-color: #111; - color: var(--text_color); - word-break: break-all; - text-align: left; - line-height: 120%; - display: block; -} - -.uploadItemImage{ - max-height: 60px; - max-width: 120px; - margin-right: 5px; - float: left; - display: block; -} \ No newline at end of file diff --git a/res/static/res/style/home.css b/res/static/res/style/home.css deleted file mode 100644 index f4c54fa..0000000 --- a/res/static/res/style/home.css +++ /dev/null @@ -1,33 +0,0 @@ -/* - Created on : Jun 3, 2015, 9:33:11 AM - Author : Fornax -*/ - -.progress-bar{ - position: relative; - width: 100%; - height: 0; - background-color: #555; - overflow: hidden; - color: #eeeeee; - text-align: left; - white-space: nowrap; -} - -.progressbar-inner{ - position: absolute; - top: 0; - width: 0%; - left: 0; - height: 100%; - background-color: var(--highlight_color);; - overflow: hidden; - color: #000; - white-space: nowrap; -} - -.progress-text{ - overflow: hidden; - width: 100%; - white-space: nowrap; -} \ No newline at end of file diff --git a/res/static/res/style/layout.css b/res/static/res/style/layout.css index 12c9ae7..925371d 100644 --- a/res/static/res/style/layout.css +++ b/res/static/res/style/layout.css @@ -20,7 +20,7 @@ html{ height: 100%; } -/* HEAD */ +/* Page layout elements */ #header{ position: relative; @@ -41,17 +41,6 @@ html{ margin-top: 15px; } -#uploads_queue{ - position: relative; - width: 100%; - height: 0; - overflow-x: hidden; - overflow-y: scroll; -} - - -/* Layout elements */ - .body{ position: relative; display: inline-block; @@ -205,6 +194,47 @@ a:hover{ white-space: nowrap; } +.uploads_queue{ + position: relative; + width: 100%; + height: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.files_container{ + position: relative; + width: 100%; + margin: 0; + height: auto; + display: inline-block; +} + +.file_button, .file_button:hover{ + position: relative; + box-sizing: border-box; + width: 316px; + max-width: 90%; + height: 60px; + float: left; + margin: 6px; + padding: 0; + overflow: hidden; + box-shadow: 2px 2px 5px 2px #111; + background-color: #111; + color: var(--text_color); + word-break: break-all; + text-align: left; + line-height: 120%; + display: block; +} +.file_button > img{ + max-height: 60px; + max-width: 120px; + margin-right: 5px; + float: left; + display: block; +} + /* Form fields */ /* BUTTONS */ diff --git a/res/static/res/typescript/home/home.ts b/res/static/res/typescript/home/home.ts index 92bcf4e..ccd4395 100644 --- a/res/static/res/typescript/home/home.ts +++ b/res/static/res/typescript/home/home.ts @@ -9,11 +9,12 @@ class UploadProgressBar implements FileUpload { constructor(file: File){ this.file = file + this.name = file.name this.queueNum = totalUploads totalUploads++ this.uploadDiv = document.createElement("a"); - this.uploadDiv.setAttribute("class", "uploadItem"); + this.uploadDiv.setAttribute("class", "file_button"); this.uploadDiv.innerText = "Queued\n" + this.file.name this.uploadDivJQ = $(this.uploadDiv) @@ -24,6 +25,7 @@ class UploadProgressBar implements FileUpload { // Interface stuff public file: File; + public name: string public onProgress(progress: number){ this.uploadDiv.innerText = "Uploading... " + Math.round(progress*1000)/10 + "%\n" + this.file.name this.uploadDiv.setAttribute( @@ -42,7 +44,7 @@ class UploadProgressBar implements FileUpload { this.uploadDiv.setAttribute('href', '/u/'+id) this.uploadDiv.setAttribute("target", "_blank"); this.uploadDivJQ.html( - ''+this.file.name+'' + ''+this.file.name+'' + this.file.name+'
' + ''+window.location.hostname+'/u/'+id+'' ) diff --git a/res/static/res/typescript/lib/uploader.ts b/res/static/res/typescript/lib/uploader.ts index 375005f..7403117 100644 --- a/res/static/res/typescript/lib/uploader.ts +++ b/res/static/res/typescript/lib/uploader.ts @@ -1,5 +1,6 @@ interface FileUpload { - file: File + file: Blob + name: string onProgress(progress: number) onFinished(id: string) onFailure(response: JQuery.Ajax.ErrorTextStatus, error: string) @@ -62,11 +63,11 @@ class UploadWorker { } private upload(file: FileUpload){ - console.debug("Starting upload of " + file.file.name) + console.debug("Starting upload of " + file.name) var formData = new FormData() formData.append('file', file.file) - formData.append("name", file.file.name) + formData.append("name", file.name) var that = this // jquery changes the definiton of "this" diff --git a/res/static/res/typescript/textupload/text.ts b/res/static/res/typescript/textupload/text.ts new file mode 100644 index 0000000..8553d1a --- /dev/null +++ b/res/static/res/typescript/textupload/text.ts @@ -0,0 +1,69 @@ +var uploader: UploadManager|null = null + +class TextUpload implements FileUpload { + constructor(file: Blob, name: string){ + this.file = file + this.name = name + } + + // Interface stuff + public file: Blob; + public name: string + public onProgress(progress: number){return} + public onFinished(id: string){ + setTimeout(window.location.href = "/u/" + id, 100); + } + public onFailure(response: JQuery.Ajax.ErrorTextStatus, error: string) { + alert("File upload failed! The server told us this: " + response); + } +} + +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; + } +}); diff --git a/res/static/res/typescript/textupload/tsconfig.json b/res/static/res/typescript/textupload/tsconfig.json new file mode 100644 index 0000000..62bafef --- /dev/null +++ b/res/static/res/typescript/textupload/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "outFile": "../../script/compiled/textupload.js" + }, + "files": [ + "text.ts", + "../lib/cookie.ts", + "../lib/jquery.d.ts", + "../lib/uploader.ts" + ] +} \ No newline at end of file diff --git a/res/template/history.html b/res/template/history.html index 7825b75..40dd86c 100644 --- a/res/template/history.html +++ b/res/template/history.html @@ -7,7 +7,6 @@ - @@ -44,7 +43,7 @@ This data is saved locally in your web browser and gets updated every time you upload a file through your current browser.

-
+
{{template "footer"}}
diff --git a/res/template/home.html b/res/template/home.html index bccebf0..c2a8c50 100644 --- a/res/template/home.html +++ b/res/template/home.html @@ -6,9 +6,7 @@ - - @@ -42,7 +40,7 @@
-
+
diff --git a/res/template/paste.html b/res/template/paste.html index 12e4462..596a716 100644 --- a/res/template/paste.html +++ b/res/template/paste.html @@ -55,26 +55,8 @@
- - - - - + + {{template "analytics"}} {{end}} \ No newline at end of file