Merge branch 'master' of ssh://git.kolab.org/git/roundcubemail-plugins-kolab

This commit is contained in:
Thomas Bruederli 2013-03-20 09:14:39 +01:00
commit abceeb6684
8 changed files with 189 additions and 57 deletions

View file

@ -69,8 +69,8 @@ window.rcmail && rcmail.addEventListener('init', function() {
/*
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('dragend', function(e){ p.drag_end(e); });
*/
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); });
@ -356,6 +356,17 @@ kolab_files_list_select = function(list)
// rcmail.select_all_mode = false;
};
kolab_files_drag_end = function()
{
var folder = $('#files-folder-list li.droptarget').removeClass('droptarget');
if (folder.length) {
folder = folder.data('folder');
file_api.file_move(kolab_files_selected(), folder);
}
};
kolab_files_selected = function()
{
var files = [];
@ -369,6 +380,11 @@ kolab_files_selected = function()
return files;
};
/***********************************************************/
/********** Commands **********/
/***********************************************************/
rcube_webmail.prototype.files_sort = function(props)
{
var params = {},
@ -507,7 +523,7 @@ function kolab_files_ui()
$.each(this.env.folders, function(i, f) {
var row = $('<li class="mailbox"><span class="branch"></span></li>');
row.attr('id', f.id)
row.attr('id', f.id).data('folder', i)
.append($('<span class="name">').text(f.name))
.click(function() { file_api.folder_select(i); });
@ -516,6 +532,15 @@ function kolab_files_ui()
if (f.virtual)
row.addClass('virtual');
else
row.mouseenter(function() {
if (rcmail.file_list.drag_active)
$(this).addClass('droptarget');
})
.mouseleave(function() {
if (rcmail.file_list.drag_active)
$(this).removeClass('droptarget');
});
list.append(row);
@ -545,6 +570,46 @@ function kolab_files_ui()
this.file_list();
};
// 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');
};
// folder create response handler
this.folder_create_response = function(response)
{
if (!this.response(response))
return;
this.display_message('kolab_files.foldercreatenotice', 'confirmation');
// refresh folders list
this.folder_list();
};
// folder delete request
this.folder_delete = function(folder)
{
this.req = this.set_busy(true, 'kolab_files.folderdeleting');
this.get('folder_delete', {folder: folder}, 'folder_delete_response');
};
// folder delete response handler
this.folder_delete_response = function(response)
{
if (!this.response(response))
return;
this.env.folder = null;
rcmail.enable_command('files-folder-delete', 'files-folder-rename', false);
this.display_message('kolab_files.folderdeletenotice', 'confirmation');
// refresh folders list
this.folder_list();
};
this.file_list = function(params)
{
if (!this.env.folder || !rcmail.gui_objects.filelist)
@ -622,46 +687,6 @@ function kolab_files_ui()
$(row).addClass('selected');
};
// 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');
};
// folder create response handler
this.folder_create_response = function(response)
{
if (!this.response(response))
return;
this.display_message('kolab_files.foldercreatenotice', 'confirmation');
// refresh folders list
this.folder_list();
};
// folder delete request
this.folder_delete = function(folder)
{
this.req = this.set_busy(true, 'kolab_files.folderdeleting');
this.get('folder_delete', {folder: folder}, 'folder_delete_response');
};
// folder delete response handler
this.folder_delete_response = function(response)
{
if (!this.response(response))
return;
this.env.folder = null;
rcmail.enable_command('files-folder-delete', 'files-folder-rename', false);
this.display_message('kolab_files.folderdeletenotice', 'confirmation');
// refresh folders list
this.folder_list();
};
this.file_search = function(value)
{
if (value) {
@ -708,6 +733,31 @@ function kolab_files_ui()
this.file_list();
};
// file(s) move request
this.file_move = function(files, folder)
{
if (!files || !files.length || !folder)
return;
var list = {};
$.each(files, function(i, v) {
list[v] = folder + file_api.env.directory_separator + file_api.file_name(v);
});
this.req = this.set_busy(true, 'kolab_files.filemoving');
this.get('file_move', {file: list}, 'file_move_response');
};
// file(s) move response handler
this.file_move_response = function(response)
{
if (!this.response(response))
return;
this.display_message('kolab_files.filemovenotice', 'confirmation');
this.file_list();
};
// file upload request
this.file_upload = function(form)
{

View file

@ -462,7 +462,8 @@ class kolab_files_engine
$this->rc->output->add_label('deletefolderconfirm', 'kolab_files.folderdeleting',
'kolab_files.foldercreating', 'kolab_files.uploading', 'kolab_files.filedeleteconfirm',
'kolab_files.folderdeleteconfirm', 'kolab_files.filedeleting');
'kolab_files.folderdeleteconfirm', 'kolab_files.filedeleting', 'kolab_files.filedeletenotice',
'kolab_files.filemoving', 'kolab_files.filemovenotice');
$this->rc->output->set_pagetitle($this->plugin->gettext('files'));
$this->rc->output->send('kolab_files.files');

View file

@ -33,8 +33,10 @@ $labels['foldercreatenotice'] = 'Folder created successfully.';
$labels['saveallnotice'] = 'Successfully saved $n file(s).';
$labels['saveallerror'] = 'Saving $n file(s) failed.';
$labels['attacherror'] = 'Failed to attach file(s) from the cloud';
$labels['filemoving'] = 'Moving file(s)...';
$labels['filedeleting'] = 'Deleting file(s)...';
$labels['filedeleteconfirm'] = 'Are you sure you want to delete selected files?';
$labels['filedeletenotice'] = 'File(s) deleted successfully.';
$labels['filemovenotice'] = 'File(s) moved successfully.';
?>

View file

@ -63,6 +63,15 @@
overflow: auto;
}
#filelistbox {
bottom: 28px;
overflow: auto;
top: 0;
left: 0;
position: absolute;
width: 100%;
}
#files-folder-list ul li span.name {
background: url(../../../../skins/larry/images/listicons.png) 6px 3px no-repeat;
padding: 6px 8px 2px 32px;

View file

@ -40,8 +40,10 @@
</div>
</div>
<div id="filelistcontainer" class="boxlistcontent uibox">
<roundcube:object name="filelist" id="filelist" class="records-table sortheader" optionsmenuIcon="true" />
<div id="filelistcontainer" class="uibox">
<div id="filelistbox" class="boxlistcontent">
<roundcube:object name="filelist" id="filelist" class="records-table sortheader" optionsmenuIcon="true" />
</div>
<roundcube:object name="message" id="message" class="statusbar" />
</div>

View file

@ -103,12 +103,12 @@ function kolab_files_upload_input(button)
file.attr({name: 'file[]', type: 'file', multiple: 'multiple', size: 5})
.change(function() { rcmail.files_upload('#filesuploadform'); })
// opacity:0 does the trick, display/visibility doesn't work
.css({opacity: 0, cursor: 'pointer', position: 'absolute', top: '10000px', left: '10000px'});
.css({opacity: 0, cursor: 'pointer', outline: 'none', position: 'absolute', top: '10000px', left: '10000px'});
// In FF we need to move the browser file-input's button under the cursor
// 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)
file.css({marginLeft: '-75px'});
if (bw.mz || bw.ie)
file.css({marginLeft: '-80px'});
// Note: now, I observe problem with cursor style on FF < 4 only
link.css({overflow: 'hidden', cursor: 'pointer'})

View file

@ -192,7 +192,7 @@ class kolab_format_event extends kolab_format_xcal
}
// read exception event objects
if (($exceptions = $this->obj->exceptions()) && $exceptions->size()) {
if (($exceptions = $this->obj->exceptions()) && is_object($exceptions) && $exceptions->size()) {
for ($i=0; $i < $exceptions->size(); $i++) {
if (($exobj = $exceptions->get($i))) {
$exception = new kolab_format_event($exobj);

View file

@ -548,9 +548,9 @@ class kolab_storage_folder
// detect old Kolab 2.0 format
if (strpos($xmlhead, '<' . $xmltype) !== false && strpos($xmlhead, 'xmlns=') === false)
$format_version = 2.0;
$format_version = '2.0';
else
$format_version = 3.0; // assume 3.0
$format_version = '3.0'; // assume 3.0
}
// get Kolab format handler for the given type
@ -588,7 +588,6 @@ class kolab_storage_folder
return false;
}
/**
* Save an object in this folder.
*
@ -659,6 +658,11 @@ class kolab_storage_folder
}
}
// save recurrence exceptions as individual objects due to lack of support in Kolab v2 format
if (kolab_storage::$version == '2.0' && $object['recurrence']['EXCEPTIONS']) {
$this->save_recurrence_exceptions($object, $type);
}
// check IMAP BINARY extension support for 'file' objects
// allow configuration to workaround bug in Cyrus < 2.4.17
$rcmail = rcube::get_instance();
@ -666,6 +670,12 @@ class kolab_storage_folder
// generate and save object message
if ($raw_msg = $this->build_message($object, $type, $binary)) {
// resolve old msguid before saving
if ($uid && empty($object['_msguid']) && ($msguid = $this->cache->uid2msguid($uid))) {
$object['_msguid'] = $msguid;
$object['_mailbox'] = $this->name;
}
if (is_array($raw_msg)) {
$result = $this->imap->save_message($this->name, $raw_msg[0], $raw_msg[1], true, null, null, $binary);
@unlink($raw_msg[0]);
@ -679,10 +689,6 @@ class kolab_storage_folder
$this->imap->delete_message($object['_msguid'], $object['_mailbox']);
$this->cache->set($object['_msguid'], false, $object['_mailbox']);
}
else if ($result && $uid && ($msguid = $this->cache->uid2msguid($uid))) {
$this->imap->delete_message($msguid, $this->name);
$this->cache->set($object['_msguid'], false);
}
// update cache with new UID
if ($result) {
@ -694,6 +700,68 @@ class kolab_storage_folder
return $result;
}
/**
* Save recurrence exceptions as individual objects.
* The Kolab v2 format doesn't allow us to save fully embedded exception objects.
*
* @param array Hash array with event properties
* @param string Object type
*/
private function save_recurrence_exceptions(&$object, $type = null)
{
if ($object['recurrence']['EXCEPTIONS']) {
$exdates = array();
foreach ((array)$object['recurrence']['EXDATE'] as $exdate) {
$key = is_a($exdate, 'DateTime') ? $exdate->format('Y-m-d') : strval($exdate);
$exdates[$key] = 1;
}
// save every exception as individual object
foreach((array)$object['recurrence']['EXCEPTIONS'] as $exception) {
$exception['uid'] = self::recurrence_exception_uid($object['uid'], $exception['start']->format('Ymd'));
$exception['sequence'] = $object['sequence'] + 1;
if ($exception['thisandfuture']) {
$exception['recurrence'] = $object['recurrence'];
// adjust the recurrence duration of the exception
if ($object['recurrence']['COUNT']) {
$recurrence = new kolab_date_recurrence($object['_formatobj']);
if ($end = $recurrence->end()) {
unset($exception['recurrence']['COUNT']);
$exception['recurrence']['UNTIL'] = new DateTime('@'.$end);
}
}
// set UNTIL date if we have a thisandfuture exception
$untildate = clone $exception['start'];
$untildate->sub(new DateInterval('P1D'));
$object['recurrence']['UNTIL'] = $untildate;
unset($object['recurrence']['COUNT']);
}
else {
if (!$exdates[$exception['start']->format('Y-m-d')])
$object['recurrence']['EXDATE'][] = clone $exception['start'];
unset($exception['recurrence']);
}
unset($exception['recurrence']['EXCEPTIONS'], $exception['_formatobj'], $exception['_msguid']);
$this->save($exception, $type, $exception['uid']);
}
unset($object['recurrence']['EXCEPTIONS']);
}
}
/**
* Generate an object UID with the given recurrence-ID in a way that it is
* unique (the original UID is not a substring) but still recoverable.
*/
private static function recurrence_exception_uid($uid, $recurrence_id)
{
$offset = -2;
return substr($uid, 0, $offset) . '-' . $recurrence_id . '-' . substr($uid, $offset);
}
/**
* Delete the specified object from this folder.