diff --git a/plugins/kolab_files/kolab_files.js b/plugins/kolab_files/kolab_files.js index 1a8106a4..81a618f8 100644 --- a/plugins/kolab_files/kolab_files.js +++ b/plugins/kolab_files/kolab_files.js @@ -1,2276 +1,2276 @@ /** * Kolab files plugin * * @author Aleksander Machniak <machniak@kolabsys.com> * * @licstart The following is the entire license notice for the * JavaScript code in this file. * * Copyright (C) 2011, Kolab Systems AG <contact@kolabsys.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * @licend The above is the entire license notice * for the JavaScript code in this file. */ window.rcmail && window.files_api && rcmail.addEventListener('init', function() { if (rcmail.task == 'mail') { // mail compose if (rcmail.env.action == 'compose') { var elem = $('#compose-attachments > div'), input = $('<input class="button" type="button">') .attr('tabindex', $('input', elem).attr('tabindex') || 0) .val(rcmail.gettext('kolab_files.fromcloud')) .click(function() { kolab_files_selector_dialog(); }) .appendTo(elem); if (rcmail.gui_objects.filelist) { rcmail.file_list = new rcube_list_widget(rcmail.gui_objects.filelist, { multiselect: true, keyboard: true, column_movable: false, dblclick_time: rcmail.dblclick_time }); rcmail.file_list.addEventListener('select', function(o) { kolab_files_list_select(o); }) .addEventListener('listupdate', function(e) { rcmail.triggerEvent('listupdate', e); }); rcmail.enable_command('files-sort', 'files-search', 'files-search-reset', true); rcmail.file_list.init(); kolab_files_list_coltypes(); } // register some commands to skip warning message on compose page $.merge(rcmail.env.compose_commands, ['files-list', 'files-sort', 'files-search', 'files-search-reset']); } // mail preview else if (rcmail.env.action == 'show' || rcmail.env.action == 'preview') { var attachment_list = $('#attachment-list'); if ($('li', attachment_list).length) { var link = $('<a href="#" class="button filesaveall">') .text(rcmail.gettext('kolab_files.saveall')) .click(function() { kolab_directory_selector_dialog(); }) .insertAfter(attachment_list); } rcmail.addEventListener('menu-open', kolab_files_attach_menu_open); rcmail.enable_command('folder-create', true); } // attachment preview else if (rcmail.env.action == 'get') { rcmail.enable_command('folder-create', true); } kolab_files_init(); } else if (rcmail.task == 'files') { if (rcmail.gui_objects.filelist) { rcmail.file_list = new rcube_list_widget(rcmail.gui_objects.filelist, { multiselect: true, draggable: true, keyboard: true, column_movable: rcmail.env.col_movable, dblclick_time: rcmail.dblclick_time }); /* rcmail.file_list.row_init = function(o){ kolab_files_init_file_row(o); }; rcmail.file_list.addEventListener('dblclick', function(o){ p.msglist_dbl_click(o); }); rcmail.file_list.addEventListener('click', function(o){ p.msglist_click(o); }); rcmail.file_list.addEventListener('keypress', function(o){ p.msglist_keypress(o); }); rcmail.file_list.addEventListener('dragstart', function(o){ p.drag_start(o); }); rcmail.file_list.addEventListener('dragmove', function(e){ p.drag_move(e); }); */ rcmail.file_list.addEventListener('dblclick', function(o) { kolab_files_list_dblclick(o); }) .addEventListener('select', function(o) { kolab_files_list_select(o); }) .addEventListener('keypress', function(o) { kolab_files_list_keypress(o); }) .addEventListener('dragend', function(e) { kolab_files_drag_end(e); }) .addEventListener('column_replace', function(e) { kolab_files_set_coltypes(e); }) .addEventListener('listupdate', function(e) { rcmail.triggerEvent('listupdate', 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 rcmail.env.file_commands = ['files-get']; // "one or more file" commands rcmail.env.file_commands_all = ['files-delete', 'files-move', 'files-copy']; kolab_files_init(); if (rcmail.env.action == 'open') { rcmail.enable_command('files-get', 'files-delete', rcmail.env.file); } else { file_api.folder_list(); file_api.browser_capabilities_check(); rcmail.enable_command('folder-mount', rcmail.env.external_sources); } } }); /**********************************************************/ /********* Shared functionality **********/ /**********************************************************/ // Initializes API object function kolab_files_init() { if (window.file_api) return; // Initialize application object (don't change var name!) file_api = $.extend(new files_api(), new kolab_files_ui()); file_api.set_env({ token: kolab_files_token(), url: rcmail.env.files_url, sort_col: 'name', sort_reverse: false, search_threads: rcmail.env.search_threads, resources_dir: rcmail.assets_path('program/resources'), supported_mimetypes: rcmail.env.file_mimetypes }); file_api.translations = rcmail.labels; }; // returns API authorization token function kolab_files_token() { // consider the token from parent window more reliable (fresher) than in framed window // it's because keep-alive is not requested in frames return window.parent && parent.rcmail && parent.rcmail.env.files_token ? parent.rcmail.env.files_token : rcmail.env.files_token; }; // folder selection dialog function kolab_directory_selector_dialog(id) { var dialog = $('#files-dialog'), input = $('#file-save-as-input'), form = $('#file-save-as'), list = $('#folderlistbox'), buttons = {}, label = 'saveto', win = window, fn; // attachment is specified if (id) { var attach = $('#attach' + id + '> a').first(), filename = attach.attr('title'); if (!filename) { attach = attach.clone(); $('.attachment-size', attach).remove(); filename = attach.text(); } form.show(); dialog.addClass('saveas'); input.val(filename); } // attachment preview page else if (rcmail.env.action == 'get') { id = rcmail.env.part; form.show(); dialog.addClass('saveas'); input.val(rcmail.env.filename); } else { form.hide(); dialog.removeClass('saveas'); label = 'saveall'; } $('#foldercreatelink').attr('tabindex', 0); buttons[rcmail.gettext('kolab_files.save')] = function () { var lock = rcmail.set_busy(true, 'saving'), request = { act: 'save-file', source: rcmail.env.mailbox, uid: rcmail.env.uid, dest: file_api.env.folder }; if (id) { request.id = id; request.name = input.val(); } rcmail.http_post('plugin.kolab_files', request, lock); kolab_dialog_close(this); }; buttons[rcmail.gettext('kolab_files.cancel')] = function () { kolab_dialog_close(this); }; if (!rcmail.env.folders_loaded) { fn = function() { file_api.folder_list(); rcmail.env.folders_loaded = true; }; } // show dialog window kolab_dialog_show(dialog, { title: rcmail.gettext('kolab_files.' + label), buttons: buttons, button_classes: ['mainaction'], minWidth: 250, minHeight: 300, height: 350, width: 300 }, fn); // "enable" folder creation when dialog is displayed in parent window if (rcmail.is_framed() && !parent.rcmail.folder_create) { parent.rcmail.enable_command('folder-create', true); parent.rcmail.folder_create = function() { win.kolab_files_folder_create_dialog(); }; } }; // file selection dialog function kolab_files_selector_dialog() { var dialog = $('#files-compose-dialog'), buttons = {}; buttons[rcmail.gettext('kolab_files.attachsel')] = function () { var list = []; $('#filelist tr.selected').each(function() { list.push($(this).data('file')); }); kolab_dialog_close(this); if (list.length) { // display upload indicator and cancel button var content = '<span>' + rcmail.get_label('kolab_files.attaching') + '</span>', id = new Date().getTime(); rcmail.add2attachment_list(id, {name:'', html:content, classname:'uploading', complete:false}); // send request rcmail.http_post('plugin.kolab_files', { act: 'attach-file', files: list, id: rcmail.env.compose_id, uploadid: id }); } }; buttons[rcmail.gettext('kolab_files.cancel')] = function () { kolab_dialog_close(this); }; // show dialog window kolab_dialog_show(dialog, { title: rcmail.gettext('kolab_files.selectfiles'), buttons: buttons, button_classes: ['mainaction'], minWidth: 500, minHeight: 300, width: 700, height: 500 }); if (!rcmail.env.files_loaded) { file_api.folder_list(); rcmail.env.files_loaded = true; } else { rcmail.file_list.clear_selection(); } }; function kolab_files_attach_menu_open(p) { if (!p || !p.props || p.props.menu != 'attachmentmenu') return; var id = p.props.id; $('#attachmenusaveas').unbind('click').attr('onclick', '').click(function(e) { return kolab_directory_selector_dialog(id); }); }; // folder creation dialog function kolab_files_folder_create_dialog() { var dialog = $('#files-folder-create-dialog'), buttons = {}, select = $('select[name="parent"]', dialog).html(''), input = $('input[name="name"]', dialog).val(''); buttons[rcmail.gettext('kolab_files.create')] = function () { var folder = '', name = input.val(), parent = select.val(); if (!name) return; if (parent) folder = parent + file_api.env.directory_separator; folder += name; file_api.folder_create(folder); kolab_dialog_close(this); }; buttons[rcmail.gettext('kolab_files.cancel')] = function () { kolab_dialog_close(this); }; // show dialog window kolab_dialog_show(dialog, { title: rcmail.gettext('kolab_files.foldercreate'), buttons: buttons, button_classes: ['mainaction'] }); // Fix submitting form with Enter $('form', dialog).submit(kolab_dialog_submit_handler); // build parent selector select.append($('<option>').val('').text('---')); $.each(file_api.env.folders, function(i, f) { var n, option = $('<option>'), name = escapeHTML(f.name); for (n=0; n<f.depth; n++) name = ' ' + name; option.val(i).html(name).appendTo(select); if (i == file_api.env.folder) option.attr('selected', true); }); }; // folder edit dialog function kolab_files_folder_edit_dialog() { var dialog = $('#files-folder-edit-dialog'), buttons = {}, options = [], separator = file_api.env.directory_separator, arr = file_api.env.folder.split(separator), folder = arr.pop(), path = arr.join(separator), select = $('select[name="parent"]', dialog).html(''), input = $('input[name="name"]', dialog).val(folder); buttons[rcmail.gettext('kolab_files.save')] = function () { var folder = '', name = input.val(), parent = select.val(); if (!name) return; if (parent) folder = parent + separator; folder += name; file_api.folder_rename(file_api.env.folder, folder); kolab_dialog_close(this); }; buttons[rcmail.gettext('kolab_files.cancel')] = function () { kolab_dialog_close(this); }; // show dialog window kolab_dialog_show(dialog, { title: rcmail.gettext('kolab_files.folderedit'), buttons: buttons, button_classes: ['mainaction'] }); // Fix submitting form with Enter $('form', dialog).submit(kolab_dialog_submit_handler); // build parent selector options.push($('<option>').val('').text('---')); $.each(file_api.env.folders, function(i, f) { var n, name = escapeHTML(f.name); for (n=0; n<f.depth; n++) name = ' ' + name; options.push($('<option>').val(i).html(name)); }); select.append(options).val(path); }; // folder mounting dialog function kolab_files_folder_mount_dialog() { var args = {buttons: {}, title: rcmail.gettext('kolab_files.foldermount')}, dialog = $('#files-folder-mount-dialog'), input = $('#folder-mount-name').val(''); args.buttons[rcmail.gettext('kolab_files.save')] = function () { var args = {}, folder = input.val(), driver = $('input[name="driver"]:checked', dialog).val(); if (!folder || !driver) return; args.folder = folder; args.driver = driver; $('#source-' + driver + ' input').each(function() { if (this.name.startsWith(driver + '[')) { args[this.name.substring(driver.length + 1, this.name.length - 1)] = this.value; } }); $('.auth-options input', dialog).each(function() { args[this.name] = this.type == 'checkbox' && !this.checked ? '' : this.value; }); file_api.folder_mount(args); kolab_dialog_close(this); }; args.buttons[rcmail.gettext('kolab_files.cancel')] = function () { kolab_dialog_close(this); }; // close folderoption menu rcmail.hide_menu('folderoptions'); // initialize drivers list if (!rcmail.drivers_list_initialized) { rcmail.drivers_list_initialized = true; $('td.source', dialog).each(function() { $(this).click(function() { $('td.selected', dialog).removeClass('selected'); dialog.find('.driverform').hide(); $(this).addClass('selected').find('.driverform').show(); $('input[type="radio"]', this).prop('checked', true); }); }); } args.button_classes = ['mainaction']; // show dialog window kolab_dialog_show(dialog, args, function() { $('td.source:first', dialog).click(); input.focus(); }); }; // file edition dialog function kolab_files_file_edit_dialog(file) { var dialog = $('#files-file-edit-dialog'), buttons = {}, name = file_api.file_name(file) input = $('input[name="name"]', dialog).val(name); buttons[rcmail.gettext('kolab_files.save')] = function () { var folder = file_api.file_path(file), name = input.val(); if (!name) return; name = folder + file_api.env.directory_separator + name; // @TODO: now we only update filename if (name != file) file_api.file_rename(file, name); kolab_dialog_close(this); }; buttons[rcmail.gettext('kolab_files.cancel')] = function () { kolab_dialog_close(this); }; // Fix submitting form with Enter $('form', dialog).submit(kolab_dialog_submit_handler); // show dialog window kolab_dialog_show(dialog, { title: rcmail.gettext('kolab_files.fileedit'), buttons: buttons, button_classes: ['mainaction'] }); }; function kolab_dialog_show(content, params, onopen) { params = $.extend({ modal: true, resizable: true, closeOnEscape: (!bw.ie6 && !bw.ie7), // disabled for performance reasons minWidth: 400, minHeight: 300, width: 500, height: 400 }, params || {}); // dialog close handler params.close = function(e, ui) { var elem, stack = rcmail.dialog_stack; content.appendTo(document.body).hide(); $(this).parent().remove(); // remove dialog // focus previously focused element (guessed) stack.pop(); if (stack.length) { elem = stack[stack.length-1].find('input[type!="hidden"]:not(:hidden):first'); if (!elem.length) elem = stack[stack.length-1].parent().find('a[role="button"], .ui-dialog-buttonpane button').first(); } (elem && elem.length ? elem : window).focus(); }; // display it as popup var dialog = rcmail.show_popup_dialog('', params.title, params.buttons, params); content.appendTo(dialog).show().find('input[type!="hidden"]:not(:hidden):first').focus(); if (onopen) onopen(content); // save dialog reference, to handle focus when closing one of opened dialogs if (!rcmail.dialog_stack) rcmail.dialog_stack = []; rcmail.dialog_stack.push(dialog); }; // Handle form submit with Enter key, click first dialog button instead function kolab_dialog_submit_handler() { $(this).parents('.ui-dialog').find('.ui-button').first().click(); return false; }; // Hides dialog function kolab_dialog_close(dialog) { (rcmail.is_framed() ? window.parent : window).$(dialog).dialog('close'); }; // smart upload button function kolab_files_upload_input(button) { var link = $(button), file = $('<input>'), offset = link.offset(); function move_file_input(e) { file.css({top: (e.pageY - offset.top - 10) + 'px', left: (e.pageX - offset.left - 10) + 'px'}); } file.attr({name: 'file[]', type: 'file', multiple: 'multiple', size: 5, title: link.attr('title'), tabindex: "-1"}) .change(function() { rcmail.files_upload('#filesuploadform'); }) .click(function() { setTimeout(function() { link.mouseleave(); }, 20); }) // opacity:0 does the trick, display/visibility doesn't work .css({opacity: 0, cursor: 'pointer', outline: 'none', position: 'absolute'}); // In FF and IE we need to move the browser file-input's button under the cursor // Thanks to the size attribute above we know the length of the input field if (bw.mz || bw.ie) file.css({marginLeft: '-80px'}); // Note: now, I observe problem with cursor style on FF < 4 only // Need position: relative (Bug #2615) link.css({overflow: 'hidden', cursor: 'pointer', position: 'relative'}) .mouseenter(function() { this.__active = true; }) // place button under the cursor .mousemove(function(e) { if (rcmail.commands['files-upload'] && this.__active) move_file_input(e); // move the input away if button is disabled else $(this).mouseleave(); }) .mouseleave(function() { file.css({top: '-10000px', left: '-10000px'}); this.__active = false; }) .attr('onclick', '') // remove default button action .click(function(e) { // forward click if mouse-enter event was missed if (rcmail.commands['files-upload'] && !this.__active) { this.__active = true; move_file_input(e); file.trigger(e); } }) .mouseleave() // initially disable/hide input .append(file); }; /***********************************************************/ /********** Main functionality **********/ /***********************************************************/ // for reordering column array (Konqueror workaround) // and for setting some message list global variables kolab_files_list_coltypes = function() { var n, list = rcmail.file_list; rcmail.env.subject_col = null; if ((n = $.inArray('name', rcmail.env.coltypes)) >= 0) { rcmail.env.subject_col = n; list.subject_col = n; } list.init_header(); }; kolab_files_set_list_options = function(cols, sort_col, sort_order) { var update = 0, i, idx, name, newcols = [], oldcols = rcmail.env.coltypes; if (sort_col === undefined) sort_col = rcmail.env.sort_col; if (!sort_order) sort_order = rcmail.env.sort_order; if (rcmail.env.sort_col != sort_col || rcmail.env.sort_order != sort_order) { update = 1; rcmail.set_list_sorting(sort_col, sort_order); } if (cols && cols.length) { // make sure new columns are added at the end of the list for (i=0; i<oldcols.length; i++) { name = oldcols[i]; idx = $.inArray(name, cols); if (idx != -1) { newcols.push(name); delete cols[idx]; } } for (i=0; i<cols.length; i++) if (cols[i]) newcols.push(cols[i]); if (newcols.join() != oldcols.join()) { update += 2; oldcols = newcols; } } if (update == 1) rcmail.command('files-list', {sort: sort_col, reverse: sort_order == 'DESC'}); else if (update) { rcmail.http_post('files/prefs', { kolab_files_list_cols: oldcols, kolab_files_sort_col: sort_col, kolab_files_sort_order: sort_order }, rcmail.set_busy(true, 'loading')); } }; kolab_files_set_coltypes = function(list) { var i, found, name, cols = list.list.tHead.rows[0].cells; rcmail.env.coltypes = []; for (i=0; i<cols.length; i++) if (cols[i].id && cols[i].id.match(/^rcm/)) { name = cols[i].id.replace(/^rcm/, ''); rcmail.env.coltypes.push(name); } // if ((found = $.inArray('name', rcmail.env.coltypes)) >= 0) // rcmail.env.subject_col = found; rcmail.env.subject_col = list.subject_col; rcmail.http_post('files/prefs', {kolab_files_list_cols: rcmail.env.coltypes}); }; kolab_files_list_dblclick = function(list) { rcmail.command('files-open'); }; kolab_files_list_select = function(list) { var selected = list.selection.length; rcmail.enable_command(rcmail.env.file_commands_all, selected); rcmail.enable_command(rcmail.env.file_commands, selected == 1); // reset all-pages-selection // if (list.selection.length && list.selection.length != list.rowcount) // rcmail.select_all_mode = false; // enable files- if (selected == 1) { // get file mimetype var type = $('tr.selected', list.list).data('type'); rcmail.env.viewer = file_api.file_type_supported(type); } else rcmail.env.viewer = 0; /* ) { // caps = this.browser_capabilities().join(); href = '?' + $.param({_task: 'files', _action: 'open', file: file, viewer: viewer == 2 ? 1 : 0}); var win = window.open(href, rcmail.html_identifier('rcubefile'+file)); if (win) setTimeout(function() { win.focus(); }, 10); } */ rcmail.enable_command('files-open', rcmail.env.viewer); }; kolab_files_list_keypress = function(list) { if (list.modkey == CONTROL_KEY) return; if (list.key_pressed == list.ENTER_KEY) rcmail.command('files-open'); else if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY) rcmail.command('files-delete'); }; kolab_files_drag_end = function(e) { var folder = $('#files-folder-list li.droptarget').removeClass('droptarget'); if (folder.length) { folder = folder.data('folder'); var modkey = rcube_event.get_modifier(e), menu = rcmail.gui_objects.file_dragmenu; if (menu && modkey == SHIFT_KEY && rcmail.commands['files-copy']) { var pos = rcube_event.get_mouse_pos(e); rcmail.env.drag_target = folder; $(menu).css({top: (pos.y-10)+'px', left: (pos.x-10)+'px'}).show(); return; } rcmail.command('files-move', folder); } }; kolab_files_drag_menu_action = function(command) { var menu = rcmail.gui_objects.file_dragmenu; if (menu) $(menu).hide(); rcmail.command(command, rcmail.env.drag_target); }; kolab_files_selected = function() { var files = []; $.each(rcmail.file_list.get_selection(), function(i, v) { var name, row = $('#rcmrow'+v); if (row.length == 1 && (name = row.data('file'))) files.push(name); }); return files; }; kolab_files_frame_load = function(frame) { var win = frame.contentWindow; rcmail.file_editor = win.file_editor && win.file_editor.editable ? win.file_editor : null; if (rcmail.file_editor) rcmail.enable_command('files-edit', true); rcmail.enable_command('files-print', (rcmail.file_editor && rcmail.file_editor.printable) || (rcmail.env.file_data && /^image\//i.test(rcmail.env.file_data.type))); // detect Print button and check if it can be accessed try { if ($('#fileframe').contents().find('#print').length) rcmail.enable_command('files-print', true); } 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; } if (!container.length) 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'); }; // returns localized file size kolab_files_file_size = function(size) { var i, units = ['GB', 'MB', 'KB', 'B']; size = file_api.file_size(size); for (i = 0; i < units.length; i++) if (size.toUpperCase().indexOf(units[i]) > 0) return size.replace(units[i], rcmail.gettext(units[i])); return size; }; kolab_files_progress_str = function(param) { var current, total = file_api.file_size(param.total).toUpperCase(); if (total.indexOf('GB') > 0) current = parseFloat(param.current/1073741824).toFixed(1); else if (total.indexOf('MB') > 0) current = parseFloat(param.current/1048576).toFixed(1); else if (total.indexOf('KB') > 0) current = parseInt(param.current/1024); else current = param.current; total = kolab_files_file_size(param.total); return rcmail.gettext('uploadprogress') .replace(/\$percent/, param.percent + '%') .replace(/\$current/, current) .replace(/\$total/, total); }; /***********************************************************/ /********** Commands **********/ /***********************************************************/ rcube_webmail.prototype.files_sort = function(props) { var params = {}, sort_order = this.env.sort_order, sort_col = !this.env.disabled_sort_col ? props : this.env.sort_col; if (!this.env.disabled_sort_order) sort_order = this.env.sort_col == sort_col && sort_order == 'ASC' ? 'DESC' : 'ASC'; // set table header and update env this.set_list_sorting(sort_col, sort_order); this.http_post('files/prefs', {kolab_files_sort_col: sort_col, kolab_files_sort_order: sort_order}); params.sort = sort_col; params.reverse = sort_order == 'DESC'; this.command('files-list', params); }; rcube_webmail.prototype.files_search = function() { var value = $(this.gui_objects.filesearchbox).val(); if (value) file_api.file_search(value, $('#search_all_folders').is(':checked')); else file_api.file_search_reset(); }; rcube_webmail.prototype.files_search_reset = function() { $(this.gui_objects.filesearchbox).val(''); file_api.file_search_reset(); }; rcube_webmail.prototype.files_folder_delete = function() { if (confirm(this.get_label('kolab_files.folderdeleteconfirm'))) file_api.folder_delete(file_api.env.folder); }; rcube_webmail.prototype.files_delete = function() { if (!confirm(this.get_label('kolab_files.filedeleteconfirm'))) return; var files = this.env.file ? [this.env.file] : kolab_files_selected(); file_api.file_delete(files); }; rcube_webmail.prototype.files_move = function(folder) { var files = kolab_files_selected(); file_api.file_move(files, folder); }; rcube_webmail.prototype.files_copy = function(folder) { var files = kolab_files_selected(); file_api.file_copy(files, folder); }; rcube_webmail.prototype.files_upload = function(form) { if (form) file_api.file_upload(form); }; rcube_webmail.prototype.files_list = function(param) { // just rcmail wrapper, to handle command busy states file_api.file_list(param); } rcube_webmail.prototype.files_list_update = function(head) { var list = this.file_list; list.clear(); $('thead', list.fixed_header ? list.fixed_header : list.list).html(head); kolab_files_list_coltypes(); file_api.file_list(); }; rcube_webmail.prototype.files_get = function() { var files = this.env.file ? [this.env.file] : kolab_files_selected(); if (files.length == 1) file_api.file_get(files[0], {'force-download': true}); }; rcube_webmail.prototype.files_open = function() { var files = kolab_files_selected(); if (files.length == 1) file_api.file_open(files[0], rcmail.env.viewer); }; // enable file editor rcube_webmail.prototype.files_edit = function() { if (this.file_editor) { this.file_editor.enable(); this.enable_command('files-save', true); } }; rcube_webmail.prototype.files_save = function() { if (!this.file_editor) return; // binary files like ODF need to be updated using FormData if (this.file_editor.getContentCallback) { if (!file_api.file_uploader_support()) return; file_api.req = file_api.set_busy(true, 'saving'); // this.file_editor.disable(); this.file_editor.getContentCallback(function(content, filename) { file_api.file_uploader([content], { action: 'file_update', params: {file: rcmail.env.file, info: 1, token: file_api.env.token}, response_handler: 'file_save_response', fieldname: 'content', single: true }); }); return; } var content = this.file_editor.getContent(); file_api.file_save(this.env.file, content); }; rcube_webmail.prototype.files_print = function() { if (this.file_editor && this.file_editor.printable) this.file_editor.print(); else if (/^image\//i.test(this.env.file_data.type)) { var frame = $('#fileframe').get(0), win = frame ? frame.contentWindow : null; if (win) { win.focus(); win.print(); } } else { // e.g. Print button in PDF viewer try { $('#fileframe').contents().find('#print').click(); } catch(e) {}; } }; rcube_webmail.prototype.files_set_quota = function(p) { if (p.total && window.file_api) { p.used *= 1024; p.total *= 1024; p.title = file_api.file_size(p.used) + ' / ' + file_api.file_size(p.total) + ' (' + p.percent + '%)'; } p.type = this.env.quota_type; this.set_quota(p); }; rcube_webmail.prototype.folder_create = function() { kolab_files_folder_create_dialog(); }; rcube_webmail.prototype.folder_rename = function() { kolab_files_folder_edit_dialog(); }; rcube_webmail.prototype.folder_mount = function() { kolab_files_folder_mount_dialog(); }; /**********************************************************/ /********* Files API handler **********/ /**********************************************************/ function kolab_files_ui() { this.requests = {}; this.uploads = []; /* // Called on "session expired" session this.logout = function(response) {}; // called when a request timed out this.request_timed_out = function() {}; // called on start of the request this.set_request_time = function() {}; // called on request response this.update_request_time = function() {}; */ // set state this.set_busy = function(a, message) { if (this.req) rcmail.hide_message(this.req); return rcmail.set_busy(a, message); }; // displays error message this.display_message = function(label, type) { return rcmail.display_message(this.t(label), type); }; this.http_error = function(request, status, err) { rcmail.http_error(request, status, err); }; // folders list request this.folder_list = function() { this.req = this.set_busy(true, 'loading'); this.request('folder_list', {}, 'folder_list_response'); }; // folder list response handler this.folder_list_response = function(response) { if (!this.response(response)) return; var first, elem = $('#files-folder-list'), list = $('<ul class="listing"></ul>'), collections = !rcmail.env.action.match(/^(preview|show)$/) ? ['audio', 'video', 'image', 'document'] : []; // try parent window if the list element does not exist // i.e. called from dialog in parent window if (!elem.length && window.parent && parent.rcmail) { elem = $('#files-folder-list', window.parent.document.body); } elem.html('').append(list); this.env.folders = this.folder_list_parse(response.result && response.result.list ? response.result.list : response.result); $.each(this.env.folders, function(i, f) { list.append(file_api.folder_list_row(i, f)); if (!first) first = i; }); // add virtual collections $.each(collections, function(i, n) { var row = $('<li class="mailbox collection ' + n + '"></li>'); row.attr({id: 'folder-collection-' + n, tabindex: 0}) .append($('<span class="name"></span>').text(rcmail.gettext('kolab_files.collection_' + n))) .click(function() { file_api.folder_select(n, true); }); list.append(row); }); // select first folder? if (this.env.folder) this.folder_select(this.env.folder); else if (this.env.collection) this.folder_select(this.env.collection, true); else if (first) this.folder_select(first); // add tree icons this.folder_list_tree(this.env.folders); // handle authentication errors on external sources this.folder_list_auth_errors(response.result); }; this.folder_select = function(folder, is_collection) { if (rcmail.busy) return; var list = $('#files-folder-list > ul'); // try parent window if the list element does not exist // i.e. called from dialog in parent window if (!list.length && window.parent && parent.rcmail) { list = $('#files-folder-list > ul', window.parent.document.body); } $('li.selected', list).removeClass('selected'); rcmail.enable_command('files-list', true); if (is_collection) { var found = $('#folder-collection-' + folder, list).addClass('selected'); rcmail.enable_command('files-folder-delete', 'folder-rename', 'files-upload', false); this.env.folder = null; rcmail.command('files-list', {collection: folder}); } else { var found = $('#' + this.env.folders[folder].id, list).addClass('selected'); rcmail.enable_command('files-folder-delete', 'folder-rename', 'files-upload', true); this.env.folder = folder; this.env.collection = null; rcmail.command('files-list', {folder: folder}); } this.quota(); }; this.folder_unselect = function() { var list = $('#files-folder-list > ul'); $('li.selected', list).removeClass('selected'); rcmail.enable_command('files-folder-delete', 'files-upload', false); this.env.folder = null; this.env.collection = null; }; this.folder_list_row = function(i, folder) { var row = $('<li class="mailbox"><span class="branch"></span></li>'); row.attr('id', folder.id).data('folder', i) .append($('<span class="name"></span>').text(folder.name)); if (folder.depth) { $('span.branch', row).width(15 * folder.depth); row.addClass('child'); } if (folder.virtual) row.addClass('virtual'); else row.attr('tabindex', 0) .keypress(function(e) { if (e.which == 13 || e.which == 32) file_api.folder_select(i); }) .click(function() { file_api.folder_select(i); }) .mouseenter(function() { if (rcmail.file_list && rcmail.file_list.drag_active && !$(this).hasClass('selected')) $(this).addClass('droptarget'); }) .mouseleave(function() { if (rcmail.file_list && rcmail.file_list.drag_active) $(this).removeClass('droptarget'); }); return row; }; // folder create request this.folder_create = function(folder) { this.req = this.set_busy(true, 'kolab_files.foldercreating'); this.request('folder_create', {folder: folder}, 'folder_create_response'); }; // folder create response handler this.folder_create_response = function(response) { if (!this.response(response)) return; this.display_message('kolab_files.foldercreatenotice', 'confirmation'); // refresh folders list this.folder_list(); }; // folder rename request this.folder_rename = function(folder, new_name) { if (folder == new_name) return; this.env.folder_rename = new_name; this.req = this.set_busy(true, 'kolab_files.folderupdating'); this.request('folder_move', {folder: folder, 'new': new_name}, 'folder_rename_response'); }; // folder create response handler this.folder_rename_response = function(response) { if (!this.response(response)) return; this.display_message('kolab_files.folderupdatenotice', 'confirmation'); // refresh folders and files list this.env.folder = this.env.folder_rename; this.folder_list(); }; // folder mount (external storage) request this.folder_mount = function(data) { this.req = this.set_busy(true, 'kolab_files.foldermounting'); this.request('folder_create', data, 'folder_mount_response'); }; // folder create response handler this.folder_mount_response = function(response) { if (!this.response(response)) return; this.display_message('kolab_files.foldermountnotice', 'confirmation'); // refresh folders list this.folder_list(); }; // folder delete request this.folder_delete = function(folder) { this.req = this.set_busy(true, 'kolab_files.folderdeleting'); this.request('folder_delete', {folder: folder}, 'folder_delete_response'); }; // folder delete response handler this.folder_delete_response = function(response) { if (!this.response(response)) return; this.env.folder = null; rcmail.enable_command('files-folder-delete', 'folder-rename', 'files-list', false); this.display_message('kolab_files.folderdeletenotice', 'confirmation'); // refresh folders list this.folder_list(); this.quota(); }; // quota request this.quota = function() { if (rcmail.env.files_quota) this.request('quota', {folder: this.env.folder}, 'quota_response'); }; // quota response handler this.quota_response = function(response) { if (!this.response(response)) return; rcmail.files_set_quota(response.result); }; this.file_list = function(params) { if (!rcmail.gui_objects.filelist) return; if (!params) params = {}; // reset all pending list requests for (i in this.requests) { this.requests[i].abort(); rcmail.hide_message(i); delete this.requests[i]; } if (params.all_folders) { params.collection = null; params.folder = null; this.folder_unselect(); } if (params.collection == undefined) params.collection = this.env.collection; if (params.folder == undefined) params.folder = this.env.folder; if (params.sort == undefined) params.sort = this.env.sort_col; if (params.reverse == undefined) params.reverse = this.env.sort_reverse; if (params.search == undefined) params.search = this.env.search; this.env.folder = params.folder; this.env.collection = params.collection; this.env.sort_col = params.sort; this.env.sort_reverse = params.reverse; rcmail.enable_command(rcmail.env.file_commands, false); rcmail.enable_command(rcmail.env.file_commands_all, false); // empty the list this.env.file_list = []; rcmail.file_list.clear(true); // request if (params.collection || params.all_folders) this.file_list_loop(params); else if (this.env.folder) { params.req_id = this.set_busy(true, 'loading'); this.requests[params.req_id] = this.request('file_list', params, 'file_list_response'); } }; // file list response handler this.file_list_response = function(response) { if (response.req_id) rcmail.hide_message(response.req_id); if (!this.response(response)) return; var i = 0, list = [], table = $('#filelist'); $.each(response.result, function(key, data) { var row = file_api.file_list_row(key, data, ++i); rcmail.file_list.insert_row(row); data.row = row; data.filename = key; list.push(data); }); this.env.file_list = list; rcmail.file_list.resize(); }; // call file_list request for every folder (used for search and virt. collections) this.file_list_loop = function(params) { var i, folders = [], limit = Math.max(this.env.search_threads || 1, 1); if (params.collection) { if (!params.search) params.search = {}; params.search['class'] = params.collection; delete params['collection']; } delete params['all_folders']; $.each(this.env.folders, function(i, f) { if (!f.virtual) folders.push(i); }); this.env.folders_loop = folders; this.env.folders_loop_params = params; this.env.folders_loop_lock = false; for (i=0; i<folders.length && i<limit; i++) { params.req_id = this.set_busy(true, 'loading'); params.folder = folders.shift(); this.requests[params.req_id] = this.request('file_list', params, 'file_list_loop_response'); } }; // file list response handler for loop'ed request this.file_list_loop_response = function(response) { var i, folders = this.env.folders_loop, params = this.env.folders_loop_params, limit = Math.max(this.env.search_threads || 1, 1), valid = this.response(response); if (response.req_id) rcmail.hide_message(response.req_id); for (i=0; i<folders.length && i<limit; i++) { params.req_id = this.set_busy(true, 'loading'); params.folder = folders.shift(); this.requests[params.req_id] = this.request('file_list', params, 'file_list_loop_response'); } rcmail.file_list.resize(); if (!valid) return; this.file_list_loop_result_add(response.result); }; // add files from list request to the table (with sorting) this.file_list_loop_result_add = function(result) { // chack if result (hash-array) is empty if (!object_is_empty(result)) return; if (this.env.folders_loop_lock) { setTimeout(function() { file_api.file_list_loop_result_add(result); }, 100); return; } // lock table, other list responses will wait this.env.folders_loop_lock = true; var n, i, len, elem, list = [], rows = [], index = this.env.file_list.length, table = rcmail.file_list; for (n=0, len=index; n<len; n++) { elem = this.env.file_list[n]; for (i in result) { if (this.sort_compare(elem, result[i]) < 0) break; var row = this.file_list_row(i, result[i], ++index); table.insert_row(row, elem.row); result[i].row = row; result[i].filename = i; list.push(result[i]); delete result[i]; } list.push(elem); } // add the rest of rows $.each(result, function(key, data) { var row = file_api.file_list_row(key, data, ++index); table.insert_row(row); result[key].row = row; result[key].filename = key; list.push(result[key]); }); this.env.file_list = list; this.env.folders_loop_lock = false; }; // sort files list (without API request) this.file_list_sort = function(col, reverse) { var n, len, list = this.env.file_list, table = $('#filelist'), tbody = $('<tbody>'); this.env.sort_col = col; this.env.sort_reverse = reverse; if (!list || !list.length) return; // sort the list list.sort(function (a, b) { return file_api.sort_compare(a, b); }); // add rows to the new body for (n=0, len=list.length; n<len; n++) { tbody.append(list[n].row); } // replace table bodies $('tbody', table).replaceWith(tbody); }; this.file_list_row = function(file, data, index) { var c, col, row = ''; for (c in rcmail.env.coltypes) { c = rcmail.env.coltypes[c]; if (c == 'name') col = '<td class="name filename ' + this.file_type_class(data.type) + '">' + '<span>' + escapeHTML(data.name) + '</span></td>'; else if (c == 'mtime') col = '<td class="mtime">' + data.mtime + '</td>'; else if (c == 'size') col = '<td class="size">' + this.file_size(data.size) + '</td>'; else if (c == 'options') col = '<td class="options"><span></span></td>'; else col = '<td class="' + c + '"></td>'; row += col; } row = $('<tr>') .html(row) .attr({id: 'rcmrow' + index, 'data-file': file, 'data-type': data.type}); $('td.options > span', row).click(function(e) { kolab_files_file_edit_dialog(file); }); // collection (or search) lists files from all folders // display file name with full path as title if (!this.env.folder) $('td.name span', row).attr('title', file); return row.get(0); }; this.file_search = function(value, all_folders) { if (value) { this.env.search = {name: value}; rcmail.command('files-list', {search: this.env.search, all_folders: all_folders}); } else this.search_reset(); }; this.file_search_reset = function() { if (this.env.search) { this.env.search = null; rcmail.command('files-list'); } }; this.file_get = function(file, params) { if (!params) params = {}; params.token = this.env.token; params.file = file; rcmail.redirect(this.env.url + this.url('file_get', params)); }; // file(s) delete request this.file_delete = function(files) { this.req = this.set_busy(true, 'kolab_files.filedeleting'); this.request('file_delete', {file: files}, 'file_delete_response'); }; // file(s) delete response handler this.file_delete_response = function(response) { if (!this.response(response)) return; var rco, dir, self = this; this.display_message('kolab_files.filedeletenotice', 'confirmation'); if (rcmail.env.file) { rco = rcmail.opener(); dir = this.file_path(rcmail.env.file); // check if opener window contains files list, if not we can just close current window if (rco && rco.file_list && (opener.file_api.env.folder == dir || !opener.file_api.env.folder)) self = opener.file_api; else window.close(); } // @TODO: consider list modification "in-place" instead of full reload self.file_list(); self.quota(); if (rcmail.env.file) window.close(); }; // file(s) move request this.file_move = function(files, folder) { if (!files || !files.length || !folder) return; var count = 0, list = {}; $.each(files, function(i, v) { var name = folder + file_api.env.directory_separator + file_api.file_name(v); if (name != v) { list[v] = name; count++; } }); if (!count) return; this.req = this.set_busy(true, 'kolab_files.filemoving'); this.request('file_move', {file: list}, 'file_move_response'); }; // file(s) move response handler this.file_move_response = function(response) { if (!this.response(response)) return; if (response.result && response.result.already_exist && response.result.already_exist.length) this.file_move_ask_user(response.result.already_exist, true); else { this.display_message('kolab_files.filemovenotice', 'confirmation'); this.file_list(); } }; // file(s) copy request this.file_copy = function(files, folder) { if (!files || !files.length || !folder) return; var count = 0, list = {}; $.each(files, function(i, v) { var name = folder + file_api.env.directory_separator + file_api.file_name(v); if (name != v) { list[v] = name; count++; } }); if (!count) return; this.req = this.set_busy(true, 'kolab_files.filecopying'); this.request('file_copy', {file: list}, 'file_copy_response'); }; // file(s) copy response handler this.file_copy_response = function(response) { if (!this.response(response)) return; if (response.result && response.result.already_exist && response.result.already_exist.length) this.file_move_ask_user(response.result.already_exist); else { this.display_message('kolab_files.filecopynotice', 'confirmation'); this.quota(); } }; // when file move/copy operation returns file-exists error // this displays a dialog where user can decide to skip // or overwrite destination file(s) this.file_move_ask_user = function(list, move) { var file = list[0], buttons = {}, text = rcmail.gettext('kolab_files.filemoveconfirm').replace('$file', file.dst) dialog = $('<div></div>'); buttons[rcmail.gettext('kolab_files.fileoverwrite')] = function() { var file = list.shift(), f = {}, action = move ? 'file_move' : 'file_copy'; f[file.src] = file.dst; file_api.file_move_ask_list = list; file_api.file_move_ask_mode = move; dialog.dialog('destroy').remove(); file_api.req = file_api.set_busy(true, move ? 'kolab_files.filemoving' : 'kolab_files.filecopying'); file_api.request(action, {file: f, overwrite: 1}, 'file_move_ask_user_response'); }; if (list.length > 1) buttons[rcmail.gettext('kolab_files.fileoverwriteall')] = function() { var f = {}, action = move ? 'file_move' : 'file_copy'; $.each(list, function() { f[this.src] = this.dst; }); dialog.dialog('destroy').remove(); file_api.req = file_api.set_busy(true, move ? 'kolab_files.filemoving' : 'kolab_files.filecopying'); file_api.request(action, {file: f, overwrite: 1}, action + '_response'); }; var skip_func = function() { list.shift(); dialog.dialog('destroy').remove(); if (list.length) file_api.file_move_ask_user(list, move); else if (move) file_api.file_list(); }; buttons[rcmail.gettext('kolab_files.fileskip')] = skip_func; if (list.length > 1) buttons[rcmail.gettext('kolab_files.fileskipall')] = function() { dialog.dialog('destroy').remove(); if (move) file_api.file_list(); }; // open jquery UI dialog kolab_dialog_show(dialog.html(text), { close: skip_func, buttons: buttons, minWidth: 400, width: 400 }); }; // file move (with overwrite) response handler this.file_move_ask_user_response = function(response) { var move = this.file_move_ask_mode, list = this.file_move_ask_list; this.response(response); if (list && list.length) this.file_move_ask_user(list, mode); else { this.display_message('kolab_files.file' + (move ? 'move' : 'copy') + 'notice', 'confirmation'); if (move) this.file_list(); } }; // file(s) rename request this.file_rename = function(oldfile, newfile) { this.req = this.set_busy(true, 'kolab_files.fileupdating'); this.request('file_move', {file: oldfile, 'new': newfile}, 'file_rename_response'); }; // file(s) move response handler this.file_rename_response = function(response) { if (!this.response(response)) return; // @TODO: we could update metadata instead this.file_list(); }; // file upload request this.file_upload = function(form) { var form = $(form), field = $('input[type=file]', form).get(0), files = field.files ? field.files.length : field.value ? 1 : 0; if (!files || !this.file_upload_size_check(field.files)) 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 <pre> tag if (response.slice(0, 5).toLowerCase() == '<pre>' && response.slice(-6).toLowerCase() == '</pre>') { response = doc.body.firstChild.firstChild.nodeValue; } response = eval('(' + response + ')'); } catch (err) { response = {status: 'ERROR'}; } file_api.file_upload_progress_stop(event.data.ts); // refresh the list on upload success file_api.file_upload_response(response); }); }; // 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', kolab_files_file_size(maxsize))); return false; } } return true; }; // post the given form to a hidden iframe this.file_upload_form = function(form, action, onload) { var ts = new Date().getTime(), frame_name = 'fileupload' + ts; // upload progress support if (rcmail.env.files_progress_name) { var fname = rcmail.env.files_progress_name, field = $('input[name='+fname+']', form); if (!field.length) { field = $('<input>').attr({type: 'hidden', name: fname}); field.prependTo(form); } field.val(ts); this.file_upload_progress(ts, true); } rcmail.display_progress({name: ts}); // have to do it this way for IE // otherwise the form will be posted to a new window if (document.all) { var html = '<iframe id="'+frame_name+'" name="'+frame_name+'"' + ' src="' + rcmail.assets_path('program/resources/blank.gif') + '"' + ' style="width:0;height:0;visibility:hidden;"></iframe>'; document.body.insertAdjacentHTML('BeforeEnd', html); } // for standards-compliant browsers else $('<iframe>') .attr({name: frame_name, id: frame_name}) .css({border: 'none', width: 0, height: 0, visibility: 'hidden'}) .appendTo(document.body); // handle upload errors, parsing iframe content in onload $('#'+frame_name).on('load', {ts:ts}, onload); $(form).attr({ target: frame_name, action: this.env.url + this.url(action, {folder: this.env.folder, token: this.env.token}), method: 'POST' }).attr(form.encoding ? 'encoding' : 'enctype', 'multipart/form-data') .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) { var files = e.target.files || e.dataTransfer.files; if (!files || !files.length || !this.file_upload_size_check(files)) return; // prepare multipart form data composition var ts = new Date().getTime(), formdata = window.FormData ? new FormData() : null, fieldname = 'file[]', boundary = '------multipartformboundary' + (new Date).getTime(), dashdash = '--', crlf = '\r\n', multipart = dashdash + boundary + crlf; // inline function to submit the files to the server var submit_data = function() { var multiple = files.length > 1; rcmail.display_progress({name: ts}); if (rcmail.env.files_progress_name) file_api.file_upload_progress(ts, true); // 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_progress_stop(ts); file_api.file_upload_response(data); }, error: function(o, status, err) { file_api.file_upload_progress_stop(ts); rcmail.http_error(o, status, err); }, xhr: function() { var xhr = jQuery.ajaxSettings.xhr(); if (!formdata && xhr.sendAsBinary) xhr.send = xhr.sendAsBinary; return xhr; } }); }; // upload progress supported (and handler exists) // add progress ID to the request - need to be added before files if (rcmail.env.files_progress_name) { if (formdata) formdata.append(rcmail.env.files_progress_name, ts); else multipart += 'Content-Disposition: form-data; name="' + rcmail.env.files_progress_name + '"' + crlf + crlf + ts + crlf + dashdash + boundary + crlf; } // 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++; } }; // upload progress requests this.file_upload_progress = function(id, init) { if (init && id) this.uploads[id] = this.env.folder; setTimeout(function() { if (id && file_api.uploads[id]) file_api.request('upload_progress', {id: id}, 'file_upload_progress_response'); }, rcmail.env.files_progress_time * 1000); }; // upload progress response this.file_upload_progress_response = function(response) { if (!this.response(response)) return; var param = response.result; if (!param.id || !this.uploads[param.id]) return; if (param.total) { param.name = param.id; if (!param.done) param.text = kolab_files_progress_str(param); rcmail.display_progress(param); } if (!param.done && param.total) this.file_upload_progress(param.id); else delete this.uploads[param.id]; }; this.file_upload_progress_stop = function(id) { - if (id && this.uploads[id]) { + if (id) { delete this.uploads[id]; rcmail.display_progress({name: id}); } }; // open file in new window, using file API viewer this.file_open = function(file, viewer) { var href = '?' + $.param({_task: 'files', _action: 'open', file: file, viewer: viewer == 2 ? 1 : 0}); rcmail.open_window(href, false, true); }; // save file this.file_save = function(file, content) { rcmail.enable_command('files-save', false); // because we currently can edit only text files // and we do not expect them to be very big, we save // file in a very simple way, no upload progress, etc. this.req = this.set_busy(true, 'saving'); this.request('file_update', {file: file, content: content, info: 1}, 'file_save_response'); }; // file save response handler this.file_save_response = function(response) { rcmail.enable_command('files-save', true); if (!this.response(response)) return; // update file properties table var table = $('#fileinfobox table'), file = response.result; if (file) { $('td.filetype', table).text(file.type); $('td.filesize', table).text(this.file_size(file.size)); $('td.filemtime', table).text(file.mtime); } }; // handle auth errors on folder list this.folder_list_auth_errors = function(result) { if (result && result.auth_errors) { if (!this.auth_errors) this.auth_errors = {}; $.extend(this.auth_errors, result.auth_errors); } // ask for password to the first storage on the list $.each(this.auth_errors || [], function(i, v) { file_api.folder_list_auth_dialog(i, v); return false; }); }; // create dialog for user credentials of external storage this.folder_list_auth_dialog = function(label, driver) { var args = {width: 400, height: 300, buttons: {}}, dialog = $('#files-folder-auth-dialog'), content = this.folder_list_auth_form(driver); dialog.find('table.propform').remove(); $('.auth-options', dialog).before(content); args.buttons[this.t('kolab_files.save')] = function() { var data = {folder: label, list: 1}; $('input', dialog).each(function() { data[this.name] = this.type == 'checkbox' && !this.checked ? '' : this.value; }); file_api.open_dialog = this; file_api.req = file_api.set_busy(true, 'kolab_files.authenticating'); file_api.request('folder_auth', data, 'folder_auth_response'); }; args.buttons[this.t('kolab_files.cancel')] = function() { delete file_api.auth_errors[label]; kolab_dialog_close(this); // go to the next one file_api.folder_list_auth_errors(); }; args.title = this.t('kolab_files.folderauthtitle').replace('$title', label); // show dialog window kolab_dialog_show(dialog, args, function() { // focus first empty input $('input', dialog).each(function() { if (!this.value) { this.focus(); return false; } }); }); }; // folder_auth handler this.folder_auth_response = function(response) { if (!this.response(response)) return; var cnt = 0, folders, folder = response.result.folder, parent = $('#' + this.env.folders[folder].id); // try parent window if the folder element does not exist if (!parent.length && window.parent && window.parent.rcmail) { parent = $('#' + this.env.folders[folder].id, window.parent.document.body); } delete this.auth_errors[folder]; kolab_dialog_close(this.open_dialog); // go to the next one this.folder_list_auth_errors(); // count folders on the list $.each(this.env.folders, function() { cnt++; }); // parse result folders = this.folder_list_parse(response.result.list, cnt); delete folders[folder]; // remove root added in folder_list_parse() // add folders from the external source to the list $.each(folders, function(i, f) { var row = file_api.folder_list_row(i, f); parent.after(row); parent = row; }); // add tree icons this.folder_list_tree(folders); $.extend(this.env.folders, folders); }; // returns content of the external storage authentication form this.folder_list_auth_form = function(driver) { var rows = []; $.each(driver.form, function(fi, fv) { var id = 'authinput' + fi, attrs = {type: fi.match(/pass/) ? 'password' : 'text', size: 25, name: fi, id: id}, input = $('<input>').attr(attrs); if (driver.form_values && driver.form_values[fi]) input.attr({value: driver.form_values[fi]}); rows.push($('<tr>') .append($('<td class="title">').append($('<label>').attr('for', id).text(fv))) .append($('<td>').append(input)) ); }); return $('<table class="propform">').append(rows); }; };