Support file upload by drag-n-drop into files list (#2945)
This commit is contained in:
parent
b640c0cc3e
commit
825a93201b
2 changed files with 200 additions and 43 deletions
|
@ -97,12 +97,11 @@ window.rcmail && window.files_api && rcmail.addEventListener('init', function()
|
||||||
.addEventListener('column_replace', function(e) { kolab_files_set_coltypes(e); })
|
.addEventListener('column_replace', function(e) { kolab_files_set_coltypes(e); })
|
||||||
.addEventListener('listupdate', function(e) { rcmail.triggerEvent('listupdate', e); });
|
.addEventListener('listupdate', function(e) { rcmail.triggerEvent('listupdate', e); });
|
||||||
|
|
||||||
rcmail.gui_objects.filelist.parentNode.onmousedown = function(e) { return kolab_files_click_on_list(e); };
|
|
||||||
|
|
||||||
rcmail.enable_command('menu-open', 'menu-save', 'files-sort', 'files-search', 'files-search-reset', 'folder-create', true);
|
rcmail.enable_command('menu-open', 'menu-save', 'files-sort', 'files-search', 'files-search-reset', 'folder-create', true);
|
||||||
|
|
||||||
rcmail.file_list.init();
|
rcmail.file_list.init();
|
||||||
kolab_files_list_coltypes();
|
kolab_files_list_coltypes();
|
||||||
|
kolab_files_drag_drop_init($(rcmail.gui_objects.filelist).parents('.droptarget'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// "one file only" commands
|
// "one file only" commands
|
||||||
|
@ -702,17 +701,6 @@ kolab_files_set_coltypes = function(list)
|
||||||
rcmail.http_post('files/prefs', {kolab_files_list_cols: rcmail.env.coltypes});
|
rcmail.http_post('files/prefs', {kolab_files_list_cols: rcmail.env.coltypes});
|
||||||
};
|
};
|
||||||
|
|
||||||
kolab_files_click_on_list = function(e)
|
|
||||||
{
|
|
||||||
if (rcmail.gui_objects.qsearchbox)
|
|
||||||
rcmail.gui_objects.qsearchbox.blur();
|
|
||||||
|
|
||||||
if (rcmail.file_list)
|
|
||||||
rcmail.file_list.focus();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
kolab_files_list_dblclick = function(list)
|
kolab_files_list_dblclick = function(list)
|
||||||
{
|
{
|
||||||
rcmail.command('files-open');
|
rcmail.command('files-open');
|
||||||
|
@ -824,6 +812,51 @@ kolab_files_frame_load = function(frame)
|
||||||
catch(e) {};
|
catch(e) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// activate html5 file drop feature (if browser supports it)
|
||||||
|
kolab_files_drag_drop_init = function(container)
|
||||||
|
{
|
||||||
|
if (!window.FormData && !(window.XMLHttpRequest && XMLHttpRequest.prototype && XMLHttpRequest.prototype.sendAsBinary)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document.body).bind('dragover dragleave drop', function(e) {
|
||||||
|
if (!file_api.env.folder)
|
||||||
|
return;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
container[e.type == 'dragover' ? 'addClass' : 'removeClass']('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
container.bind('dragover dragleave', function(e) {
|
||||||
|
return kolab_files_drag_hover(e);
|
||||||
|
})
|
||||||
|
container.children('div').bind('dragover dragleave', function(e) {
|
||||||
|
return kolab_files_drag_hover(e);
|
||||||
|
})
|
||||||
|
container.get(0).addEventListener('drop', function(e) {
|
||||||
|
// abort event and reset UI
|
||||||
|
kolab_files_drag_hover(e);
|
||||||
|
return file_api.file_drop(e);
|
||||||
|
}, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// handler for drag/drop on element
|
||||||
|
kolab_files_drag_hover = function(e)
|
||||||
|
{
|
||||||
|
if (!file_api.env.folder)
|
||||||
|
return;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
var elem = $(e.target);
|
||||||
|
|
||||||
|
if (!elem.hasClass('droptarget'))
|
||||||
|
elem = elem.parents('.droptarget');
|
||||||
|
|
||||||
|
elem[e.type == 'dragover' ? 'addClass' : 'removeClass']('hover');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/********** Commands **********/
|
/********** Commands **********/
|
||||||
|
@ -1776,22 +1809,12 @@ function kolab_files_ui()
|
||||||
// file upload request
|
// file upload request
|
||||||
this.file_upload = function(form)
|
this.file_upload = function(form)
|
||||||
{
|
{
|
||||||
var i, size = 0, maxsize = rcmail.env.files_max_upload,
|
var form = $(form),
|
||||||
form = $(form),
|
|
||||||
field = $('input[type=file]', form).get(0),
|
field = $('input[type=file]', form).get(0),
|
||||||
files = field.files ? field.files.length : field.value ? 1 : 0;
|
files = field.files ? field.files.length : field.value ? 1 : 0;
|
||||||
|
|
||||||
if (files) {
|
if (!files || !this.file_upload_size_check(field.files))
|
||||||
// check upload max size
|
|
||||||
if (field.files && maxsize) {
|
|
||||||
for (i=0; i < files; i++)
|
|
||||||
size += field.files[i].size;
|
|
||||||
|
|
||||||
if (size > maxsize) {
|
|
||||||
alert(rcmail.get_label('kolab_files.uploadsizeerror').replace('$size', this.file_size(maxsize)));
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// submit form and read server response
|
// submit form and read server response
|
||||||
this.file_upload_form(form, 'file_upload', function(event) {
|
this.file_upload_form(form, 'file_upload', function(event) {
|
||||||
|
@ -1804,20 +1827,45 @@ function kolab_files_ui()
|
||||||
response = doc.body.firstChild.firstChild.nodeValue;
|
response = doc.body.firstChild.firstChild.nodeValue;
|
||||||
}
|
}
|
||||||
response = eval('(' + response + ')');
|
response = eval('(' + response + ')');
|
||||||
} catch (err) {
|
}
|
||||||
|
catch (err) {
|
||||||
response = {status: 'ERROR'};
|
response = {status: 'ERROR'};
|
||||||
}
|
}
|
||||||
|
|
||||||
rcmail.hide_message(event.data.ts);
|
rcmail.hide_message(event.data.ts);
|
||||||
|
|
||||||
// refresh the list on upload success
|
// refresh the list on upload success
|
||||||
if (file_api.response_parse(response))
|
file_api.file_upload_response(response);
|
||||||
file_api.file_list();
|
|
||||||
file_api.quota();
|
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// refresh the list on upload success
|
||||||
|
this.file_upload_response = function(response)
|
||||||
|
{
|
||||||
|
if (this.response_parse(response)) {
|
||||||
|
this.file_list();
|
||||||
|
this.quota();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// check upload max size
|
||||||
|
this.file_upload_size_check = function(files)
|
||||||
|
{
|
||||||
|
var i, size = 0, maxsize = rcmail.env.files_max_upload;
|
||||||
|
|
||||||
|
if (maxsize && files) {
|
||||||
|
for (i=0; i < files.length; i++)
|
||||||
|
size += files[i].size || files[i].fileSize;
|
||||||
|
|
||||||
|
if (size > maxsize) {
|
||||||
|
alert(rcmail.get_label('kolab_files.uploadsizeerror').replace('$size', this.file_size(maxsize)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// post the given form to a hidden iframe
|
// post the given form to a hidden iframe
|
||||||
this.file_upload_form = function(form, action, onload)
|
this.file_upload_form = function(form, action, onload)
|
||||||
{
|
{
|
||||||
|
@ -1861,6 +1909,97 @@ function kolab_files_ui()
|
||||||
.submit();
|
.submit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// handler when files are dropped to a designated area.
|
||||||
|
// compose a multipart form data and submit it to the server
|
||||||
|
this.file_drop = function(e)
|
||||||
|
{
|
||||||
|
// prepare multipart form data composition
|
||||||
|
var files = e.target.files || e.dataTransfer.files,
|
||||||
|
formdata = window.FormData ? new FormData() : null,
|
||||||
|
fieldname = 'file[]',
|
||||||
|
boundary = '------multipartformboundary' + (new Date).getTime(),
|
||||||
|
dashdash = '--', crlf = '\r\n',
|
||||||
|
multipart = dashdash + boundary + crlf;
|
||||||
|
|
||||||
|
if (!files || !files.length || !this.file_upload_size_check(files))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// inline function to submit the files to the server
|
||||||
|
var submit_data = function() {
|
||||||
|
var multiple = files.length > 1,
|
||||||
|
ts = rcmail.display_message(rcmail.get_label('kolab_files.uploading'), 'loading', 1000);
|
||||||
|
|
||||||
|
// complete multipart content and post request
|
||||||
|
multipart += dashdash + boundary + dashdash + crlf;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
url: file_api.env.url + file_api.url('file_upload', {folder: file_api.env.folder}),
|
||||||
|
contentType: formdata ? false : 'multipart/form-data; boundary=' + boundary,
|
||||||
|
processData: false,
|
||||||
|
timeout: 0, // disable default timeout set in ajaxSetup()
|
||||||
|
data: formdata || multipart,
|
||||||
|
headers: {'X-Session-Token': file_api.env.token},
|
||||||
|
success: function(data) {
|
||||||
|
file_api.file_upload_response(data);
|
||||||
|
rcmail.hide_message(ts);
|
||||||
|
},
|
||||||
|
error: function(o, status, err) {
|
||||||
|
rcmail.http_error(o, status, err);
|
||||||
|
rcmail.hide_message(ts);
|
||||||
|
},
|
||||||
|
xhr: function() {
|
||||||
|
var xhr = jQuery.ajaxSettings.xhr();
|
||||||
|
if (!formdata && xhr.sendAsBinary)
|
||||||
|
xhr.send = xhr.sendAsBinary;
|
||||||
|
return xhr;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// get contents of all dropped files
|
||||||
|
var f, j, i = 0, last = files.length - 1;
|
||||||
|
for (j = 0; j <= last && (f = files[i]); i++) {
|
||||||
|
if (!f.name) f.name = f.fileName;
|
||||||
|
if (!f.size) f.size = f.fileSize;
|
||||||
|
if (!f.type) f.type = 'application/octet-stream';
|
||||||
|
|
||||||
|
// file name contains non-ASCII characters, do UTF8-binary string conversion.
|
||||||
|
if (!formdata && /[^\x20-\x7E]/.test(f.name))
|
||||||
|
f.name_bin = unescape(encodeURIComponent(f.name));
|
||||||
|
|
||||||
|
// do it the easy way with FormData (FF 4+, Chrome 5+, Safari 5+)
|
||||||
|
if (formdata) {
|
||||||
|
formdata.append(fieldname, f);
|
||||||
|
if (j == last)
|
||||||
|
return submit_data();
|
||||||
|
}
|
||||||
|
// use FileReader supporetd by Firefox 3.6
|
||||||
|
else if (window.FileReader) {
|
||||||
|
var reader = new FileReader();
|
||||||
|
|
||||||
|
// closure to pass file properties to async callback function
|
||||||
|
reader.onload = (function(file, j) {
|
||||||
|
return function(e) {
|
||||||
|
multipart += 'Content-Disposition: form-data; name="' + fieldname + '"';
|
||||||
|
multipart += '; filename="' + (f.name_bin || file.name) + '"' + crlf;
|
||||||
|
multipart += 'Content-Length: ' + file.size + crlf;
|
||||||
|
multipart += 'Content-Type: ' + file.type + crlf + crlf;
|
||||||
|
multipart += reader.result + crlf;
|
||||||
|
multipart += dashdash + boundary + crlf;
|
||||||
|
|
||||||
|
if (j == last) // we're done, submit the data
|
||||||
|
return submit_data();
|
||||||
|
}
|
||||||
|
})(f,j);
|
||||||
|
reader.readAsBinaryString(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// open file in new window, using file API viewer
|
// open file in new window, using file API viewer
|
||||||
this.file_open = function(file, viewer)
|
this.file_open = function(file, viewer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -288,6 +288,24 @@
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#filelistcontainer.droptarget.hover,
|
||||||
|
#filelistcontainer.droptarget.active {
|
||||||
|
border-color: #019bc6;
|
||||||
|
box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
|
||||||
|
-webkit-box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#filelistcontainer.droptarget.hover {
|
||||||
|
background-color: #d9ecf4;
|
||||||
|
box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
|
||||||
|
-webkit-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
#filelistcontainer.droptarget.hover #filelist tbody td {
|
||||||
|
background-color: #d9ecf4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* plugin dialogs */
|
/* plugin dialogs */
|
||||||
|
|
||||||
#files-dialog,
|
#files-dialog,
|
||||||
|
|
Loading…
Add table
Reference in a new issue