Add file drag and drop and asynchronous upload
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,19 +0,0 @@
|
||||
#screenshot-zone {
|
||||
position: relative;
|
||||
border: 2px dashed #ccc;
|
||||
width: 90%;
|
||||
height: 250px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#screenshot-inner {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 48%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#screenshot-zone.screenshot-pasted {
|
||||
border: 2px solid #333;
|
||||
}
|
||||
39
assets/css/src/upload.css
Normal file
39
assets/css/src/upload.css
Normal file
@@ -0,0 +1,39 @@
|
||||
#file-dropzone,
|
||||
#screenshot-zone {
|
||||
position: relative;
|
||||
border: 2px dashed #ccc;
|
||||
width: 99%;
|
||||
height: 250px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#file-dropzone-inner,
|
||||
#screenshot-inner {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 48%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
#screenshot-zone.screenshot-pasted {
|
||||
border: 2px solid #333;
|
||||
}
|
||||
|
||||
#file-list {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
#file-list li {
|
||||
list-style-type: none;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px dotted #ddd;
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
#file-list li.file-error {
|
||||
font-weight: bold;
|
||||
color: #b94a48;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -9,6 +9,7 @@ function App() {
|
||||
this.task = new Task();
|
||||
this.project = new Project();
|
||||
this.subtask = new Subtask();
|
||||
this.file = new FileUpload(this);
|
||||
this.keyboardShortcuts();
|
||||
this.chosen();
|
||||
this.poll();
|
||||
@@ -39,6 +40,7 @@ App.prototype.listen = function() {
|
||||
this.task.listen();
|
||||
this.swimlane.listen();
|
||||
this.subtask.listen();
|
||||
this.file.listen();
|
||||
this.search.focus();
|
||||
this.autoComplete();
|
||||
this.datePicker();
|
||||
|
||||
124
assets/js/src/FileUpload.js
Normal file
124
assets/js/src/FileUpload.js
Normal file
@@ -0,0 +1,124 @@
|
||||
function FileUpload(app) {
|
||||
this.app = app;
|
||||
this.files = [];
|
||||
this.currentFile = 0;
|
||||
}
|
||||
|
||||
FileUpload.prototype.listen = function() {
|
||||
var dropzone = document.getElementById("file-dropzone");
|
||||
var self = this;
|
||||
|
||||
if (dropzone) {
|
||||
dropzone.ondragover = dropzone.ondragenter = function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
dropzone.ondrop = function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
self.files = e.dataTransfer.files;
|
||||
self.show();
|
||||
$("#file-error-max-size").hide();
|
||||
}
|
||||
|
||||
$(document).on("click", "#file-browser", function(e) {
|
||||
e.preventDefault();
|
||||
$("#file-form-element").get(0).click();
|
||||
});
|
||||
|
||||
$(document).on("click", "#file-upload-button", function(e) {
|
||||
e.preventDefault();
|
||||
self.currentFile = 0;
|
||||
self.checkFiles();
|
||||
});
|
||||
|
||||
$("#file-form-element").change(function() {
|
||||
self.files = document.getElementById("file-form-element").files;
|
||||
self.show();
|
||||
$("#file-error-max-size").hide();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
FileUpload.prototype.show = function() {
|
||||
$("#file-list").remove();
|
||||
|
||||
if (this.files.length > 0) {
|
||||
$("#file-upload-button").prop("disabled", false);
|
||||
$("#file-dropzone-inner").hide();
|
||||
|
||||
var ul = jQuery("<ul>", {"id": "file-list"});
|
||||
|
||||
for (var i = 0; i < this.files.length; i++) {
|
||||
var percentage = jQuery("<span>", {"id": "file-percentage-" + i}).append("(0%)");
|
||||
var progress = jQuery("<progress>", {"id": "file-progress-" + i, "value": 0});
|
||||
var li = jQuery("<li>", {"id": "file-label-" + i})
|
||||
.append(progress)
|
||||
.append(" ")
|
||||
.append(this.files[i].name)
|
||||
.append(" ")
|
||||
.append(percentage);
|
||||
|
||||
ul.append(li);
|
||||
}
|
||||
|
||||
$("#file-dropzone").append(ul);
|
||||
} else {
|
||||
$("#file-dropzone-inner").show();
|
||||
}
|
||||
};
|
||||
|
||||
FileUpload.prototype.checkFiles = function() {
|
||||
var max = parseInt($("#file-dropzone").data("max-size"));
|
||||
|
||||
for (var i = 0; i < this.files.length; i++) {
|
||||
if (this.files[i].size > max) {
|
||||
$("#file-error-max-size").show();
|
||||
$("#file-label-" + i).addClass("file-error");
|
||||
$("#file-upload-button").prop("disabled", true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.uploadFiles();
|
||||
};
|
||||
|
||||
FileUpload.prototype.uploadFiles = function() {
|
||||
if (this.files.length > 0) {
|
||||
this.uploadFile(this.files[this.currentFile]);
|
||||
}
|
||||
};
|
||||
|
||||
FileUpload.prototype.uploadFile = function(file) {
|
||||
var dropzone = document.getElementById("file-dropzone");
|
||||
var url = dropzone.dataset.url;
|
||||
var xhr = new XMLHttpRequest();
|
||||
var fd = new FormData();
|
||||
|
||||
xhr.upload.addEventListener("progress", this.updateProgress.bind(this));
|
||||
xhr.upload.addEventListener("load", this.transferComplete.bind(this));
|
||||
|
||||
xhr.open("POST", url, true);
|
||||
fd.append('files[]', file);
|
||||
xhr.send(fd);
|
||||
};
|
||||
|
||||
FileUpload.prototype.updateProgress = function(e) {
|
||||
if (e.lengthComputable) {
|
||||
$("#file-progress-" + this.currentFile).val(e.loaded / e.total);
|
||||
$("#file-percentage-" + this.currentFile).text('(' + Math.floor((e.loaded / e.total) * 100) + '%)');
|
||||
}
|
||||
};
|
||||
|
||||
FileUpload.prototype.transferComplete = function() {
|
||||
this.currentFile++;
|
||||
|
||||
if (this.currentFile < this.files.length) {
|
||||
this.uploadFile(this.files[this.currentFile]);
|
||||
} else {
|
||||
$("#file-upload-button").prop("disabled", true);
|
||||
$("#file-upload-button").parent().hide();
|
||||
$("#file-done").show();
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user