plugins/kolab_files

Aleksander Machniak machniak at kolabsys.com
Thu May 16 13:09:58 CEST 2013


 plugins/kolab_files/config.inc.php.dist                       |    5 
 plugins/kolab_files/kolab_files.js                            |  430 ++++++++--
 plugins/kolab_files/lib/kolab_files_engine.php                |   33 
 plugins/kolab_files/localization/en_US.inc                    |   13 
 plugins/kolab_files/skins/larry/images/folders.png            |binary
 plugins/kolab_files/skins/larry/style.css                     |   36 
 plugins/kolab_files/skins/larry/templates/compose_plugin.html |   11 
 plugins/kolab_files/skins/larry/templates/files.html          |   87 +-
 plugins/kolab_files/skins/larry/ui.js                         |   10 
 9 files changed, 489 insertions(+), 136 deletions(-)

New commits:
commit 716a464a6ddb441867ce1509206bc808519e2ff9
Author: Aleksander Machniak <machniak at kolabsys.com>
Date:   Thu May 16 13:08:58 2013 +0200

    Added support for virtual collections, multi-folder search,
    skip/overwrite questions on file move/copy, other improvements

diff --git a/plugins/kolab_files/config.inc.php.dist b/plugins/kolab_files/config.inc.php.dist
index 0c9704c..fd3016b 100644
--- a/plugins/kolab_files/config.inc.php.dist
+++ b/plugins/kolab_files/config.inc.php.dist
@@ -1,7 +1,7 @@
 <?php
 
 // URL of kolab-chwala installation
-$rcmail_config['kolab_files_url'] = 'https://' . $_SERVER["HTTP_HOST"] . '/chwala';
+$rcmail_config['kolab_files_url'] = 'https://localhost/kolab-chwala/public_html';
 
 // List of files list columns. Available are: name, size, mtime, type
 $rcmail_config['kolab_files_list_cols'] = array('name', 'mtime', 'size');
@@ -12,4 +12,7 @@ $rcmail_config['kolab_files_sort_col'] = 'name';
 // Order of the files list sort
 $rcmail_config['kolab_files_sort_order'] = 'asc';
 
+// Number of concurent requests for searching and collections listing. Default: 1
+$rcmail_config['kolab_files_search_threads'] = 1;
+
 ?>
diff --git a/plugins/kolab_files/kolab_files.js b/plugins/kolab_files/kolab_files.js
index 2bbb2e6..097e038 100644
--- a/plugins/kolab_files/kolab_files.js
+++ b/plugins/kolab_files/kolab_files.js
@@ -64,12 +64,10 @@ window.rcmail && rcmail.addEventListener('init', function() {
       rcmail.file_list.addEventListener('dblclick', function(o){ p.msglist_dbl_click(o); });
       rcmail.file_list.addEventListener('click', function(o){ p.msglist_click(o); });
       rcmail.file_list.addEventListener('keypress', function(o){ p.msglist_keypress(o); });
-*/
-      rcmail.file_list.addEventListener('select', function(o){ kolab_files_list_select(o); });
-/*
       rcmail.file_list.addEventListener('dragstart', function(o){ p.drag_start(o); });
       rcmail.file_list.addEventListener('dragmove', function(e){ p.drag_move(e); });
 */
+      rcmail.file_list.addEventListener('select', function(o){ kolab_files_list_select(o); });
       rcmail.file_list.addEventListener('dragend', function(e){ kolab_files_drag_end(e); });
       rcmail.file_list.addEventListener('column_replace', function(e){ kolab_files_set_coltypes(e); });
       rcmail.file_list.addEventListener('listupdate', function(e){ rcmail.triggerEvent('listupdate', e); });
@@ -110,8 +108,9 @@ function kolab_files_init()
   file_api.set_env({
     token: kolab_files_token(),
     url: rcmail.env.files_url,
-    sort_column: 'name',
-    sort_reverse: 0
+    sort_col: 'name',
+    sort_reverse: false,
+    search_threads: rcmail.env.search_threads
   });
 
   file_api.translations = rcmail.labels;
@@ -201,10 +200,10 @@ function kolab_files_selector_dialog()
 
     if (list.length) {
       // display upload indicator and cancel button
-      var content = '<span>' + rcmail.get_label('uploading' + (list.length > 1 ? 'many' : '')) + '</span>',
+      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 });
+      rcmail.add2attachment_list(id, {name:'', html:content, classname:'uploading', complete:false});
 
       // send request
       rcmail.http_post('plugin.kolab_files', {
@@ -396,7 +395,7 @@ kolab_files_set_list_options = function(cols, sort_col, sort_order)
   }
 
   if (update == 1)
-    file_api.file_list({sort: sort_col, reverse: sort_order == 'DESC'});
+    rcmail.command('files-list', {sort: sort_col, reverse: sort_order == 'DESC'});
   else if (update) {
     rcmail.http_post('files/prefs', {
       kolab_files_list_cols: oldcols,
@@ -514,7 +513,7 @@ rcube_webmail.prototype.files_sort = function(props)
   params.sort = sort_col;
   params.reverse = sort_order == 'DESC';
 
-  file_api.file_list(params);
+  this.command('files-list', params);
 };
 
 rcube_webmail.prototype.files_search = function()
@@ -522,7 +521,7 @@ rcube_webmail.prototype.files_search = function()
   var value = $(this.gui_objects.filesearchbox).val();
 
   if (value)
-    file_api.file_search(value);
+    file_api.file_search(value, $('#search_all_folders').is(':checked'));
   else
     file_api.file_search_reset();
 };
@@ -567,6 +566,12 @@ rcube_webmail.prototype.files_upload = function(form)
     file_api.file_upload(form);
 };
 
+rcube_webmail.prototype.files_list = function(param)
+{
+  // just rcmail wrapper, to handle command busy states
+  file_api.file_list(param);
+}
+
 rcube_webmail.prototype.files_list_update = function(head)
 {
   var list = this.file_list;
@@ -625,10 +630,11 @@ function kolab_files_ui()
     rcmail.http_error(request, status, err);
   };
 
+  // folders list request
   this.folder_list = function()
   {
     this.req = this.set_busy(true, 'loading');
-    this.get('folder_list', {}, 'folder_list_response');
+    this.request('folder_list', {}, 'folder_list_response');
   };
 
   // folder list response handler
@@ -638,7 +644,8 @@ function kolab_files_ui()
       return;
 
     var first, elem = $('#files-folder-list'),
-      list = $('<ul class="listing"></ul>');
+      list = $('<ul class="listing"></ul>'),
+      collections = !rcmail.env.action.match(/^(preview|show)$/) ? ['audio', 'video', 'image', 'document'] : [];
 
     elem.html('').append(list);
 
@@ -672,33 +679,71 @@ function kolab_files_ui()
         first = i;
     });
 
+    // add virtual collections
+    $.each(collections, function(i, n) {
+      var row = $('<li class="mailbox collection ' + n + '"></li>');
+
+      row.attr('id', 'folder-collection-' + n)
+        .append($('<span class="name">').text(rcmail.gettext('kolab_files.collection_' + n)))
+        .click(function() { file_api.folder_select(n, true); });
+
+      list.append(row);
+    });
+
    // select first folder?
-   if (this.env.folder || first)
-     this.folder_select(this.env.folder ? this.env.folder : first);
+   if (this.env.folder)
+     this.folder_select(this.env.folder);
+   else if (this.env.collection)
+     this.folder_select(this.env.collection, true);
+   else if (first)
+     this.folder_select(first);
 
     // add tree icons
     this.folder_list_tree(this.env.folders);
   };
 
-  this.folder_select = function(i)
+  this.folder_select = function(folder, is_collection)
   {
     var list = $('#files-folder-list > ul');
+
+    if (rcmail.busy)
+      return;
+
     $('li.selected', list).removeClass('selected');
-    $('#' + this.env.folders[i].id, list).addClass('selected');
 
-    this.env.folder = i;
+    rcmail.enable_command('files-list', true);
 
-    rcmail.enable_command('files-folder-delete', 'files-upload', true);
+    if (is_collection) {
+      var found = $('#folder-collection-' + folder, list).addClass('selected');
 
-    // list files in selected folder
-    this.file_list();
+      rcmail.enable_command('files-folder-delete', 'files-upload', false);
+      this.env.folder = null;
+      rcmail.command('files-list', {collection: folder});
+    }
+    else {
+      var found = $('#' + this.env.folders[folder].id, list).addClass('selected');
+
+      rcmail.enable_command('files-folder-delete', 'files-upload', true);
+      this.env.folder = folder;
+      this.env.collection = null;
+      rcmail.command('files-list', {folder: folder});
+    }
+  };
+
+  this.folder_unselect = function()
+  {
+    var list = $('#files-folder-list > ul');
+    $('li.selected', list).removeClass('selected');
+    rcmail.enable_command('files-folder-delete', 'files-upload', false);
+    this.env.folder = null;
+    this.env.collection = null;
   };
 
   // folder create request
   this.folder_create = function(folder)
   {
     this.req = this.set_busy(true, 'kolab_files.foldercreating');
-    this.get('folder_create', {folder: folder}, 'folder_create_response');
+    this.request('folder_create', {folder: folder}, 'folder_create_response');
   };
 
   // folder create response handler
@@ -717,7 +762,7 @@ function kolab_files_ui()
   this.folder_delete = function(folder)
   {
     this.req = this.set_busy(true, 'kolab_files.folderdeleting');
-    this.get('folder_delete', {folder: folder}, 'folder_delete_response');
+    this.request('folder_delete', {folder: folder}, 'folder_delete_response');
   };
 
   // folder delete response handler
@@ -727,7 +772,7 @@ function kolab_files_ui()
       return;
 
     this.env.folder = null;
-    rcmail.enable_command('files-folder-delete', 'files-folder-rename', false);
+    rcmail.enable_command('files-folder-delete', 'files-folder-rename', 'files-list', false);
     this.display_message('kolab_files.folderdeletenotice', 'confirmation');
 
     // refresh folders list
@@ -736,14 +781,22 @@ function kolab_files_ui()
 
   this.file_list = function(params)
   {
-    if (!this.env.folder || !rcmail.gui_objects.filelist)
+    if (!rcmail.gui_objects.filelist)
       return;
 
     if (!params)
       params = {};
 
-    params.folder = this.env.folder;
+    if (params.all_folders) {
+      params.collection = null;
+      params.folder = null;
+      this.folder_unselect();
+    }
 
+    if (params.collection == undefined)
+      params.collection = this.env.collection;
+    if (params.folder == undefined)
+      params.folder = this.env.folder;
     if (params.sort == undefined)
       params.sort = this.env.sort_col;
     if (params.reverse == undefined)
@@ -751,16 +804,25 @@ function kolab_files_ui()
     if (params.search == undefined)
       params.search = this.env.search;
 
+    this.env.folder = params.folder;
+    this.env.collection = params.collection;
     this.env.sort_col = params.sort;
     this.env.sort_reverse = params.reverse;
 
-    this.req = this.set_busy(true, 'loading');
-
     rcmail.enable_command(rcmail.env.file_commands, false);
     rcmail.enable_command(rcmail.env.file_commands_all, false);
+
+    // empty the list
+    this.env.file_list = [];
     rcmail.file_list.clear();
 
-    this.get('file_list', params, 'file_list_response');
+    // request
+    if (params.collection || params.all_folders)
+      this.file_list_loop(params);
+    else if (this.env.folder) {
+      this.req = this.set_busy(true, 'loading');
+      this.request('file_list', params, 'file_list_response');
+    }
   };
 
   // file list response handler
@@ -771,51 +833,174 @@ function kolab_files_ui()
 
     var i = 0, table = $('#filelist');
 
-    $('tbody', table).empty();
-
     $.each(response.result, function(key, data) {
-      var c, col, row = '';
-
       i++;
+      var row = file_api.file_list_row(key, data, i);
+      rcmail.file_list.insert_row(row);
+    });
+  };
+
+  // call file_list request for every folder (used for search and virt. collections)
+  this.file_list_loop = function(params)
+  {
+    var i, folders = [], limit = Math.max(this.env.search_threads || 1, 1);
+
+    if (params.collection) {
+      if (!params.search)
+        params.search = {};
+      params.search['class'] = params.collection;
+      delete params['collection'];
+    }
+
+    delete params['all_folders'];
+
+    $.each(this.env.folders, function(i, f) {
+      if (!f.virtual)
+        folders.push(i);
+    });
+
+    this.env.folders_loop = folders;
+    this.env.folders_loop_params = params;
+    this.env.folders_loop_lock = false;
+
+    for (i=0; i<folders.length && i<limit; i++) {
+      this.req = this.set_busy(true, 'loading');
+      params.folder = folders.shift();
+      this.request('file_list', params, 'file_list_loop_response');
+    }
+  };
+
+  // file list response handler for loop'ed request
+  this.file_list_loop_response = function(response)
+  {
+    var i, folders = this.env.folders_loop,
+      params = this.env.folders_loop_params,
+      limit = Math.max(this.env.search_threads || 1, 1),
+      valid = this.response(response);
+
+    for (i=0; i<folders.length && i<limit; i++) {
+      this.req = this.set_busy(true, 'loading');
+      params.folder = folders.shift();
+      this.request('file_list', params, 'file_list_loop_response');
+    }
+
+    if (!valid)
+      return;
+
+    this.file_list_loop_result_add(response.result);
+  };
+
+  // add files from list request to the table (with sorting)
+  this.file_list_loop_result_add = function(result)
+  {
+    // chack if result (hash-array) is empty
+    if (!object_is_empty(result))
+      return;
+
+    if (this.env.folders_loop_lock) {
+      setTimeout(function() { file_api.file_list_loop_result_add(result); }, 100);
+      return;
+    }
+
+    // lock table, other list responses will wait
+    this.env.folders_loop_lock = true;
+
+    var n, i, len, elem, list = [], rows = [],
+      index = this.env.file_list.length,
+      table = rcmail.file_list;
 
-      for (c in rcmail.env.coltypes) {
-        c = rcmail.env.coltypes[c];
-        if (c == 'name')
-            col = '<td class="name filename ' + file_api.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">' + file_api.file_size(data.size) + '</td>';
-        else if (c == 'options')
-          col = '<td class="options"></td>'; // @TODO
-        else
-          col = '<td class="' + c + '"></td>';
-
-        row += col;
+    for (n=0, len=index; n<len; n++) {
+      elem = this.env.file_list[n];
+      for (i in result) {
+        if (this.sort_compare(elem, result[i]) < 0)
+          break;
+
+        var row = this.file_list_row(i, result[i], index++);
+        table.insert_row(row, elem.row);
+        result[i].row = row;
+        list.push(result[i]);
+        delete result[i];
       }
 
-      row = $('<tr>')
-        .html(row)
-        .attr({id: 'rcmrow' + i, 'data-file': key});
+      list.push(elem);
+    }
+
+    // add the rest of rows
+    $.each(result, function(key, data) {
+      var row = file_api.file_list_row(key, data, index++);
+      table.insert_row(row);
+      result[key].row = row;
+      list.push(result[key]);
+    });
+
+    this.env.file_list = list;
+    this.env.folders_loop_lock = false;
+  };
+
+  // sort files list (without API request)
+  this.file_list_sort = function(col, reverse)
+  {
+    var n, len, list = this.env.file_list,
+      table = $('#filelist'), tbody = $('<tbody>');
+
+    this.env.sort_col = col;
+    this.env.sort_reverse = reverse;
+
+    if (!list || !list.length)
+      return;
 
-//      table.append(row);
-      rcmail.file_list.insert_row(row.get([0]));
+    // sort the list
+    list.sort(function (a, b) {
+      return file_api.sort_compare(a, b);
     });
+
+    // add rows to the new body
+    for (n=0, len=list.length; n<len; n++) {
+      tbody.append(list[n].row);
+    }
+
+    // replace table bodies
+    $('tbody', table).replaceWith(tbody);
   };
 
-  this.file_select = function(e, row)
+  this.file_list_row = function(file, data, index)
   {
-    var table = $('#filelist');
-//    $('tr.selected', table).removeClass('selected');
-    $(row).addClass('selected');
+    var c, col, row = '';
+
+    for (c in rcmail.env.coltypes) {
+      c = rcmail.env.coltypes[c];
+      if (c == 'name')
+        col = '<td class="name filename ' + this.file_type_class(data.type) + '">'
+          + '<span>' + escapeHTML(data.name) + '</span></td>';
+      else if (c == 'mtime')
+        col = '<td class="mtime">' + data.mtime + '</td>';
+      else if (c == 'size')
+        col = '<td class="size">' + this.file_size(data.size) + '</td>';
+      else if (c == 'options')
+        col = '<td class="options"></td>'; // @TODO
+      else
+        col = '<td class="' + c + '"></td>';
+
+      row += col;
+    }
+
+    row = $('<tr>')
+      .html(row)
+      .attr({id: 'rcmrow' + index, 'data-file': file});
+
+    // collection (or search) lists files from all folders
+    // display file name with full path as title
+    if (!this.env.folder)
+      $('td.name span', row).attr('title', file);
+
+    return row.get(0);
   };
 
-  this.file_search = function(value)
+  this.file_search = function(value, all_folders)
   {
     if (value) {
       this.env.search = {name: value};
-      this.file_list({search: this.env.search});
+      rcmail.command('files-list', {search: this.env.search, all_folders: all_folders});
     }
     else
       this.search_reset();
@@ -825,7 +1010,7 @@ function kolab_files_ui()
   {
     if (this.env.search) {
       this.env.search = null;
-      this.file_list();
+      rcmail.command('files-list');
     }
   };
 
@@ -844,7 +1029,7 @@ function kolab_files_ui()
   this.file_delete = function(files)
   {
     this.req = this.set_busy(true, 'kolab_files.filedeleting');
-    this.get('file_delete', {file: files}, 'file_delete_response');
+    this.request('file_delete', {file: files}, 'file_delete_response');
   };
 
   // file(s) delete response handler
@@ -863,13 +1048,22 @@ function kolab_files_ui()
     if (!files || !files.length || !folder)
       return;
 
-    var list = {};
+    var count = 0, list = {};
+
     $.each(files, function(i, v) {
-      list[v] = folder + file_api.env.directory_separator + file_api.file_name(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.get('file_move', {file: list}, 'file_move_response');
+    this.request('file_move', {file: list}, 'file_move_response');
   };
 
   // file(s) move response handler
@@ -878,8 +1072,12 @@ function kolab_files_ui()
     if (!this.response(response))
       return;
 
-    this.display_message('kolab_files.filemovenotice', 'confirmation');
-    this.file_list();
+    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
@@ -888,13 +1086,22 @@ function kolab_files_ui()
     if (!files || !files.length || !folder)
       return;
 
-    var list = {};
+    var count = 0, list = {};
+
     $.each(files, function(i, v) {
-      list[v] = folder + file_api.env.directory_separator + file_api.file_name(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.get('file_copy', {file: list}, 'file_copy_response');
+    this.request('file_copy', {file: list}, 'file_copy_response');
   };
 
   // file(s) copy response handler
@@ -903,7 +1110,88 @@ function kolab_files_ui()
     if (!this.response(response))
       return;
 
-    this.display_message('kolab_files.filecopynotice', 'confirmation');
+    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');
+  };
+
+  // when file move/copy operation returns file-exists error
+  // this displays a dialog where user can decide to skip
+  // or overwrite destination file(s)
+  this.file_move_ask_user = function(list, move)
+  {
+    var file = list[0], buttons = {},
+      text = rcmail.gettext('kolab_files.filemoveconfirm').replace('$file', file.dst)
+      dialog = $('<div></div>');
+
+    buttons[rcmail.gettext('kolab_files.fileoverwrite')] = function() {
+      var file = list.shift(), f = {},
+        action = move ? 'file_move' : 'file_copy';
+
+      f[file.src] = file.dst;
+      file_api.file_move_ask_list = list;
+      file_api.file_move_ask_mode = move;
+      dialog.dialog('destroy').remove();
+      file_api.req = file_api.set_busy(true, move ? 'kolab_files.filemoving' : 'kolab_files.filecopying');
+      file_api.request(action, {file: f, overwrite: 1}, 'file_move_ask_user_response');
+    };
+
+    if (list.length > 1)
+      buttons[rcmail.gettext('kolab_files.fileoverwriteall')] = function() {
+        var f = {}, action = move ? 'file_move' : 'file_copy';
+
+        $.each(list, function() { f[this.src] = this.dst; });
+        dialog.dialog('destroy').remove();
+        file_api.req = file_api.set_busy(true, move ? 'kolab_files.filemoving' : 'kolab_files.filecopying');
+        file_api.request(action, {file: f, overwrite: 1}, action + '_response');
+      };
+
+    var skip_func = function() {
+      list.shift();
+      dialog.dialog('destroy').remove();
+
+      if (list.length)
+        file_api.file_move_ask_user(list, move);
+      else if (move)
+        file_api.file_list();
+    };
+
+    buttons[rcmail.gettext('kolab_files.fileskip')] = skip_func;
+
+    if (list.length > 1)
+      buttons[rcmail.gettext('kolab_files.fileskipall')] = function() {
+      dialog.dialog('destroy').remove();
+        if (move)
+          file_api.file_list();
+      };
+
+    // open jquery UI dialog
+    dialog.dialog({
+      modal: true,
+      resizable: !bw.ie6,
+      closeOnEscape: (!bw.ie6 && !bw.ie7),  // disable for performance reasons
+      close: skip_func,
+      buttons: buttons,
+      minWidth: 400,
+      width: 400
+    }).html(text).show();
+  };
+
+  // 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 upload request
@@ -915,7 +1203,7 @@ function kolab_files_ui()
 
     if (files) {
       // submit form and read server response
-      this.async_upload_form(form, 'file_create', function(event) {
+      this.file_upload_form(form, 'file_upload', function(event) {
         var doc, response;
         try {
           doc = this.contentDocument ? this.contentDocument : this.contentWindow.document;
@@ -939,7 +1227,7 @@ function kolab_files_ui()
   };
 
   // post the given form to a hidden iframe
-  this.async_upload_form = function(form, action, onload)
+  this.file_upload_form = function(form, action, onload)
   {
     var ts = rcmail.display_message(rcmail.get_label('kolab_files.uploading'), 'loading', 1000),
       frame_name = 'fileupload'+ts;
diff --git a/plugins/kolab_files/lib/kolab_files_engine.php b/plugins/kolab_files/lib/kolab_files_engine.php
index 3600efb..4e42c82 100644
--- a/plugins/kolab_files/lib/kolab_files_engine.php
+++ b/plugins/kolab_files/lib/kolab_files_engine.php
@@ -44,7 +44,7 @@ class kolab_files_engine
      */
     public function ui()
     {
-        $this->plugin->add_texts('localization/', true);
+        $this->plugin->add_texts('localization/');
 
         // set templates of Files UI and widgets
         if ($this->rc->task == 'mail') {
@@ -67,6 +67,11 @@ class kolab_files_engine
                     'label'      => 'kolab_files.saveto',
                     ), 'attachmentmenu');
             }
+
+            $this->plugin->add_label('save', 'cancel',
+                'saveall', 'fromcloud', 'attachsel', 'selectfiles', 'attaching',
+                'collection_audio', 'collection_video', 'collection_image', 'collection_document'
+            );
         }
         else if ($this->rc->task == 'files') {
             $template = 'files';
@@ -155,7 +160,7 @@ class kolab_files_engine
             $out = $this->rc->output->form_tag($attrib, $out);
         }
 
-        $this->rc->output->add_label('kolab_files.foldercreating', 'kolab_files.create');
+        $this->plugin->add_label('foldercreating', 'create', 'foldercreate', 'cancel');
         $this->rc->output->add_gui_object('folder-create-form', $attrib['id']);
 
         return $out;
@@ -185,6 +190,7 @@ class kolab_files_engine
         // add form tag around text field
         if (empty($attrib['form'])) {
             $out = $this->rc->output->form_tag(array(
+                    'action'   => '?_task=files',
                     'name'     => "filesearchform",
                     'onsubmit' => rcmail_output::JS_OBJECT_NAME . ".command('files-search'); return false",
                 ), $out);
@@ -198,8 +204,6 @@ class kolab_files_engine
      */
     public function file_list($attrib)
     {
-//        $this->rc->output->add_label('');
-
         // define list of cols to be displayed based on parameter or config
         if (empty($attrib['columns'])) {
             $list_cols     = $this->rc->config->get('kolab_files_list_cols');
@@ -211,7 +215,6 @@ class kolab_files_engine
             $a_show_cols = preg_split('/[\s,;]+/', strip_quotes($attrib['columns']));
         }
 
-
         // make sure 'name' and 'options' column is present
         if (!in_array('name', $a_show_cols)) {
             array_unshift($a_show_cols, 'name');
@@ -241,6 +244,7 @@ class kolab_files_engine
         $this->rc->output->set_env('sort_col', $_SESSION['kolab_files_sort_col']);
         $this->rc->output->set_env('sort_order', $_SESSION['kolab_files_sort_order']);
         $this->rc->output->set_env('coltypes', $a_show_cols);
+        $this->rc->output->set_env('search_threads', $this->rc->config->get('kolab_files_search_threads'));
 
         $this->rc->output->include_script('list.js');
 
@@ -263,7 +267,7 @@ class kolab_files_engine
     protected function file_list_head($attrib, $a_show_cols)
     {
         $skin_path = $_SESSION['skin_path'];
-        $image_tag = html::img(array('src' => "%s%s", 'alt' => "%s"));
+//        $image_tag = html::img(array('src' => "%s%s", 'alt' => "%s"));
 
         // check to see if we have some settings for sorting
         $sort_col   = $_SESSION['kolab_files_sort_col'];
@@ -456,12 +460,12 @@ class kolab_files_engine
 
     protected function action_index()
     {
-        $this->rc->output->add_label(
-            'kolab_files.folderdeleting', 'kolab_files.folderdeleteconfirm',
-            'kolab_files.foldercreating', 'kolab_files.uploading',
-            'kolab_files.filedeleting', 'kolab_files.filedeletenotice', 'kolab_files.filedeleteconfirm',
-            'kolab_files.filemoving', 'kolab_files.filemovenotice',
-            'kolab_files.filecopying', 'kolab_files.filecopynotice'
+        $this->plugin->add_label(
+            'folderdeleting', 'folderdeleteconfirm', 'foldercreating', 'uploading', 'attaching',
+            'filedeleting', 'filedeletenotice', 'filedeleteconfirm',
+            'filemoving', 'filemovenotice', 'filecopying', 'filecopynotice',
+            'collection_audio', 'collection_video', 'collection_image', 'collection_document',
+            'fileskip', 'fileskipall', 'fileoverwrite', 'fileoverwriteall', 'filemoveconfirm'
         );
 
         $this->rc->output->set_pagetitle($this->plugin->gettext('files'));
@@ -511,14 +515,13 @@ class kolab_files_engine
      */
     protected function action_save_file()
     {
-        $source = rcube_utils::get_input_value('source', rcube_utils::INPUT_POST);
+//        $source = rcube_utils::get_input_value('source', rcube_utils::INPUT_POST);
         $uid    = rcube_utils::get_input_value('uid', rcube_utils::INPUT_POST);
         $dest   = rcube_utils::get_input_value('dest', rcube_utils::INPUT_POST);
         $id     = rcube_utils::get_input_value('id', rcube_utils::INPUT_POST);
         $name   = rcube_utils::get_input_value('name', rcube_utils::INPUT_POST);
 
         $temp_dir = unslashify($this->rc->config->get('temp_dir'));
-        $storage  = $this->rc->get_storage();
         $message  = new rcube_message($uid);
         $request  = $this->get_request();
         $url      = $request->getUrl();
@@ -528,7 +531,7 @@ class kolab_files_engine
 
         $request->setMethod(HTTP_Request2::METHOD_POST);
         $request->setHeader('X-Session-Token', $this->get_api_token());
-        $url->setQueryVariables(array('method' => 'file_create', 'folder' => $dest));
+        $url->setQueryVariables(array('method' => 'file_upload', 'folder' => $dest));
         $request->setUrl($url);
 
         foreach ($message->attachments as $attach_prop) {
diff --git a/plugins/kolab_files/localization/en_US.inc b/plugins/kolab_files/localization/en_US.inc
index a038ff3..1b6eb81 100644
--- a/plugins/kolab_files/localization/en_US.inc
+++ b/plugins/kolab_files/localization/en_US.inc
@@ -27,7 +27,13 @@ $labels['view'] = 'View';
 $labels['viewfile'] = 'View file';
 $labels['deletefile'] = 'Delete selected file(s)';
 
+$labels['collection_audio'] = 'Audio';
+$labels['collection_video'] = 'Video';
+$labels['collection_image'] = 'Images';
+$labels['collection_document'] = 'Documents';
+
 $labels['uploading'] = 'Uploading file(s)...';
+$labels['attaching'] = 'Attaching file(s)...';
 $labels['foldercreating'] = 'Creating folder...';
 $labels['folderdeleting'] = 'Deleting folder...';
 $labels['folderdeleteconfirm'] = 'Are you sure you want to delete selected folder?';
@@ -44,4 +50,11 @@ $labels['filedeletenotice'] = 'File(s) deleted successfully.';
 $labels['filemovenotice'] = 'File(s) moved successfully.';
 $labels['filecopynotice'] = 'File(s) copied successfully.';
 
+$labels['allfolders'] = 'search in all folders';
+$labels['fileskip'] = 'Skip';
+$labels['fileskipall'] = 'Skip all';
+$labels['fileoverwrite'] = 'Overwrite';
+$labels['fileoverwriteall'] = 'Overwrite all';
+$labels['filemoveconfirm'] = 'This action is going to overwrite the destination file: <b>$file</b>.';
+
 ?>
diff --git a/plugins/kolab_files/skins/larry/images/folders.png b/plugins/kolab_files/skins/larry/images/folders.png
new file mode 100644
index 0000000..e716ef8
Binary files /dev/null and b/plugins/kolab_files/skins/larry/images/folders.png differ
diff --git a/plugins/kolab_files/skins/larry/style.css b/plugins/kolab_files/skins/larry/style.css
index 2602eba..fcaaea6 100644
--- a/plugins/kolab_files/skins/larry/style.css
+++ b/plugins/kolab_files/skins/larry/style.css
@@ -46,6 +46,12 @@
   display: inline;
 }
 
+#quicksearchbar #filesearchmenulink {
+  position: absolute;
+  top: 5px;
+  left: 6px;
+}
+
 #folderlistbox {
   position: absolute;
   top: 42px;
@@ -83,6 +89,34 @@
   color: #376572;
 }
 
+#files-folder-list ul li.mailbox.collection span.name {
+  background: url(images/folders.png) 5px 0 no-repeat;
+}
+#files-folder-list ul li.mailbox.collection.audio span.name {
+  background-position: 5px -95px;
+}
+#files-folder-list ul li.mailbox.collection.video span.name {
+  background-position: 5px -143px;
+}
+#files-folder-list ul li.mailbox.collection.document span.name {
+  background-position: 5px 0;
+}
+#files-folder-list ul li.mailbox.collection.image span.name {
+  background-position: 5px -48px;
+}
+#files-folder-list ul li.mailbox.collection.audio.selected span.name {
+  background-position: 5px -119px;
+}
+#files-folder-list ul li.mailbox.collection.video.selected span.name {
+  background-position: 5px -167px;
+}
+#files-folder-list ul li.mailbox.collection.document.selected span.name {
+  background-position: 5px -24px;
+}
+#files-folder-list ul li.mailbox.collection.image.selected span.name {
+  background-position: 5px -72px;
+}
+
 #files-folder-list ul li span.branch {
   display: inline-block;
 }
@@ -107,7 +141,7 @@
 }
 
 #filelist tr td.size {
-  width: 60px;
+  width: 80px;
   text-align: right;
 }
 
diff --git a/plugins/kolab_files/skins/larry/templates/compose_plugin.html b/plugins/kolab_files/skins/larry/templates/compose_plugin.html
index 1e4df79..7ab8777 100644
--- a/plugins/kolab_files/skins/larry/templates/compose_plugin.html
+++ b/plugins/kolab_files/skins/larry/templates/compose_plugin.html
@@ -1,10 +1,7 @@
 <div id="files-compose-dialog" class="uidialog">
     <div id="quicksearchbar" class="searchbox">
         <roundcube:object name="file-search-form" id="filesearchbox" />
-<!--
-        <roundcube:button name="searchmenulink" id="searchmenulink" class="iconbutton searchoptions" onclick="UI.show_popup('searchmenu');return false" title="searchmod" content=" " />
--->
-        <a id="searchmenulink" class="iconbutton searchoptions"> </a>
+        <roundcube:button name="filesearchmenulink" id="filesearchmenulink" class="iconbutton searchoptions" onclick="UI.show_popup('filesearchmenu');return false" title="searchmod" content=" " />
         <roundcube:button command="files-search-reset" id="searchreset" class="iconbutton reset" title="resetsearch" content=" " />
     </div>
 
@@ -16,3 +13,9 @@
         <roundcube:object name="filelist" id="filelist" class="records-table sortheader" />
     </div>
 </div>
+
+<div id="filesearchmenu" class="popupmenu" style="z-index: 2000">
+    <ul class="toolbarmenu">
+        <li><label><input type="checkbox" name="all_folders" value="1" id="search_all_folders" /> <span><roundcube:label name="kolab_files.allfolders" /></span></label></li>
+    </ul>
+</div>
diff --git a/plugins/kolab_files/skins/larry/templates/files.html b/plugins/kolab_files/skins/larry/templates/files.html
index ac8779f..ba52300 100644
--- a/plugins/kolab_files/skins/larry/templates/files.html
+++ b/plugins/kolab_files/skins/larry/templates/files.html
@@ -22,10 +22,7 @@
 
 <div id="quicksearchbar" class="quicksearchbox">
     <roundcube:object name="file-search-form" id="quicksearchbox" />
-<!--
-        <roundcube:button name="searchmenulink" id="searchmenulink" class="iconbutton searchoptions" onclick="UI.show_popup('searchmenu');return false" title="searchmod" content=" " />
--->
-    <a id="searchmenulink" class="iconbutton searchoptions"> </a>
+    <roundcube:button name="filesearchmenulink" id="filesearchmenulink" class="iconbutton searchoptions" onclick="UI.show_popup('filesearchmenu');return false" title="searchmod" content=" " />
     <roundcube:button command="files-search-reset" id="searchreset" class="iconbutton reset" title="resetsearch" content=" " />
 </div>
 
@@ -63,47 +60,53 @@
 
 <div id="listoptions" class="propform popupdialog">
 <roundcube:if condition="!in_array('kolab_files_list_cols', (array)config:dont_override)" />
-	<fieldset class="floating">
-		<legend><roundcube:label name="listcolumns" /></legend>
-		<ul class="proplist">
-			<li><label class="disabled"><input type="checkbox" name="list_col[]" value="options" checked="checked" disabled="disabled" /> <span><roundcube:label name="options" /></span></label></li>
-			<li><label class="disabled"><input type="checkbox" name="list_col[]" value="name" checked="checked" disabled="disabled" /> <span><roundcube:label name="kolab_files.name" /></span></label></li>
-			<li><label><input type="checkbox" name="list_col[]" value="mtime" /> <span><roundcube:label name="kolab_files.mtime" /></span></label></li>
-			<li><label><input type="checkbox" name="list_col[]" value="size" /> <span><roundcube:label name="size" /></span></label></li>
-		</ul>
-	</fieldset>
-	<roundcube:endif />
-	<roundcube:if condition="!in_array('kolab_files_sort_col', (array)config:dont_override)" />
-	<fieldset class="floating">
-		<legend><roundcube:label name="listsorting" /></legend>
-		<ul class="proplist">
-			<li><label><input type="radio" name="sort_col" value="name" /> <span><roundcube:label name="kolab_files.name" /></span></label></li>
-			<li><label><input type="radio" name="sort_col" value="mtime" /> <span><roundcube:label name="kolab_files.mtime" /></span></label></li>
-			<li><label><input type="radio" name="sort_col" value="size" /> <span><roundcube:label name="size" /></span></label></li>
-		</ul>
-	</fieldset>
-	<roundcube:endif />
-	<roundcube:if condition="!in_array('kolab_files_sort_order', (array)config:dont_override)" />
-	<fieldset class="floating">
-		<legend><roundcube:label name="listorder" /></legend>
-		<ul class="proplist">
-			<li><label><input type="radio" name="sort_ord" value="ASC" /> <span><roundcube:label name="asc" /></span></label></li>
-			<li><label><input type="radio" name="sort_ord" value="DESC" /> <span><roundcube:label name="desc" /></span></label></li>
-		</ul>
-	</fieldset>
-	<roundcube:endif />
-	<br style="clear:both" />
-	<div class="formbuttons">
-		<roundcube:button command="menu-save" id="listmenusave" type="input" class="button mainaction" label="save" />
-		<roundcube:button command="menu-open" id="listmenucancel" type="input" class="button" label="cancel" />
-	</div>
+    <fieldset class="floating">
+        <legend><roundcube:label name="listcolumns" /></legend>
+        <ul class="proplist">
+            <li><label class="disabled"><input type="checkbox" name="list_col[]" value="options" checked="checked" disabled="disabled" /> <span><roundcube:label name="options" /></span></label></li>
+            <li><label class="disabled"><input type="checkbox" name="list_col[]" value="name" checked="checked" disabled="disabled" /> <span><roundcube:label name="kolab_files.name" /></span></label></li>
+            <li><label><input type="checkbox" name="list_col[]" value="mtime" /> <span><roundcube:label name="kolab_files.mtime" /></span></label></li>
+            <li><label><input type="checkbox" name="list_col[]" value="size" /> <span><roundcube:label name="size" /></span></label></li>
+        </ul>
+    </fieldset>
+    <roundcube:endif />
+    <roundcube:if condition="!in_array('kolab_files_sort_col', (array)config:dont_override)" />
+    <fieldset class="floating">
+        <legend><roundcube:label name="listsorting" /></legend>
+        <ul class="proplist">
+            <li><label><input type="radio" name="sort_col" value="name" /> <span><roundcube:label name="kolab_files.name" /></span></label></li>
+            <li><label><input type="radio" name="sort_col" value="mtime" /> <span><roundcube:label name="kolab_files.mtime" /></span></label></li>
+            <li><label><input type="radio" name="sort_col" value="size" /> <span><roundcube:label name="size" /></span></label></li>
+        </ul>
+    </fieldset>
+    <roundcube:endif />
+    <roundcube:if condition="!in_array('kolab_files_sort_order', (array)config:dont_override)" />
+    <fieldset class="floating">
+        <legend><roundcube:label name="listorder" /></legend>
+        <ul class="proplist">
+            <li><label><input type="radio" name="sort_ord" value="ASC" /> <span><roundcube:label name="asc" /></span></label></li>
+            <li><label><input type="radio" name="sort_ord" value="DESC" /> <span><roundcube:label name="desc" /></span></label></li>
+        </ul>
+    </fieldset>
+    <roundcube:endif />
+    <br style="clear:both" />
+    <div class="formbuttons">
+        <roundcube:button command="menu-save" id="listmenusave" type="input" class="button mainaction" label="save" />
+        <roundcube:button command="menu-open" id="listmenucancel" type="input" class="button" label="cancel" />
+    </div>
 </div>
 
 <div id="dragfilemenu" class="popupmenu">
-	<ul class="toolbarmenu">
-		<li><roundcube:button command="files-move" onclick="return kolab_files_drag_menu_action('files-move')" label="move" classAct="active" /></li>
-		<li><roundcube:button command="files-copy" onclick="return kolab_files_drag_menu_action('files-copy')" label="copy" classAct="active" /></li>
-	</ul>
+    <ul class="toolbarmenu">
+        <li><roundcube:button command="files-move" onclick="return kolab_files_drag_menu_action('files-move')" label="move" classAct="active" /></li>
+        <li><roundcube:button command="files-copy" onclick="return kolab_files_drag_menu_action('files-copy')" label="copy" classAct="active" /></li>
+    </ul>
+</div>
+
+<div id="filesearchmenu" class="popupmenu">
+    <ul class="toolbarmenu">
+        <li><label><input type="checkbox" name="all_folders" value="1" id="search_all_folders" /> <span><roundcube:label name="kolab_files.allfolders" /></span></label></li>
+    </ul>
 </div>
 
 <roundcube:include file="/includes/footer.html" />
diff --git a/plugins/kolab_files/skins/larry/ui.js b/plugins/kolab_files/skins/larry/ui.js
index 20ac934..fda15c8 100644
--- a/plugins/kolab_files/skins/larry/ui.js
+++ b/plugins/kolab_files/skins/larry/ui.js
@@ -7,11 +7,17 @@ function kolab_files_ui_init()
     rcmail.addEventListener('menu-open', kolab_files_show_listoptions);
     rcmail.addEventListener('menu-save', kolab_files_save_listoptions);
 
-    var dragmenu = $('#dragfilemenu');
-    if (dragmenu.length) {
+    var menu = $('#dragfilemenu');
+    if (menu.length) {
       rcmail.gui_object('file_dragmenu', 'dragfilemenu');
       UI.add_popup('dragfilemenu', {sticky: 1});
     }
+
+    menu = $('#filesearchmenu');
+    if (menu.length) {
+      rcmail.gui_object('file_searchmenu', 'filesearchmenu');
+      UI.add_popup('filesearchmenu', {sticky: 1});
+    }
   });
 
   kolab_files_upload_input('#filestoolbar a.upload');






More information about the commits mailing list