Merge branch 'master' of ssh://git.kolab.org/git/roundcubemail-plugins-kolab
This commit is contained in:
commit
abceeb6684
8 changed files with 189 additions and 57 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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.';
|
||||
|
||||
?>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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'})
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Reference in a new issue