文件操作 - kolab_files.js
返回文件管理
返回主菜单
删除本文件
文件: /root/Desktop/tmp/roundcubemail-plugins-kolab/plugins/kolab_files/kolab_files.js
编辑文件内容
/** * 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-2015, 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') { kolab_files_from_cloud_widget($('#compose-attachments > div')); // 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($('.header-content > .header-links').length ? $('.header-links > a:last') : 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); } if (!rcmail.env.action || rcmail.env.action == 'show' || rcmail.env.action == 'preview') { // add "attach from cloud" button for event/task dialog in mail rcmail.addEventListener('plugin.mail2event_dialog', function() { if (!$('#calendar-attachment-form a.fromcloud').length) kolab_files_from_cloud_widget($('#calendar-attachment-form > div.buttons')); }); } } else if (rcmail.task == 'calendar') { // add "attach from cloud" button for event dialog if (!rcmail.env.action) kolab_files_from_cloud_widget($('#calendar-attachment-form > div.buttons, #edit-attachments-form')); } else if (rcmail.task == 'tasks') { // add "attach from cloud" button for task dialog if (!rcmail.env.action) kolab_files_from_cloud_widget($('#taskedit-attachment-form > div.buttons, #taskedit-attachments-form')); } else if (rcmail.task == 'files') { if (rcmail.gui_objects.fileslist) { rcmail.fileslist = new rcube_list_widget(rcmail.gui_objects.fileslist, { multiselect: true, draggable: true, keyboard: true, column_movable: rcmail.env.files_col_movable, dblclick_time: rcmail.dblclick_time }); rcmail.fileslist.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('dragstart', function(e) { kolab_files_drag_start(e); }) .addEventListener('dragmove', function(e) { kolab_files_drag_move(e); }) .addEventListener('dragend', function(e) { kolab_files_drag_end(e); }) .addEventListener('column_replace', function(e) { kolab_files_set_coltypes(e, 'files'); }); rcmail.enable_command('menu-open', 'menu-save', 'files-sort', 'files-search', 'files-search-reset', 'folder-create', true); rcmail.fileslist.init(); kolab_files_list_coltypes('files'); kolab_files_drag_drop_init($(rcmail.gui_objects.fileslist).parents('.droptarget')); } if (rcmail.gui_objects.sessionslist) { rcmail.sessionslist = new rcube_list_widget(rcmail.gui_objects.sessionslist, { keyboard: true, column_movable: rcmail.env.sessions_col_movable, dblclick_time: rcmail.dblclick_time }); rcmail.sessionslist.addEventListener('dblclick', function(o) { kolab_files_sessions_list_dblclick(o); }) .addEventListener('select', function(o) { kolab_files_sessions_list_select(o); }) .addEventListener('keypress', function(o) { kolab_files_sessions_list_keypress(o); }) .addEventListener('column_replace', function(e) { kolab_files_set_coltypes(e, 'sessions'); }); rcmail.sessionslist.init(); kolab_files_list_coltypes('sessions'); } // "one file only" commands rcmail.env.file_commands = ['files-get', 'files-rename']; // "one or more file" commands rcmail.env.file_commands_all = ['files-delete', 'files-move', 'files-copy']; if (rcmail.env.action == 'open' || rcmail.env.action == 'edit') { rcmail.enable_command('files-get', true); rcmail.enable_command('files-delete', rcmail.env.file_data.writable); } else { rcmail.enable_command('folder-mount', rcmail.env.external_sources); } } kolab_files_init(); }); /**********************************************************/ /********* Shared functionality **********/ /**********************************************************/ // Initializes API object function kolab_files_init() { if (window.file_api) return; var editor_config = {}; // 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.env.files_url.replace(/\/api\/?$/, '/resources'), caps: rcmail.env.files_caps, supported_mimetypes: rcmail.env.file_mimetypes }); file_api.translations = rcmail.labels; if (rcmail.task == 'files') { if (rcmail.env.action == 'edit' && rcmail.env.editor_type) { // Extract the domain here, it can't be done by Chwala // when using WOPI, which does not set iframe src attribute var domain, href = rcmail.env.file_data.viewer.href; if (href && /^(https?:\/\/[^/]+)/i.test(href)) domain = RegExp.$1; editor_config = { // UI elements iframe: $('#fileframe').get(0), domain: domain, export_menu: rcmail.gui_objects.exportmenu ? $('ul', rcmail.gui_objects.exportmenu).get(0) : null, title_input: $('#document-title').get(0), members_list: $('#members').get(0), photo_url: '?_task=addressbook&_action=photo&_error=1&_email=%email', photo_default_url: rcmail.env.photo_placeholder, // events ready: function(data) { document_editor_init(); }, sessionClosed: function(data) { return document_editor_close(); } }; if (rcmail.env.file_data.writable) editor_config.documentChanged = function(data) { rcmail.enable_command('document-save', true); }; } else if (rcmail.env.action == 'open') { // initialize folders list (for dialogs) // file_api.folder_list(); // get ongoing sessions file_api.request('folder_info', {folder: file_api.file_path(rcmail.env.file), sessions: 1}, 'folder_info_response'); } else if (rcmail.env.action == 'share') { kolab_files_share_form_init(); } else { file_api.env.init_folder = rcmail.env.folder; file_api.env.init_collection = rcmail.env.collection; file_api.folder_list(); file_api.browser_capabilities_check(); if (rcmail.env.contextmenu) { rcmail.env.folders_cm = rcmail.contextmenu.init({menu_name: 'foldercontextmenu', menu_source: '#folderoptions > ul', list_object: 'folder_list'}, { addmenuitem: function(p) { // don't add Mount option to the menu var str = $(p.el).children('a').first().attr('onclick'); if (str && str.match(/folder-mount/)) return {result: false, abort: true}; }, activate: function(p) { var folder = rcmail.env.context_menu_source_id; switch (p.command) { case 'files-folder-delete': case 'folder-rename': return !folder.match(/^folder-collection-(.*)$/); case 'folder-share': return !folder.match(/^folder-collection-(.*)$/) && file_api.is_shareable(folder); case 'folder-create': case 'folder-mount': return true; } }, beforecommand: function(e) { rcmail.env.file_api_context = [file_api.env.folder, file_api.env.collection]; file_api.env.folder = rcmail.env.context_menu_source_id; }, aftercommand: function(e) { file_api.env.folder = rcmail.env.file_api_context[0]; file_api.env.collection = rcmail.env.file_api_context[1]; } }); } } } if (rcmail.env.files_caps && !rcmail.env.framed && rcmail.env.files_caps.DOCEDIT) $.extend(editor_config, { // invitation notifications api: file_api, owner: rcmail.env.files_user, interval: rcmail.env.files_interval || 60, invitationMore: true, invitationChange: document_editor_invitation_handler }); $.extend(editor_config, { // notifications/alerts gettext: function(label) { return rcmail.get_label(label, 'kolab_files'); }, set_busy: function(state, message) { return rcmail.set_busy(state, message ? 'kolab_files.' + message : ''); }, hide_message: function(id) { return rcmail.hide_message(id); }, display_message: function(label, type, is_txt, timeout) { if (!is_txt) label = 'kolab_files.' + label; return rcmail.display_message(label, type, timeout * 1000); } }); if (window.document_editor_api) document_editor = new document_editor_api(editor_config); else document_editor = new manticore_api(editor_config); rcmail.addEventListener('responseafterreset', function(o) { // update caps/mountpoints on reset file_api.set_env({caps: rcmail.env.files_caps}); }); }; // 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 rcmail.is_framed() && parent.rcmail.env.files_token ? parent.rcmail.env.files_token : rcmail.env.files_token; }; function kolab_files_from_cloud_widget(elem) { $('<a class="button btn btn-secondary fromcloud">') .attr('tabindex', $('button,input', elem).first().attr('tabindex') || 0) .text(rcmail.gettext('kolab_files.fromcloud')) .click(function() { kolab_files_selector_dialog(); }) .appendTo(elem); if (rcmail.gui_objects.fileslist) { rcmail.fileslist = new rcube_list_widget(rcmail.gui_objects.fileslist, { multiselect: true, keyboard: true, column_movable: false, dblclick_time: rcmail.dblclick_time }); rcmail.fileslist.addEventListener('select', function(o) { kolab_files_list_select(o); }); rcmail.enable_command('files-sort', 'files-search', 'files-search-reset', true); rcmail.fileslist.init(); kolab_files_list_coltypes(); } } // 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 = $.trim(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 () { if (!file_api.env.folder) return; 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() { rcmail.env.folder_list_selector = '#files-dialog #files-folder-list'; rcmail.env.folder_search_selector = '#files-dialog #foldersearch'; file_api.folder_list({writable: 1}); rcmail.env.folders_loaded = true; }; } // show dialog window kolab_dialog_show(dialog, { title: rcmail.gettext('kolab_files.' + label), buttons: buttons, button_classes: ['mainaction save', 'cancel'], classes: {'ui-dialog': 'selection-dialog files-dialog'}, minWidth: 250, minHeight: 300, height: 400, width: 300 }, fn); // add link for "more options" drop-down if (!dialog.find('foldercreatelink').length) $('<a>') .attr({href: '#', 'class': 'btn btn-link options add-folder'}) .text(rcmail.gettext('kolab_files.addfolder')) .click(function(e) { rcmail.command('folder-create', '', this, e); }) .prependTo(dialog.parent().parent().find('.ui-dialog-buttonset')); // "enable" folder creation when dialog is displayed in parent window if (rcmail.is_framed()) { 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 save', 'cancel'], classes: {'ui-dialog': 'selection-dialog files-dialog'}, minWidth: 500, minHeight: 300, width: 700, height: 500 }, function() { rcmail.fileslist.resize(); }); if (!rcmail.env.files_loaded) { rcmail.env.folder_list_selector = '#files-compose-dialog #files-folder-list'; rcmail.env.folder_search_selector = '#files-compose-dialog #foldersearch'; file_api.folder_list(); rcmail.env.files_loaded = true; } else { rcmail.fileslist.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 save', 'cancel'], height: 200 }); // Fix submitting form with Enter $('form', dialog).submit(kolab_dialog_submit_handler); // build parent selector file_api.folder_select_element(select, {empty: !rcmail.env.files_caps.NOROOT, writable: true}); }; // folder edit dialog function kolab_files_folder_edit_dialog() { var dialog = $('#files-folder-edit-dialog'), buttons = {}, separator = file_api.env.directory_separator, current_folder = file_api.env.folder, arr = current_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(current_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 save', 'cancel'], height: 200 }); // Fix submitting form with Enter $('form', dialog).submit(kolab_dialog_submit_handler); // build parent selector file_api.folder_select_element(select, {selected: path, empty: !rcmail.env.files_caps.NOROOT}); }; // folder sharing dialog function kolab_files_folder_share_dialog() { var dialog = $('<iframe>').attr('src', rcmail.url('share', {_folder: file_api.env.folder, _framed: 1})); rcmail.simple_dialog(dialog, rcmail.gettext('kolab_files.foldershare'), null, { cancel_button: 'close', width: 600, height: 500 }); }; // 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); }; // initialize drivers list if (!rcmail.drivers_list_initialized) { rcmail.drivers_list_initialized = true; $('td.source', dialog).each(function() { var td = $(this), id = td.attr('id').replace('source-', ''), meta = rcmail.env.external_sources[id]; $.each(meta.form_values || [], function(i, v) { td.find('#source-' + id + '-' + i).val(v); }); td.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 save', 'cancel']; // show dialog window kolab_dialog_show(dialog, args, function() { $('td.source:first', dialog).click(); input.focus(); }); }; // file edit dialog function kolab_files_file_edit_dialog(file, sessions, readonly) { var content = [], items = [], height = 300, dialog = $('#files-file-edit-dialog'), buttons = {}, name = file_api.file_name(file), title = rcmail.gettext('kolab_files.editfiledialog'), mainaction = rcmail.gettext('kolab_files.select'), item_fn = function(id, txt, classes) { return $('<label>').attr('class', 'session' + (classes ? ' ' + classes : '')) .append($('<input>').attr({name: 'opt', value: id, type: 'radio'})).append($('<span>').text(txt)); }, select_fn = function(dlg) { var session, input = $('input:checked', dialog), id = input.val(); if (dlg) kolab_dialog_close(dlg); if (id && input.parent().is('.session.request')) { document_editor.invitation_request({session_id: id}); return; } if (readonly && (id == 0 || !input.length)) return kolab_files_file_create_dialog(file); rcmail.files_edit(id ? id : true); }; // Create sessions selection if (sessions && sessions.length) { items.push($('<div>').text(rcmail.gettext('kolab_files.editfilesessions'))); // first display owned sessions, then invited, other at the end $.each(sessions, function() { if (this.is_owner) { var txt = rcmail.gettext('kolab_files.ownedsession'); items.push(item_fn(this.id, txt, 'owner')); } }); if (items.length == 1) items.push(item_fn(0, rcmail.gettext('kolab_files.newsession' + (readonly ? 'ro' : '')))); $.each(sessions, function() { if (this.is_invited) { var txt = rcmail.gettext('kolab_files.invitedsession') .replace('$user', this.owner_name ? this.owner_name : this.owner); items.push(item_fn(this.id, txt, 'invited')); } }); $.each(sessions, function() { if (!this.is_owner && !this.is_invited) { var txt = rcmail.gettext('kolab_files.joinsession') .replace('$user', this.owner_name ? this.owner_name : this.owner); items.push(item_fn(this.id, txt, 'request')); } }); // check the first option $('input', items[1]).attr('checked', true); $('div', dialog).html(items); // if there's only one session and it's owned, skip the dialog if (!readonly && items.length == 2 && $('input:checked', dialog).parent().is('.owner')) return select_fn(); } // no ongoing session, folder is readonly warning else { title = rcmail.gettext('kolab_files.editfilerotitle'); height = 150; $('div', dialog).text(rcmail.gettext('kolab_files.editfilero')); mainaction = rcmail.gettext('kolab_files.create'); } buttons[mainaction] = function() { select_fn(this); }; buttons[rcmail.gettext('kolab_files.cancel')] = function () { kolab_dialog_close(this); }; // show dialog window kolab_dialog_show(dialog, { title: title, buttons: buttons, button_classes: ['mainaction save', 'cancel'], minHeight: height - 100, height: height }); }; // file rename dialog function kolab_files_file_rename_dialog(file) { var dialog = $('#files-file-rename-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; 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.renamefile'), buttons: buttons, button_classes: ['mainaction save', 'cancel'], minHeight: 100, height: 100 }); }; // file creation (or cloning) dialog function kolab_files_file_create_dialog(file) { var buttons = {}, action = file ? 'copy' : 'create', button_classes = ['mainaction save edit'], dialog = $('#files-file-create-dialog'), type_select = $('select[name="type"]', dialog), select = $('select[name="parent"]', dialog).html(''), input = $('input[name="name"]', dialog).val(''), create_func = function(dialog, editaction) { var sel, folder = select.val(), type = type_select.val(), name = input.val(); if (!name || !folder || !file_api.is_writable(folder)) return; if (!/\.[a-z0-9]{1,5}$/.test(name)) { name += '.' + rcmail.env.file_extensions[type]; } name = folder + file_api.env.directory_separator + name; // get type of cloned file if (file) { if (rcmail.env.file_data) type = rcmail.env.file_data.type; else { sel = rcmail.fileslist.get_selection(); type = $('#rcmrow' + sel[0]).data('type'); } } file_api.file_create(name, type, editaction, file); kolab_dialog_close(dialog); }; buttons[rcmail.gettext('kolab_files.' + action + 'andedit')] = function() { create_func(this, true); }; if (action == 'create') { button_classes.push('save'); buttons[rcmail.gettext('kolab_files.create')] = function() { create_func(this); }; type_select.parent('tr').show(); } else { input.val(file_api.file_name(file)); type_select.parent('tr').hide(); } button_classes.push('cancel'); 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.' + action + 'file'), buttons: buttons, button_classes: button_classes, minHeight: 150, height: 250 }); // build folder selector file_api.folder_select_element(select, {writable: true}); }; // file session dialog function kolab_files_session_dialog(session) { var buttons = {}, button_classes = [], dialog = $('#files-session-dialog'), filename = file_api.file_name(session.file), owner = session.owner_name || session.owner, title = rcmail.gettext('kolab_files.sessiondialog'), content = rcmail.gettext('kolab_files.sessiondialogcontent'), join_session = function(id) { var viewer = file_api.file_type_supported('application/vnd.oasis.opendocument.text', rcmail.env.files_caps); params = {action: 'edit', session: id}; file_api.file_open('', viewer, params); }; content = content.replace('$file', filename).replace('$owner', owner); $('div', dialog).text(content); if (session.is_owner) { buttons[rcmail.gettext('kolab_files.open')] = function() { kolab_dialog_close(this); join_session(session.id); }; buttons[rcmail.gettext('kolab_files.close')] = function() { kolab_dialog_close(this); file_api.document_delete(session.id); }; button_classes = ['mainaction edit', 'delete']; } else if (session.is_invited) { button_classes = ['mainaction edit']; // @TODO: check if not-accepted and provide "Decline invitation" button // @TODO: Add "Accept button", add comment field to the dialog buttons[rcmail.gettext('kolab_files.join')] = function() { kolab_dialog_close(this); join_session(session.id); }; } else { button_classes = ['mainaction session request']; buttons[rcmail.gettext('kolab_files.request')] = function() { kolab_dialog_close(this); // @TODO: Add comment field to the dialog document_editor.invitation_request({session_id: session.id}); }; } button_classes.push('cancel'); buttons[rcmail.gettext('kolab_files.cancel')] = function() { kolab_dialog_close(this); }; // show dialog window kolab_dialog_show(dialog, { title: title, buttons: buttons, button_classes: button_classes, minHeight: 100, height: 150 }); }; function kolab_dialog_show(content, params, onopen) { params = $.extend({ modal: true, resizable: true, 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); content.hide(); // for Larry's dialogs $(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(); rcmail.ksearch_blur(); }; // This is required for Larry's dialogs params.create = function() { content.show(); }; // display it as popup var dialog = rcmail.show_popup_dialog(content, params.title, params.buttons, params); 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-dialog-buttonpane button').first().click(); return false; }; // Hides dialog function kolab_dialog_close(dialog, destroy) { (rcmail.is_framed() ? window.parent : window).$(dialog).dialog(destroy ? 'destroy' : '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 files/sessions list global variables function kolab_files_list_coltypes(type) { if (!type) type = 'files'; var n, list = rcmail[type + 'list']; rcmail.env.subject_col = null; if ((n = $.inArray('name', rcmail.env[type + '_coltypes'])) >= 0) { rcmail.env.subject_col = n; list.subject_col = n; } list.init_header(); }; function kolab_files_set_list_options(cols, sort_col, sort_order, type) { var update = 0, i, idx, name, newcols = [], oldcols = rcmail.env[type + '_coltypes']; if (sort_col === undefined) sort_col = rcmail.env[type + '_sort_col']; if (!sort_order) sort_order = rcmail.env[type + '_sort_order']; if (rcmail.env[type + '_sort_col'] != sort_col || rcmail.env[type + '_sort_order'] != sort_order) { update = 1; // set table header class kolab_files_set_list_sorting(sort_col, sort_order, type); } 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(type + '-list', {sort: sort_col, reverse: sort_order == 'DESC'}); else if (update) { rcmail.http_post('files/prefs', { type: type, kolab_files_list_cols: oldcols, kolab_files_sort_col: sort_col, kolab_files_sort_order: sort_order }, rcmail.set_busy(true, 'loading')); } }; function kolab_files_set_list_sorting(sort_col, sort_order, type) { // set table header class var old_col = rcmail.env[type + '_sort_col'], old_sort = rcmail.env[type + '_sort_order']; $('#rcm' + old_col).removeClass('sortedASC sortedDESC'); $('#rcm' + sort_col).addClass('sorted' + sort_order); rcmail.env[type + '_sort_col'] = sort_col; rcmail.env[type + '_sort_order'] = sort_order; }; function kolab_files_set_coltypes(list, type) { var i, found, name, cols = list.list.tHead.rows[0].cells; rcmail.env[type + '_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[type + '_coltypes'].push(name); } // if ((found = $.inArray('name', rcmail.env.files_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[type + '_coltypes'], type: type}); }; function kolab_files_sessions_list_dblclick(list) { rcmail.command('sessions-open'); }; function kolab_files_sessions_list_select(list) { var selected = list.selection.length; rcmail.enable_command('sessions-open', selected == 1); }; function kolab_files_sessions_list_keypress(list) { if (list.modkey == CONTROL_KEY) return; if (list.key_pressed == list.ENTER_KEY) { // use setTimeout(), otherwise the opened dialog will be immediately closed setTimeout(function() { rcmail.command('sessions-open'); }, 50); } // else if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY) // rcmail.command('sessions-delete'); }; function kolab_files_list_dblclick(list) { rcmail.command('files-open'); }; function kolab_files_list_select(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; if (selected == 1) { // get file mimetype var elem = $('tr.selected', list.list), type = elem.data('type'), folder = file_api.file_path(elem.data('file')); rcmail.env.viewer = file_api.file_type_supported(type, rcmail.env.files_caps); if (!file_api.is_writable(folder)) rcmail.enable_command('files-delete', 'files-rename', false); } else rcmail.env.viewer = 0; rcmail.enable_command('files-edit', (rcmail.env.viewer & 4) == 4); rcmail.enable_command('files-open', rcmail.env.viewer); }; function kolab_files_list_keypress(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'); }; function kolab_files_drag_start(e) { rcmail.env.drag_target = null; if (rcmail.folder_list) rcmail.folder_list.drag_start(); }; function kolab_files_drag_end(e) { if (rcmail.folder_list) { rcmail.folder_list.drag_end(); if (rcmail.env.drag_target) { var modkey = rcube_event.get_modifier(e), menu = rcmail.gui_objects.file_dragmenu; rcmail.fileslist.draglayer.hide(); if (menu && modkey == SHIFT_KEY && rcmail.commands['files-copy']) { var pos = rcube_event.get_mouse_pos(e); rcmail.show_menu(menu.id, true, e); $(menu).css({top: (pos.y-10)+'px', left: (pos.x-10)+'px'}); return; } rcmail.command('files-move', rcmail.env.drag_target); rcmail.env.drag_target = null; } } }; function kolab_files_drag_move(e) { if (rcmail.folder_list) { var mouse = rcube_event.get_mouse_pos(e); rcmail.env.drag_target = rcmail.folder_list.intersects(mouse, true); } }; function kolab_files_drag_menu_action(command) { var menu = rcmail.gui_objects.file_dragmenu; if (menu) $(menu).hide(); rcmail.command(command, rcmail.env.drag_target); }; function kolab_files_selected() { var files = []; $.each(rcmail.fileslist.get_selection(), function(i, v) { var name, row = $('#rcmrow'+v); if (row.length == 1 && (name = row.data('file'))) files.push(name); }); return files; }; function kolab_files_frame_load(frame) { var win = frame.contentWindow, info = rcmail.env.file_data; try { rcmail.file_editor = win.file_editor; } catch (e) {}; rcmail.enable_command('files-edit', (rcmail.file_editor && rcmail.file_editor.editable) || rcmail.env.editor_type || (file_api.file_type_supported(rcmail.env.file_data.type, rcmail.env.files_caps) & 4)); rcmail.enable_command('files-print', (rcmail.file_editor && rcmail.file_editor.printable) || (info && /^image\//i.test(info.type))); // Enable image tools rcmail.enable_command('image-scale', 'image-rotate', info && !!/^image\//.test(info.type)); rcmail.gui_objects.messagepartframe = frame; // on edit page switch immediately to edit mode if (rcmail.file_editor && rcmail.file_editor.editable && rcmail.env.action == 'edit') rcmail.files_edit(); // 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) function kolab_files_drag_drop_init(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.is_writable()) 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 function kolab_files_drag_hover(e) { if (!file_api.is_writable()) 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 function kolab_files_file_size(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; }; function kolab_files_progress_str(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); }; function kolab_files_share_form_init() { $('fieldset > table', rcmail.gui_objects.shareform).each(function() { var cnt = 0, mode = $(this).data('mode'), single = $(this).data('single'); $('tbody > tr', this).each(function(i, row) { if (!i) { $('button.submit', row).on('click', function() { file_api.sharing_submit(rcmail.env.folder, row, mode); }); $('input[data-autocomplete]').each(function() { var input = $(this), req_name = 'filesac-' + mode; kolab_files_autocomplete(input, req_name, function(e) { $(row).find('input[type=hidden]').each(function() { $(this).val(e.data[this.name] || ''); }); }); }); } else { cnt++; $('button.delete', row).on('click', function() { file_api.sharing_delete(rcmail.env.folder, row, mode); }); $('select,input[type=text]', row).on('change', function() { file_api.sharing_update(rcmail.env.folder, row, mode); }); } }); if (single && cnt) { $('tbody > tr:first', this).find('button.submit, input, select').prop('disabled', true); } }); }; function kolab_files_autocomplete(input, action, insert_callback) { rcmail.init_address_input_events(input, {action: action}); // "Redirect" autocomplete requests to Chwala API if (rcmail.env.files_api_version > 3) { rcmail.addEventListener('request' + action, function(post) { var params = {search: post._search, mode: input.data('autocomplete') || 'user', folder: rcmail.env.folder}, callback = function(response) { var result = response.result || []; $.each(result, function() { // add fake email to skip Roundcube's group expanding code if (this.type == 'group' && !this.email) this.email = 1; }); rcmail.ksearch_query_results(result, post._search, post._reqid); }, error_callback = function(o, status, err, data) { file_api.http_error(o, status, err, data); rcmail.ksearch_query_results([], post._search, post._reqid); }; return file_api.get('autocomplete', params, callback, error_callback); }); } // Update hidden fields on selection rcmail.addEventListener('autocomplete_insert', function(e) { if (e.field == input[0]) { input.val(e.insert.replace(/[, ]+$/, '')); } if (insert_callback) insert_callback(e); }); }; /**********************************************************/ /********* document editor functionality **********/ /**********************************************************/ // Initialize document toolbar functionality function document_editor_init() { var info = rcmail.env.file_data; rcmail.enable_command('document-export', 'document-print', true); if (info && info.session && info.session.is_owner) rcmail.enable_command('document-close', 'document-editors', true); }; // executed on editing session termination function document_editor_close() { var dialog = $('<div>').addClass('popupdialog').attr('role', 'alertdialog') .html($('<span>').text(rcmail.gettext('kolab_files.sessionterminated'))); rcmail.alert_dialog(dialog, function() { window.close(); }, { title: rcmail.gettext('kolab_files.sessionterminatedtitle') }); return false; // skip Chwala's error message }; rcube_webmail.prototype.document_save = function() { document_editor.save(function(data) { rcmail.enable_command('document-save', false); }); }; rcube_webmail.prototype.document_export = function(type) { document_editor.export(type || 'odt'); }; rcube_webmail.prototype.document_print = function() { document_editor.print(); }; rcube_webmail.prototype.document_editors = function() { kolab_files_editors_dialog(); }; // close editing session rcube_webmail.prototype.document_close = function() { var delete_fn = function() { document_editor.terminate(function() { var win = window.opener || window.parent; if (win && win.rcmail && win.file_api) win.file_api.document_delete(rcmail.env.file_data.session.id); // For Elastic: hide the parent dialog if (rcmail.is_framed()) { parent.$('.ui-dialog:visible button.cancel').click(); } window.close(); }); }; // check document "unsaved changes" state and display a warning // skip the warning for WOPI, Collabora will save the document anyway on session close if (this.commands['document-save'] && (!this.env.file_data.viewer || !this.env.file_data.viewer.wopi)) this.confirm_dialog(this.gettext('kolab_files.unsavedchanges'), 'kolab_files.terminate', delete_fn, {button_class: 'delete'}); else delete_fn(); }; // document editors management dialog function kolab_files_editors_dialog(session) { var items = [], buttons = {}, info = rcmail.env.file_data, dialog = $('#document-editors-dialog'), comment = $('#invitation-comment'); if (!info || !info.session || !info.session.is_owner) return; // always add the session organizer items.push(kolab_files_attendee_record(info.session.owner, 'organizer')); $.each(info.session.invitations || [], function(i, u) { var record = kolab_files_attendee_record(u.user, u.status, u.user_name); items.push(record); info.session.invitations[i].record = record; }); $('table > tbody', dialog).html(items); buttons[rcmail.gettext('kolab_files.close')] = function() { kolab_dialog_close(this); }; // show dialog window kolab_dialog_show(dialog, { title: rcmail.gettext('kolab_files.manageeditors'), buttons: buttons, button_classes: ['cancel'] }); if (!rcmail.env.editors_dialog) { rcmail.env.editors_dialog = dialog; kolab_files_autocomplete($('#invitation-editor-name'), 'files/autocomplete', function(e) { var success = false; if (e.field.name == 'participant') { // e.data && e.data.type == 'group' ? 'GROUP' : 'INDIVIDUAL' success = kolab_files_add_attendees(e.insert, comment.val()); } if (e.field && success) { e.field.value = ''; } }); $('#invitation-editor-add').click(function() { var input = $('#invitation-editor-name'); rcmail.ksearch_blur(); if (kolab_files_add_attendees(input.val(), comment.val())) { input.val(''); } }); } }; // add the given list of participants function kolab_files_add_attendees(names, comment) { var i, item, success, email, name, attendees = {}, counter = 0; names = file_api.explode_quoted_string(names.replace(/,\s*$/, ''), ','); // parse name/email pairs for (i = 0; i < names.length; i++) { email = name = ''; item = $.trim(names[i]); if (!item.length) { continue; } // address in brackets without name (do nothing) else if (item.match(/^<[^@]+@[^>]+>$/)) { email = item.replace(/[<>]/g, ''); } // address without brackets and without name (add brackets) else if (rcube_check_email(item)) { email = item; } // address with name else if (item.match(/([^\s<@]+@[^>]+)>*$/)) { email = RegExp.$1; name = item.replace(email, '').replace(/^["\s<>]+/, '').replace(/["\s<>]+$/, ''); } if (email) { attendees[email] = {user: email, name: name}; counter++; } else { rcmail.alert_dialog(rcmail.gettext('noemailwarning')); } } success = counter > 0; // remove already existing entries if (counter) { if (attendees[rcmail.env.file_data.session.owner]) { delete attendees[this.user]; counter--; } $.each(rcmail.env.file_data.session.invitations || [], function() { if (this.user in attendees) { delete attendees[this.user]; counter--; } }); } if (counter) file_api.document_invite(rcmail.env.file_data.session.id, attendees, comment); return success; }; function kolab_files_attendee_record(user, status, username) { var options = [], select, type = status ? status.replace(/-.*$/, '') : '', name = $('<td class="name">').text(user), buttons = $('<td class="options">'), state = $('<td class="status">').text(rcmail.gettext('kolab_files.status' + type)); // @todo: accept/decline invitation request if (type == 'requested' || status == 'accepted-owner' || status == 'declined-owner') { select = $('<select>').change(function() { var val = $(this).val(), map = {accepted: 'invitation_accept', declined: 'invitation_decline'}; if (map[val]) document_editor[map[val]]({user: user, session_id: rcmail.env.file_data.session.id}); }); if (type == 'requested') options.push($('<option>').text(rcmail.gettext('kolab_files.statusrequested')).attr('value', 'requested')); options.push($('<option>').text(rcmail.gettext('kolab_files.statusaccepted')).attr('value', 'accepted')); options.push($('<option>').text(rcmail.gettext('kolab_files.statusdeclined')).attr('value', 'declined')); state.html(select.html(options).val(type)); } // delete button if (status != 'organizer') { $('<a>').attr({'class': 'delete', href: '#', title: rcmail.gettext('kolab_files.removeparticipant')}) .click(function() { file_api.document_cancel(rcmail.env.file_data.session.id, [user]); }) .appendTo(buttons); } if (username && status != 'organizer') name.html($('<a>').attr({href: 'mailto:' + user, 'class': 'mailtolink'}).text(username)) .click(function(e) { rcmail.command('compose', user, e.target, e); return false; }); return $('<tr>').attr('class', 'invitation' + (type ? ' ' + type : '')) .append(name).append(state).append(buttons); }; function document_editor_invitation_handler(invitation) { // make the "More" link clickable $('#' + invitation.id).parent('div').click(function() { kolab_files_invitation_dialog(invitation); }); }; function kolab_files_invitation_dialog(invitation) { var text, records = [], content = [], buttons = {}, button_classes = [], dialog = $('#document-invitation-dialog'), data_map = {status: 'status', 'changed': 'when', filename: 'file', comment: 'comment'}, record_fn = function(type, label, value) { records.push($('<tr>').attr('class', type) .append($('<td class="label">').text(rcmail.gettext('kolab_files.'+ label))) .append($('<td>').text(value)) ); }; join_session = function() { var viewer = file_api.file_type_supported('application/vnd.oasis.opendocument.text', rcmail.env.files_caps); params = {action: 'edit', session: invitation.session_id}; file_api.file_open('', viewer, params); }; if (!dialog.length) dialog = $('<div>').attr({id: 'document-invitation-dialog', role: 'dialog', 'aria-hidden': 'true'}) .append($('<div>')) .appendTo(document.body); if (!invitation.is_session_owner) { if (invitation.status == 'invited') { text = document_editor.invitation_msg(invitation); button_classes = ['session join', 'session accept', 'session decline delete']; buttons[rcmail.gettext('kolab_files.join')] = function() { join_session(); kolab_dialog_close(this); }; buttons[rcmail.gettext('kolab_files.accept')] = function() { document_editor.invitation_accept(invitation); kolab_dialog_close(this); }; buttons[rcmail.gettext('kolab_files.decline')] = function() { document_editor.invitation_decline(invitation); kolab_dialog_close(this); }; } else if (invitation.status == 'declined-owner') { // @todo: add option to request for an invitation again? text = document_editor.invitation_msg(invitation); } else if (invitation.status == 'accepted-owner') { text = document_editor.invitation_msg(invitation); button_classes = ['mainaction session join']; buttons[rcmail.gettext('kolab_files.join')] = function() { join_session(); kolab_dialog_close(this); }; } } else { if (invitation.status == 'accepted') { text = document_editor.invitation_msg(invitation); } else if (invitation.status == 'declined') { // @todo: add option to invite the user again? text = document_editor.invitation_msg(invitation); } else if (invitation.status == 'requested') { text = document_editor.invitation_msg(invitation); button_classes = ['session accept', 'session decline delete']; buttons[rcmail.gettext('kolab_files.accept')] = function() { document_editor.invitation_accept(invitation); kolab_dialog_close(this); }; buttons[rcmail.gettext('kolab_files.decline')] = function() { document_editor.invitation_decline(invitation); kolab_dialog_close(this); }; } } if (text) { $.each(data_map, function(i, label) { var value = invitation[i]; if (value) { if (i == 'status') value = rcmail.gettext('kolab_files.status' + value.replace(/-.*$/, '')); record_fn(i, label, value); } }); content.push($('<div>').text(text)); content.push($('<table class="propform">').html(records)); } button_classes.push('cancel'); buttons[rcmail.gettext('kolab_files.close')] = function() { kolab_dialog_close(this); }; $('div', dialog).html(content); // show dialog window kolab_dialog_show(dialog, { title: rcmail.gettext('kolab_files.invitationtitle').replace('$file', invitation.filename), buttons: buttons, button_classes: button_classes }); }; /***********************************************************/ /********** Commands **********/ /***********************************************************/ rcube_webmail.prototype.files_sort = function(props) { this.files_sort_handler(props, 'files'); }; rcube_webmail.prototype.sessions_sort = function(props) { this.files_sort_handler(props, 'sessions'); }; rcube_webmail.prototype.files_sort_handler = function(col, type) { var params = {}, c = type == 'files' ? '' : ('_' + type), sort_order = this.env[type + '_sort_order'], sort_col = !this.env['kolab_files' + c + '_disabled_sort_col'] ? col : this.env[type + '_sort_col']; if (!this.env['kolab_files' + c + '_disabled_sort_order']) sort_order = this.env[type + '_sort_col'] == sort_col && sort_order == 'ASC' ? 'DESC' : 'ASC'; // set table header and update env kolab_files_set_list_sorting(sort_col, sort_order, type); this.http_post('files/prefs', {kolab_files_sort_col: sort_col, kolab_files_sort_order: sort_order, type: type}); params.sort = sort_col; params.reverse = sort_order == 'DESC'; this.command(type + '-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(prop, elem, event) { this.hide_menu('folderoptions', event); this.confirm_dialog(this.get_label('kolab_files.folderdeleteconfirm'), 'delete', function() { file_api.folder_delete(file_api.env.folder); }); }; rcube_webmail.prototype.files_delete = function() { this.confirm_dialog(this.get_label('kolab_files.filedeleteconfirm'), 'delete', function() { var files = rcmail.env.file ? [rcmail.env.file] : kolab_files_selected(); file_api.file_delete(files); }); }; rcube_webmail.prototype.files_move = function(folder, obj, event, files) { if (!files) files = kolab_files_selected(); if (!folder) { var ref = this; return this.files_folder_selector(event, function(folder) { ref.files_move(folder, null, event, files); }); } file_api.file_move(files, folder); }; rcube_webmail.prototype.files_copy = function(folder, obj, event, files) { if (!files) files = kolab_files_selected(); if (!folder) { var ref = this; return this.files_folder_selector(event, function(folder) { ref.files_copy(folder, null, event, files); }); } file_api.file_copy(files, folder); }; // create folder selector popup rcube_webmail.prototype.files_folder_selector = function(event, callback) { if (this.folder_selector_reset) this.destroy_entity_selector('folder-selector'); // The list is incomplete, reset needed before next use this.folder_selector_reset = file_api.list_updates > 0; this.entity_selector('folder-selector', callback, file_api.env.folders, function(folder, a, folder_fullname) { var n = folder.depth || 0, row = $('<li>'); if (folder.virtual || folder.readonly) a.addClass('virtual').attr({'aria-disabled': 'true', tabindex: '-1'}); else a.addClass('active').data('id', folder_fullname); a.css('padding-left', n ? (n * 16) + 'px' : 0); // add folder name element a.append($('<span>').text(folder.name)); return row.append(a); }, event); }; 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.fileslist; $('thead', list.fixed_header ? list.fixed_header : list.list).html(head); kolab_files_list_coltypes(); file_api.file_list(); }; rcube_webmail.prototype.sessions_list = function(param) { // just rcmail wrapper, to handle command busy states file_api.session_list(param); }; rcube_webmail.prototype.sessions_list_update = function(head) { var list = this.sessionslist; $('thead', list.fixed_header ? list.fixed_header : list.list).html(head); kolab_files_list_coltypes('sessions'); file_api.sessions_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(session) { var files, readonly, sessions, file = this.env.file, params = {action: 'edit'}; if (!file && !this.env.action) { files = kolab_files_selected(); if (files.length == 1) file = files[0]; readonly = !file_api.is_writable(file_api.file_path(file)); } else { readonly = !this.env.file_data.writable; } // check if the folder is read-only or there are ongoing sessions // in such cases display dialog for the user to decide what to do if (!session) { sessions = file_api.file_sessions(file); if (sessions.length || readonly) { kolab_files_file_edit_dialog(file, sessions, readonly); return; } } else if (session !== true) params.session = session; if (this.file_editor && this.file_editor.editable && !session) { this.file_editor.enable(); this.enable_command('files-save', true); } else if (this.env.file) { var viewer = file_api.file_type_supported(this.env.file_data.type, this.env.files_caps); params.local = true; file_api.file_open(file, viewer, params); } else if (file) { file_api.file_open(file, this.env.viewer, params); } }; // save changes to the file 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.files_create = function() { kolab_files_file_create_dialog(); }; rcube_webmail.prototype.files_rename = function() { var files = kolab_files_selected(); kolab_files_file_rename_dialog(files[0]); }; rcube_webmail.prototype.folder_create = function() { kolab_files_folder_create_dialog(); }; rcube_webmail.prototype.folder_rename = function(prop, elem, event) { this.hide_menu('folderoptions', event); kolab_files_folder_edit_dialog(); }; rcube_webmail.prototype.folder_share = function(prop, elem, event) { this.hide_menu('folderoptions', event); kolab_files_folder_share_dialog(); }; rcube_webmail.prototype.folder_mount = function(prop, elem, event) { this.hide_menu('folderoptions', event); kolab_files_folder_mount_dialog(); }; // open a session dialog rcube_webmail.prototype.sessions_open = function() { var id = this.sessionslist.get_selection(), session = id ? file_api.env.sessions_list[id] : null; if (session) kolab_files_session_dialog(session); }; /**********************************************************/ /********* Files API handler **********/ /**********************************************************/ function kolab_files_ui() { this.requests = {}; this.uploads = []; this.list_updates = 0; /* // 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, data) { rcmail.http_error(request, status, err, data ? data.req_id : null); }; // check if specified/current folder/view is writable this.is_writable = function(folder) { if (!folder) folder = this.env.folder; if (!folder) return false; var all_folders = $.extend({}, this.env.folders, this.search_results); if (!all_folders[folder] || all_folders[folder].readonly || all_folders[folder].virtual) return false; return true; }; // Check if specified folder (hierarchy) supports sharing this.is_shareable = function(folder) { if (!folder) folder = this.env.folder; if (!folder) return false; var root = folder.split(this.env.directory_separator)[0], caps = this.env.caps; if (this.env.caps.MOUNTPOINTS[root]) caps = root != folder ? this.env.caps.MOUNTPOINTS[root] : {}; return !!caps.ACL; }; // folders list request this.folder_list = function(params, update) { if (!params) params = {} params.permissions = 1; if (params.level === undefined) params.level = -1; if (update) { this.list_updates++; params.req = rcmail.display_message('', 'loading'); } else { params.req = this.set_busy(true, 'loading'); this.list_params = params; } this.request('folder_list', params, update ? 'folder_list_update_response' : 'folder_list_response'); }; // folder list response handler this.folder_list_response = function(response, params) { rcmail.hide_message(params.req); if (!this.response(response)) return; var folder, first, body, rows = [], list_selector = rcmail.env.folder_list_selector || '#files-folder-list', search_selector = rcmail.env.folder_search_selector || '#foldersearch', elem = $(list_selector), searchbox = $(search_selector), list = $('<ul class="treelist listing folderlist"></ul>'), collections = ['audio', 'video', 'image', 'document']; // try parent window if the list element does not exist // i.e. called from a dialog in parent window if (!elem.length && rcmail.is_framed() && (rcmail.env.task != 'files' || (rcmail.env.action != 'open' && rcmail.env.action != 'edit'))) { body = window.parent.document.body; elem = $(list_selector, body); searchbox = $(search_selector, body); } this.list_element = list; if (elem.data('no-collections') == true) collections = []; this.env.folders = this.folder_list_parse(response.result && response.result.list ? response.result.list : response.result); rcmail.enable_command('files-create', response.result && response.result.list && response.result.list.length > 0); if (!elem.length) return; elem.html(''); $.each(this.env.folders, function(i, f) { var row; if (row = file_api.folder_list_row(i, f)) { if (!first) first = i; rows.push(row); } }); // add virtual collections $.each(collections, function(i, n) { var row = $('<li class="mailbox collection ' + n + '"></li>'); row.attr('id', 'rcmli' + rcmail.html_identifier_encode('folder-collection-' + n)) .append($('<a class="name"></a>').text(rcmail.gettext('kolab_files.collection_' + n))) rows.push(row); }); // add Sessions entry if (rcmail.task == 'files' && !rcmail.env.action && this.env.caps && this.env.caps.DOCEDIT) { rows.push($('<li class="mailbox collection sessions"></li>') .attr('id', 'rcmli' + rcmail.html_identifier_encode('folder-collection-sessions')) .append($('<a class="name"></a>').text(rcmail.gettext('kolab_files.sessions'))) ); } list.append(rows).appendTo(elem) .on('click', 'a.subscription', function(e) { return file_api.folder_list_subscription_button_click(this); }) .on('mouseover', 'a.name', function() { rcube_webmail.long_subject_title_ex(this); }); if (rcmail.task == 'files' && rcmail.env.contextmenu) list.on('contextmenu', function(e) { var elem = $(e.target).closest('li'); id = rcmail.html_identifier_decode(elem.attr('id').replace(/^rcmli/, '')); rcmail.contextmenu.show_one(e, elem[0], id, rcmail.env.folders_cm); }); if (rcmail.folder_list) { rcmail.folder_list.reset(); this.search_results_widget = null; } // init treelist widget rcmail.folder_list = new rcube_treelist_widget(list, { selectable: true, id_prefix: 'rcmli', parent_focus: true, searchbox: searchbox, id_encode: rcmail.html_identifier_encode, id_decode: rcmail.html_identifier_decode, check_droptarget: function(node) { return !node.virtual && node.id != file_api.env.folder && $.inArray('readonly', node.classes) == -1 && $.inArray('collection', node.classes) == -1; } }); rcmail.folder_list .addEventListener('collapse', function(node) { file_api.folder_collapsed(node); }) .addEventListener('expand', function(node) { file_api.folder_collapsed(node); }) .addEventListener('beforeselect', function(node) { return !rcmail.busy; }) .addEventListener('search', function(search) { file_api.folder_search(search); }) .addEventListener('select', function(node) { if (file_api.search_results_widget) file_api.search_results_widget.select(); file_api.folder_select(node.id); }); // select first/current folder if (response.result.auth_errors && response.result.auth_errors.length) this.env.folder = this.env.collection = null; else if (this.env.folder) rcmail.folder_list.select(this.env.folder); else if (this.env.collection) rcmail.folder_list.select('folder-collection-' + this.env.collection); else if (folder = this.env.init_folder) { if (this.env.folders[folder]) { this.env.init_folder = null; rcmail.folder_list.select(folder); } } else if (folder = this.env.init_collection) { this.env.init_collection = null; rcmail.folder_list.select('folder-collection-' + folder); } else if (first) rcmail.folder_list.select(first); // handle authentication errors on external sources this.folder_list_auth_errors(response.result); // Fetch 2 levels of folder hierarchy for all mount points that // do not support fast folders list if (rcmail.env.files_api_version > 4) { var ref = this; $.each(this.env.caps.MOUNTPOINTS || [], function(k, v) { if (!v.FAST_FOLDER_LIST) ref.folder_list({level: 2, folder: k}, true); }); } // Elastic: Set notree class on the folder list var callback = function() { list[list.find('.treetoggle').length > 0 ? 'removeClass' : 'addClass']('notree'); }; if (window.MutationObserver) (new MutationObserver(callback)).observe(list.get(0), {childList: true, subtree: true}); callback(); }; // folder list response handler this.folder_list_update_response = function(response, params) { rcmail.hide_message(params.req); this.list_updates--; if (!this.response(response)) return; // handle authentication errors on external sources this.folder_list_auth_errors(response.result); // Update the list this.folder_list_merge(params.folder, response.result.list, params.level); }; this.folder_list_update_wait = function(folder) { var ref = this; // do maximum 10 parallel requests if (this.list_updates > 10) return setTimeout(function() { ref.folder_list_update_wait(folder); }, 20); this.folder_list({folder: folder, level: 0}, true); }; this.folder_select = function(folder) { if (rcmail.busy || !folder) return; rcmail.triggerEvent('files-folder-select', {folder: folder}); var is_collection = folder.match(/^folder-collection-(.*)$/), collection = RegExp.$1 || null; if (rcmail.task == 'files' && !rcmail.env.action) rcmail.update_state(is_collection ? {collection: collection} : {folder: folder}); if (collection == 'sessions') { rcmail.enable_command('files-list', 'files-folder-delete', 'folder-rename', 'files-upload', 'files-open', 'files-edit', false); this.sessions_list(); return; } if (is_collection) folder = null; // search-reset can re-select the same folder, skip if (this.env.folder == folder && this.env.collection == collection) return; this.env.folder = folder; this.env.collection = collection; rcmail.enable_command('files-list', true); rcmail.enable_command('files-folder-delete', 'folder-rename', !is_collection); rcmail.enable_command('files-upload', !is_collection && this.is_writable()); rcmail.enable_command('folder-share', !is_collection && this.is_shareable()); rcmail.command('files-list', is_collection ? {collection: collection} : {folder: folder}); this.quota(); }; this.folder_unselect = function() { rcmail.folder_list.select(); this.env.folder = null; this.env.collection = null; rcmail.enable_command('files-folder-delete', 'files-upload', false); }; this.folder_collapsed = function(node) { var prefname = 'kolab_files_collapsed_folders', old = rcmail.env[prefname], entry = '&' + urlencode(node.id) + '&'; if (node.collapsed) { rcmail.env[prefname] = rcmail.env[prefname] + entry; // select the folder if one of its childs is currently selected // don't select if it's virtual (#1488346) if (!node.virtual && this.env.folder && this.env.folder.startsWith(node.id + '/')) { rcmail.folder_list.select(node.id); } } else { rcmail.env[prefname] = rcmail.env[prefname].replace(entry, ''); } if (old !== rcmail.env[prefname] && (!rcmail.fileslist || !rcmail.fileslist.drag_active)) rcmail.command('save-pref', {name: prefname, value: rcmail.env[prefname]}); }; this.folder_list_row = function(i, folder, parent) { var toggle, sublist, collapsed, parent, parent_name, classes = ['mailbox'], row = $('<li>'), id = 'rcmli' + rcmail.html_identifier_encode(i), content = $('<div>').append($('<a class="name">').text(folder.name)); if (folder.virtual) classes.push('virtual'); else { if (folder.subscribed !== undefined) content.append(this.folder_list_subscription_button(folder.subscribed)); if (folder.readonly) classes.push('readonly'); } folder.ref = row.attr({id: id, 'class': classes.join(' ')}).append(content); if (folder.depth) { // find parent folder parent_name = i.replace(/\/[^/]+$/, ''); if (!parent) parent = $(this.env.folders[parent_name].ref); toggle = $('div.treetoggle', parent); sublist = $('> ul', parent); if (!toggle.length) { collapsed = rcmail.env.kolab_files_collapsed_folders.indexOf('&' + urlencode(parent_name) + '&') > -1; toggle = $('<div>').attr('class', 'treetoggle' + (collapsed ? ' collapsed' : ' expanded')) .html(' ').appendTo(parent); sublist = $('<ul>').attr({role: 'group'}).appendTo(parent); if (collapsed) sublist.hide(); } sublist.append(row); } else { return row; } }; // create subscription button element this.folder_list_subscription_button = function(subscribed) { return $('<a>').attr({ title: rcmail.gettext('kolab_files.listpermanent'), 'class': 'subscription' + (subscribed ? ' subscribed' : ''), 'aria-checked': subscribed, role: 'checkbox' }); }; // subscription button handler this.folder_list_subscription_button_click = function(elem) { var folder = $(elem).parents('li:first').prop('id').replace(/^rcmli/, ''), selected = $(elem).hasClass('subscribed'); folder = folder.replace(/--xsR$/, ''); // this might be a search result folder = rcmail.html_identifier_decode(folder); file_api['folder_' + (selected ? 'unsubscribe' : 'subscribe')](folder); return false; }; // sets subscription button status this.folder_list_subscription_state = function(elem, status) { $(elem).find('a.subscription:first') .prop('aria-checked', status)[status ? 'addClass' : 'removeClass']('subscribed'); }; // Folder searching handler (for unsubscribed folders) this.folder_search = function(search) { // hide search results if (this.search_results_widget) { this.search_results_container.hide(); this.search_results_widget.reset(); } this.search_results = {}; // send search request to the server if (search.query && search.execute) { // cancel previous search request if (this.listsearch_request) { this.listsearch_request.abort(); this.listsearch_request = null; } var params = $.extend({search: search.query, unsubscribed: 1}, this.list_params); this.req = this.set_busy(true, rcmail.gettext('searching')); this.listsearch_request = this.request('folder_list', params, 'folder_search_response'); } else if (!search.query) { if (this.listsearch_request) { this.listsearch_request.abort(); this.listsearch_request = null; } // any subscription changed, make sure the newly added records // are listed before collections not after if (this.folder_subscribe) { var r, last, move = [], rows = $(rcmail.folder_list.container).children('li'); if (rows.length && !$(rows[rows.length-1]).hasClass('collection')) { // collect all folders to move while (rows.length--) { r = $(rows[rows.length]); if (r.hasClass('collection')) last = r; else if (last) break; else move.push(r); } if (last) $.each(move, function() { this.remove(); last.before(this); }); } } } }; // folder search response handler this.folder_search_response = function(response) { if (!this.response(response)) return; var folders = response.result && response.result.list ? response.result.list : response.result; if (!folders.length) return; folders = this.folder_list_parse(folders, 10000, false); if (!this.search_results_widget) { var list = rcmail.folder_list.container, title = rcmail.gettext('kolab_files.additionalfolders'), list_id = list.attr('id') || '0'; this.search_results_container = $('<div class="searchresults"></div>') .append($('<h2 class="boxtitle" id="st:' + list_id + '"></h2>').text(title)) .insertAfter(list); this.search_results_widget = new rcube_treelist_widget('<ul>', { id_prefix: 'rcmli', id_encode: rcmail.html_identifier_encode, id_decode: rcmail.html_identifier_decode, selectable: true }); this.search_results_widget .addEventListener('beforeselect', function(node) { return !rcmail.busy; }) .addEventListener('select', function(node) { rcmail.folder_list.select(); file_api.folder_select(node.id); }); this.search_results_widget.container // copy classes from main list .addClass(list.attr('class')).attr('aria-labelledby', 'st:' + list_id) .appendTo(this.search_results_container) .on('click', 'a.subscription', function(e) { return file_api.folder_list_subscription_button_click(this); }); } // add results to the list $.each(folders, function(i, folder) { var node, separator = file_api.env.directory_separator, path = i.split(separator), classes = ['mailbox'], html = [$('<a>').text(folder.name)]; if (!folder.virtual) { // add subscription button html.push(file_api.folder_list_subscription_button(false)); if (folder.readonly) classes.push('readonly'); } path.pop(); file_api.search_results_widget.insert({ id: i, classes: classes, text: folder.name, html: $('<div>').append(html), collapsed: false, virtual: folder.virtual }, path.length ? path.join(separator) : null); }); this.search_results = folders; this.search_results_container.show(); }; // folder subscribe request this.folder_subscribe = function(folder) { this.env.folder_subscribe = folder; this.req = this.set_busy(true, 'foldersubscribing'); this.request('folder_subscribe', {folder: folder}, 'folder_subscribe_response'); } // folder subscribe response handler this.folder_subscribe_response = function(response) { if (!this.response(response)) return; this.display_message('foldersubscribed', 'confirmation'); var item, node = rcmail.folder_list.get_item(this.env.folder_subscribe); if (this.search_results && this.search_results[this.env.folder_subscribe]) { item = this.search_results_widget.get_item(this.env.folder_subscribe); this.folder_list_subscription_state(item, true); if (item = $(item).attr('id')) this.folder_list_subscription_state($('#' + item.replace(/--xsR$/, '')), true); } // search result, move from search to main list widget if (!node && this.search_results && this.search_results[this.env.folder_subscribe]) { var i, html, dir, folder, separator = this.env.directory_separator, path = this.env.folder_subscribe.split(separator); // add all folders in a path to the main list if needed // including the subscribed folder for (i=0; i<path.length; i++) { dir = path.slice(0, i + 1).join(separator); node = rcmail.folder_list.get_node(dir); if (!node) { node = this.search_results_widget.get_node(dir); if (!node) { // sanity check return; } if (i == path.length - 1) { item = this.search_results_widget.get_item(dir); this.folder_list_subscription_state(item, true); } folder = this.search_results[dir]; html = [$('<a>').text(folder.name)]; if (!folder.virtual) html.push(this.folder_list_subscription_button(true)); node.html = $('<div>').append(html); delete node.children; rcmail.folder_list.insert(node, i > 0 ? path.slice(0, i).join(separator) : null); // we're in search result, so there will be two records, // add subscription button to the visible one, it was not cloned if (!folder.virtual) { node = rcmail.folder_list.get_item(dir); $(node).append(file_api.folder_list_subscription_button(true)); } this.env.folders[dir] = folder; } } // now remove them from the search widget while (path.length) { dir = path.join(separator); node = this.search_results_widget.get_item(dir); if ($('ul[role="group"] > li', node).length) break; this.search_results_widget.remove(dir); path.pop(); } node = null; } if (node) this.folder_list_subscription_state(node, true); this.env.folders[this.env.folder_subscribe].subscribed = true; }; // folder unsubscribe request this.folder_unsubscribe = function(folder) { this.env.folder_subscribe = folder; this.req = this.set_busy(true, 'folderunsubscribing'); this.request('folder_unsubscribe', {folder: folder}, 'folder_unsubscribe_response'); } // folder unsubscribe response handler this.folder_unsubscribe_response = function(response) { if (!this.response(response)) return; this.display_message('folderunsubscribed', 'confirmation'); var folder = this.env.folders[this.env.folder_subscribe], node = rcmail.folder_list.get_item(this.env.folder_subscribe); if (this.search_results && this.search_results[this.env.folder_subscribe]) { item = this.search_results_widget.get_item(this.env.folder_subscribe); if (item) { this.folder_list_subscription_state(item, false); item = $('#' + $(item).attr('id').replace(/--xsR$/, '')); } else item = $('#rcmli' + rcmail.html_identifier_encode(this.env.folder_subscribe), rcmail.folder_list.container); this.folder_list_subscription_state(item, false); } this.folder_list_subscription_state(node, false); folder.subscribed = false; }; // 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 // TODO: Don't reload the whole list this.folder_list(); }; // folder rename request this.folder_rename = function(folder, new_name) { if (folder == new_name) return; 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, params) { if (!this.response(response)) return; this.display_message('kolab_files.folderupdatenotice', 'confirmation'); // refresh folders and files list if (this.env.folder == params.folder) this.env.folder = params['new']; // Removed mount point, refresh capabilities stored in session if (this.env.caps.MOUNTPOINTS[params.folder]) { this.env.caps.MOUNTPOINTS[params['new']] = this.env.caps.MOUNTPOINTS[params.folder]; delete this.env.caps.MOUNTPOINTS[params.folder]; rcmail.http_post('files/reset', {}); } // TODO: Don't reload the whole list 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, params) { if (!this.response(response)) return; this.display_message('kolab_files.foldermountnotice', 'confirmation'); if (response.result.capabilities) { // we make sure the result is an object not array // when the list is empty it is an array, because of how works JSON encoding from PHP var add = {}; add[params.folder] = response.result.capabilities; this.env.caps.MOUNTPOINTS = $.extend({}, this.env.caps.MOUNTPOINTS, add); } // Refresh capabilities stored in session rcmail.http_post('files/reset', {}); // refresh folders list // TODO: load only folders from the created mount point 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, params) { if (!this.response(response)) return; this.display_message('kolab_files.folderdeletenotice', 'confirmation'); if (this.env.folder == params.folder) { this.env.folder = null; rcmail.enable_command('files-folder-delete', 'folder-rename', 'files-list', false); } // Removed mount point, refresh capabilities stored in session if (this.env.caps.MOUNTPOINTS[params.folder]) { delete this.env.caps.MOUNTPOINTS[params.folder]; rcmail.http_post('files/reset', {}); } // refresh folders list this.folder_list(); this.quota(); }; this.sharing_submit = function(folder, row, mode) { var post = this.sharing_data(row, {action: 'submit', folder: folder, mode: mode}); if (post === false) return; this.sharing_submit_post = post; this.sharing_submit_row = row; this.req = this.set_busy(true, 'kolab_files.updatingfolder' + mode); this.post('sharing', post, 'sharing_submit_response'); }; this.sharing_submit_response = function(response) { if (!this.response(response)) return; // reset inputs $(this.sharing_submit_row).find('input[type=text]').val(''); var hidden = [], post = $.extend({}, this.sharing_submit_post, response.result || {}), form_info = rcmail.env.form_info[post.mode], table = $(this.sharing_submit_row).closest('table'), row = $('<tr>'), btn = $('<button type="button" class="btn btn-secondary btn-danger delete">') .text(rcmail.gettext('delete')) .on('click', function() { file_api.sharing_delete(post.folder, $(this).closest('tr'), post.mode); }); if (form_info.list_column) { row.append($('<td>').append($('<span class="name">') .text(response.result.display || post[form_info.list_column]) .attr('title', response.result.title)) ); } else { $.each(form_info.form || [], function(i, v) { var content, opts = []; if (v.type == 'select') { content = $('<select>').attr('name', i) .on('change', function() { file_api.sharing_update(post.folder, $(this).closest('tr'), post.mode); }); $.each(v.options, function(i, v) { opts.push($('<option>').attr('value', i).text(v)); }); content.append(opts).val(post[i]); } else { content = $('<span class="name">').text(response.result.display || post[i]).attr('title', response.result.title); hidden.push($('<input>').attr({type: 'hidden', name: i, value: post[i] || ''})); } row.append($('<td>').append(content)); }); } $.each(form_info.extra_fields || [], function(i, v) { hidden.push($('<input>').attr({type: 'hidden', name: i, value: post[i] || ''})); }); row.append($('<td>').append(btn).append(hidden)); $(this.sharing_submit_row).parent().append(row); if (window.UI && UI.pretty_select) row.find('select').each(function() { UI.pretty_select(this); }); // for Elastic if (table.data('single')) { $('tbody > tr:first', table).find('button,input,select').prop('disabled', true); } $('tbody > tr:first', table).find('input[type=text],input[type=password]').val(''); }; this.sharing_update = function(folder, row, mode) { var post = this.sharing_data(row, {action: 'update', folder: folder, mode: mode}); this.req = this.set_busy(true, 'kolab_files.updatingfolder' + mode); this.post('sharing', post, 'sharing_update_response'); }; this.sharing_update_response = function(response) { if (!this.response(response)) return; // todo: on error reset fields? }; this.sharing_delete = function(folder, row, mode) { var post = this.sharing_data(row, {action: 'delete', folder: folder, mode: mode}); this.sharing_delete_row = row; this.req = this.set_busy(true, 'kolab_files.updatingfolder' + mode); this.post('sharing', post, 'sharing_delete_response'); }; this.sharing_delete_response = function(response) { if (!this.response(response)) return; var table = $(this.sharing_delete_row).closest('table'); if (table.data('single')) { $('tbody > tr:first', table).find('button,input,select').prop('disabled', false); } $(this.sharing_delete_row).remove(); }; this.sharing_data = function(row, data) { var error; $('select,input', row).each(function() { if (this.type == 'password' && !this.name.match(/confirm$/) && this.value != $('input[name=' + this.name + 'confirm]', row).val()) error = rcmail.display_message('kolab_files.passwordconflict', 'error'); data[this.name] = $(this).val(); }); return error ? false : data; }; // quota request this.quota = function() { if (rcmail.env.files_quota && (this.env.folder || !this.env.caps.NOROOT)) 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); }; // List of sessions this.sessions_list = function(params) { if (!rcmail.gui_objects.sessionslist) return; this.file_list_abort(true); if (!params) params = {}; if (rcmail.gui_objects.fileslist) { $(rcmail.gui_objects.fileslist).parent().hide(); $(rcmail.gui_objects.sessionslist).parent().show(); rcmail.fileslist.clear(); } this.env.folder = null; this.env.collection = null; // empty the list this.env.sessions_list = {}; rcmail.sessionslist.clear(true); rcmail.enable_command(rcmail.env.file_commands, false); rcmail.enable_command(rcmail.env.file_commands_all, false); params.req_id = this.set_busy(true, 'loading'); this.requests[params.req_id] = this.request('sessions', params, 'sessions_list_response'); }; // file list response handler this.sessions_list_response = function(response) { if (response.req_id) rcmail.hide_message(response.req_id); if (!this.response(response)) return; $.each(response.result, function(sess_id, data) { var row = file_api.session_list_row(sess_id, data); rcmail.sessionslist.insert_row(row); response.result[sess_id].row = row; }); this.env.sessions_list = response.result; rcmail.sessionslist.resize(); }; // Files list this.file_list = function(params) { if (!rcmail.gui_objects.fileslist) return; this.file_list_abort(true); if (!params) params = {}; 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.files_sort_col; if (params.reverse == undefined) params.reverse = this.env.files_sort_reverse; if (params.search == undefined) params.search = this.env.search; this.env.folder = params.folder; this.env.collection = params.collection; this.env.files_sort_col = params.sort; this.env.files_sort_reverse = params.reverse; rcmail.enable_command(rcmail.env.file_commands, false); rcmail.enable_command(rcmail.env.file_commands_all, false); if (rcmail.gui_objects.sessionslist) { $(rcmail.gui_objects.sessionslist).parent().hide(); $(rcmail.gui_objects.fileslist).parent().show(); rcmail.sessionslist.clear(true) } // empty the list this.env.file_list = []; rcmail.fileslist.clear(true); rcmail.triggerEvent('listupdate', {list: rcmail.fileslist, rowcount: 0}); // request if (params.collection || params.all_folders) this.file_list_loop(params); else if (this.env.folder) { params.req_id = this.env.file_list_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 = []; $.each(response.result, function(key, data) { var row = file_api.file_list_row(key, data, ++i); rcmail.fileslist.insert_row(row); data.row = row; data.filename = key; list.push(data); }); this.env.file_list = list; rcmail.fileslist.resize(); rcmail.triggerEvent('listupdate', {list: rcmail.fileslist, rowcount: rcmail.fileslist.rowcount}); // update document sessions info of this folder if (list && list.length) this.request('folder_info', {folder: this.file_path(list[0].filename), sessions: 1}, 'folder_info_response'); }; this.file_list_abort = function(all) { if (all) { clearTimeout(this.file_list_worker); this.file_list_worker = null; } // reset all pending list requests $.each(this.requests, function(i, v) { v.abort(); rcmail.hide_message(i); }); this.requests = {}; rcmail.set_busy(false, null, this.env.file_list_req_id); }; // 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), msg = rcmail.get_label('searching') + ' <a onclick="file_api.file_list_abort()">' + rcmail.get_label('kolab_files.abort') + '</a>'; 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_lock = false; this.env.file_list_req_id = rcmail.display_message(msg, 'loading', 5 * 60 * 1000, 'files-file-search'); rcmail.set_busy(true); for (i=0; i<folders.length && i<limit; i++) { params.req_id = new Date().getTime(); 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, params) { var folders = this.env.folders_loop, valid = this.response(response); if (folders.length) { params.req_id = new Date().getTime(); params.folder = folders.shift(); this.requests[params.req_id] = this.request('file_list', params, 'file_list_loop_response'); } else { rcmail.set_busy(false, null, this.env.file_list_req_id); } // refresh sessions info in time intervals (one request for all folders) if (!this.file_list_worker && this.env.caps && this.env.caps.DOCEDIT && (rcmail.fileslist || rcmail.env.file)) this.file_list_worker = setTimeout(function() { var params = {req_id: file_api.set_busy(true, 'loading')}; file_api.request('sessions', params, 'file_list_sessions_response'); }, 0); rcmail.fileslist.resize(); if (!valid) return; this.file_list_loop_result_add(response.result); }; // Update sessions metadata for files list (in multifolder mode) this.file_list_sessions_response = function(response) { this.file_list_worker = setTimeout(function() { var params = {req_id: file_api.set_busy(true, 'loading')}; file_api.request('sessions', params, 'file_list_sessions_response'); }, (rcmail.env.files_interval || 60) * 1000); if (response.req_id) rcmail.hide_message(response.req_id); if (!this.response(response)) return; this.sessions = []; $.each(response.result || [], function(sess_id, data) { var folder = file_api.file_path(data.file); if (!file_api.sessions[folder]) file_api.sessions[folder] = {}; file_api.sessions[folder][sess_id] = data; }); // update files list with document session info $.each(file_api.env.file_list || [], function(i, file) { var folder = file_api.file_path(file.filename); file_api.file_session_data_set(file, file_api.sessions[folder]); }); }; // 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, folder, list = [], index = this.env.file_list.length, table = rcmail.fileslist, fn = function(result, key, before) { var row = file_api.file_list_row(key, result[key], ++index); table.insert_row(row, before); result[key].row = row; result[key].filename = key; list.push(result[key]); if (!folder) folder = file_api.file_path(key); }; 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; fn(result, i, elem.row); delete result[i]; } list.push(elem); } // add the rest of rows for (i in result) fn(result, i); this.env.file_list = list; // update files list with document session info if (folder && this.sessions[folder]) $.each(list, function(i, file) { if (folder == file_api.file_path(file.filename)) file_api.file_session_data_set(file, file_api.sessions[folder]); }); 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>', table); 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); }; // Files list record this.file_list_row = function(file, data, index) { var c, col, row = ''; for (c in rcmail.env.files_coltypes) { c = rcmail.env.files_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}); // 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); }; // Sessions list record this.session_list_row = function(id, data) { var c, col, row = '', classes = ['session']; for (c in rcmail.env.sessions_coltypes) { c = rcmail.env.sessions_coltypes[c]; if (c == 'name') col = '<td class="name filename ' + this.file_type_class(data.type) + '">' + '<span>' + escapeHTML(file_api.file_name(data.file)) + '</span></td>'; else if (c == 'owner') col = '<td class="owner">' + escapeHTML(data.owner_name || data.owner) + '</td>'; else if (c == 'options') col = '<td class="options"><span></span></td>'; row += col; } if (data.is_owner) classes.push('owner'); else if (data.is_invited) classes.push('invited'); row = $('<tr>') .html(row) .attr({id: 'rcmrow' + id, 'class': classes.join(' ')}); 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'); } }; // handler for folder info response this.folder_info_response = function(response) { if (!this.response(response) || !response.result) return; var folder = response.result.folder, prefix = folder + file_api.env.directory_separator; if (response.result.sessions) this.sessions[folder] = response.result.sessions; // update files list with document session info $.each(file_api.env.file_list || [], function(i, file) { // skip files from a different folder (in multi-folder listing) if (file.filename.indexOf(prefix) >= 0) file_api.file_session_data_set(file, response.result.sessions) }); // refresh sessions info in time intervals if (this.env.caps && this.env.caps.DOCEDIT && (rcmail.fileslist || rcmail.env.file)) this.file_list_worker = setTimeout(function() { file_api.request('folder_info', {folder: folder, sessions: 1}, 'folder_info_response'); }, (rcmail.env.files_interval || 60) * 1000); }; // Set html classes on a file list entry according to defined document sessions this.file_session_data_set = function(file, sessions) { var classes = [], old_class = file.row.className; if ($(file.row).is('.selected')) classes.push('selected'); $.each(sessions || [], function(session_id, session) { if (file.filename == session.file) { if ($.inArray('session', classes) < 0) classes.push('session'); if (session.is_owner && $.inArray('owner', classes) < 0) classes.push('owner'); else if (session.is_invited && $.inArray('invited', classes) < 0) classes.push('invited'); } }); if (classes.length || old_class.length) $(file.row).attr('class', classes.join(' ')); }; 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), false); }; // 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.fileslist && (opener.file_api.env.folder == dir || !opener.file_api.env.folder)) self = opener.file_api; // also try parent for framed UI (Elastic) else if (rcmail.is_framed() && parent.rcmail.fileslist && (parent.file_api.env.folder == dir || !parent.file_api.env.folder)) self = parent.file_api; } // @TODO: consider list modification "in-place" instead of full reload self.file_list(); self.quota(); if (rcmail.env.file) { if (rcmail.is_framed()) { parent.$('.ui-dialog:visible > .ui-dialog-buttonpane button.cancel').click(); } else 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 = {}, button_classes = ['mainaction save file overwrite'], 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; kolab_dialog_close(this, true); 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) { button_classes.push('save file overwrite all'); buttons[rcmail.gettext('kolab_files.fileoverwriteall')] = function() { var f = {}, action = move ? 'file_move' : 'file_copy'; $.each(list, function() { f[this.src] = this.dst; }); kolab_dialog_close(this, true); 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(); kolab_dialog_close(this, true); if (list.length) file_api.file_move_ask_user(list, move); else if (move) file_api.file_list(); }; button_classes.push('cancel file skip'); buttons[rcmail.gettext('kolab_files.fileskip')] = skip_func; if (list.length > 1) { button_classes.push('cancel file skip all'); buttons[rcmail.gettext('kolab_files.fileskipall')] = function() { kolab_dialog_close(this, true); if (move) file_api.file_list(); }; } // open jquery UI dialog kolab_dialog_show(dialog.html(text), { title: rcmail.gettext('confirmationtitle'), close: skip_func, buttons: buttons, button_classes: button_classes, height: 50, 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) create (or clone) request this.file_create = function(file, type, edit, cloneof) { this.file_create_edit_file = edit ? file : null; this.file_create_edit_type = edit ? type : null; this.file_create_folder = this.file_path(file); if (cloneof) { this.req = this.set_busy(true, 'kolab_files.filecopying'); this.request('file_copy', {file: cloneof, 'new': file}, 'file_create_response'); } else { this.req = this.set_busy(true, 'kolab_files.filecreating'); this.request('file_create', {file: file, 'content-type': type, content: ''}, 'file_create_response'); } }; // file(s) create response handler this.file_create_response = function(response) { if (!this.response(response)) return; // @TODO: we could update metadata instead if (this.file_create_folder == this.env.folder) this.file_list(); // open the file for editing if editable if (this.file_create_edit_file) { var viewer = this.file_type_supported(this.file_create_edit_type, this.env.caps); this.file_open(this.file_create_edit_file, viewer, {action: 'edit'}); } }; // 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) { rcmail.alert_dialog(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) { delete this.uploads[id]; rcmail.display_progress({name: id}); } }; // open file in new window, using file API viewer this.file_open = function(file, viewer, params) { var args = { _task: 'files', _action: params && params.action ? params.action : 'open', _file: file, _viewer: viewer || 0, _frame: 1 }; if (rcmail.is_framed()) args._framed = 1; if (params && params.session) args._session = params.session; if (rcmail.env.extwin) args._extwin = 1; href = '?' + $.param(args); if (params && params.local) location.href = href; else 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); } }; // document session delete request this.document_delete = function(id) { this.req = this.set_busy(true, 'kolab_files.sessionterminating'); this.request('document_delete', {id: id}, 'document_delete_response'); }; // document session delete response handler this.document_delete_response = function(response, params) { if (!this.response(response)) return; var list = rcmail.sessionslist; // remove session from the list (if sessions list exist) if (list) list.remove_row(params.id); if (this.env.sessions_list) delete this.env.sessions_list[params.id]; // @todo: force sessions info update, update files list }; // Invite document session participants this.document_invite = function(id, attendees, comment) { var list = []; // expect attendees to be email => name hash $.each(attendees || {}, function() { list.push(this); }); if (list.length) { this.req = this.set_busy(true, 'kolab_files.documentinviting'); this.request('document_invite', {id: id, users: list, comment: comment || ''}, 'document_invite_response'); } }; // document invite response handler this.document_invite_response = function(response) { if (!this.response(response) || !response.result) return; var info = rcmail.env.file_data, table = $('#document-editors-dialog table > tbody'); $.each(response.result.list || {}, function() { var record = kolab_files_attendee_record(this.user, this.status, this.user_name); table.append(record); if (info.session && info.session.invitations) info.session.invitations.push($.extend({status: 'invited', record: record}, this)); }); }; // Cancel invitations to an editing session this.document_cancel = function(id, attendees) { if (attendees.length) { this.req = this.set_busy(true, 'kolab_files.documentcancelling'); this.request('document_cancel', {id: id, users: attendees}, 'document_cancel_response'); } }; // document_cancel response handler this.document_cancel_response = function(response) { if (!this.response(response) || !response.result) return; var info = rcmail.env.file_data; $.each(response.result.list || {}, function(i, user) { var invitations = []; $.each(info.session.invitations, function(i, u) { if (u.user == user && u.record) u.record.remove(); else invitations.push(u); }); info.session.invitations = invitations; }); }; // 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 = {}; $.each(result.auth_errors || {}, function(i, v) { // for normal errors we display only an error message, other will display a dialog if (v.error) { if (v.error == 580) { rcmail.display_message(rcmail.gettext('kolab_files.storageautherror').replace('$title', i), 'error'); } delete result.auth_errors[i]; } }); $.extend(this.auth_errors, result.auth_errors); } // ask for password to the first storage on the list var ref = this; $.each(this.auth_errors || [], function(i, v) { if (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); if ($('#files-folder-auth-dialog').is(':visible')) return false; dialog.find('table.propform').remove(); $('.auth-options', dialog).before(content); args.buttons[this.t('kolab_files.save')] = function() { var data = {folder: label, list: 1, permissions: 1, level: -2}; $('input', dialog).each(function() { data[this.name] = this.type == 'checkbox' && !this.checked ? '' : this.value; }); file_api.req = file_api.set_busy(true, 'kolab_files.authenticating'); file_api.request('folder_auth', data, 'folder_auth_response'); kolab_dialog_close(this); }; 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); args.button_classes = ['mainaction save', 'cancel']; // show dialog window kolab_dialog_show(dialog, args, function() { // focus first empty input $('input', dialog).each(function() { if (!this.value) { this.focus(); return false; } }); }); return true; }; // folder_auth handler this.folder_auth_response = function(response, params) { if (!this.response(response)) { this.folder_list_auth_errors(); return; } delete this.auth_errors[response.result.folder]; // go to the next one this.folder_list_auth_errors(); // update the list this.folder_list_merge(response.result.folder, response.result.list, params.level); }; // Update folders list with additional folders this.folder_list_merge = function(folder, list, level) { if (!list || !list.length) return; var i, last, folders, result = {}, index = [], ref = this; if (this.list_merge_lock) { return setTimeout(function() { ref.folder_list_merge(folder, list); }, 50); } this.list_merge_lock = true; // Parse result folders = this.folder_list_parse(list); if (level < 0) level *= -1; // Add folders from the external source to the list $.each(folders, function(i, f) { if (ref.env.folders[i]) { last = i; return; } // We don't use this id delete f.id; // Append row to the list var row = file_api.folder_list_row(i, f); if (row) ref.list_element.append(row); // Need env.folders update so all parents are available // in successive folder_list_row() calls ref.env.folders[i] = f; index.push(i); // Load deeper folder hierarchies if (level && f.depth == level) ref.folder_list_update_wait(i); }); // Reset folders list widget rcmail.folder_list.reset(true, true); // Rebuild folders list with correct order for (i in this.env.folders) { result[i] = this.env.folders[i]; if (i === last) break; } for (i in index) { result[index[i]] = this.env.folders[index[i]]; } for (i in this.env.folders) { if (!result[i]) { result[i] = this.env.folders[i]; } } this.env.folders = result; if ((folder = this.env.folder) || (folder = this.env.init_folder)) { if (this.env.folders[folder]) { this.env.init_folder = null; if (folder != rcmail.folder_list.get_selection()) rcmail.folder_list.select(folder); } } this.list_merge_lock = false; }; // 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); }; };
修改文件时间
将文件时间修改为当前时间的前一年
删除文件