diff --git a/plugins/kolab_files/kolab_files.js b/plugins/kolab_files/kolab_files.js index 51755737..33712a86 100644 --- a/plugins/kolab_files/kolab_files.js +++ b/plugins/kolab_files/kolab_files.js @@ -97,12 +97,11 @@ window.rcmail && window.files_api && rcmail.addEventListener('init', function() .addEventListener('column_replace', function(e) { kolab_files_set_coltypes(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.file_list.init(); kolab_files_list_coltypes(); + kolab_files_drag_drop_init($(rcmail.gui_objects.filelist).parents('.droptarget')); } // "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}); }; -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) { rcmail.command('files-open'); @@ -824,6 +812,51 @@ kolab_files_frame_load = function(frame) 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 **********/ @@ -1776,48 +1809,63 @@ function kolab_files_ui() // file upload request this.file_upload = function(form) { - var i, size = 0, maxsize = rcmail.env.files_max_upload, - form = $(form), + var form = $(form), field = $('input[type=file]', form).get(0), files = field.files ? field.files.length : field.value ? 1 : 0; - if (files) { - // check upload max size - if (field.files && maxsize) { - for (i=0; i < files; i++) - size += field.files[i].size; + if (!files || !this.file_upload_size_check(field.files)) + return; - if (size > maxsize) { - alert(rcmail.get_label('kolab_files.uploadsizeerror').replace('$size', this.file_size(maxsize))); - return; + // submit form and read server response + this.file_upload_form(form, 'file_upload', function(event) { + var doc, response; + try { + doc = this.contentDocument ? this.contentDocument : this.contentWindow.document; + response = doc.body.innerHTML; + // response may be wrapped in
 tag
+        if (response.slice(0, 5).toLowerCase() == '
' && response.slice(-6).toLowerCase() == '
') { + response = doc.body.firstChild.firstChild.nodeValue; } + response = eval('(' + response + ')'); + } + catch (err) { + response = {status: 'ERROR'}; } - // submit form and read server response - this.file_upload_form(form, 'file_upload', function(event) { - var doc, response; - try { - doc = this.contentDocument ? this.contentDocument : this.contentWindow.document; - response = doc.body.innerHTML; - // response may be wrapped in
 tag
-          if (response.slice(0, 5).toLowerCase() == '
' && response.slice(-6).toLowerCase() == '
') { - response = doc.body.firstChild.firstChild.nodeValue; - } - response = eval('(' + response + ')'); - } catch (err) { - response = {status: 'ERROR'}; - } + rcmail.hide_message(event.data.ts); - rcmail.hide_message(event.data.ts); + // refresh the list on upload success + file_api.file_upload_response(response); + }); + }; - // refresh the list on upload success - if (file_api.response_parse(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 this.file_upload_form = function(form, action, onload) { @@ -1861,6 +1909,97 @@ function kolab_files_ui() .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 this.file_open = function(file, viewer) { diff --git a/plugins/kolab_files/skins/larry/style.css b/plugins/kolab_files/skins/larry/style.css index 94ae49e7..d64253c7 100644 --- a/plugins/kolab_files/skins/larry/style.css +++ b/plugins/kolab_files/skins/larry/style.css @@ -288,6 +288,24 @@ 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 */ #files-dialog,