Merge branch 'master' of ssh://git.kolabsys.com/git/roundcube
This commit is contained in:
commit
1f7d51be85
12 changed files with 886 additions and 67 deletions
|
@ -5,7 +5,7 @@
|
||||||
+ Edit: 3.16: Reminder set
|
+ Edit: 3.16: Reminder set
|
||||||
+ Edit: 3.17: Priority: High/Low
|
+ Edit: 3.17: Priority: High/Low
|
||||||
- Edit: 3.18: Recurrence (in line with Kontact)
|
- Edit: 3.18: Recurrence (in line with Kontact)
|
||||||
- Edit: 3.19: Attachment Upload
|
+ Edit: 3.19: Attachment Upload
|
||||||
- Edit: 3.20: Print
|
- Edit: 3.20: Print
|
||||||
- Add/Manage Attendees
|
- Add/Manage Attendees
|
||||||
- Edit: 3.21: Required / Optional / Resource specification
|
- Edit: 3.21: Required / Optional / Resource specification
|
||||||
|
|
|
@ -106,6 +106,8 @@ class calendar extends rcube_plugin
|
||||||
$this->register_action('load_events', array($this, 'load_events'));
|
$this->register_action('load_events', array($this, 'load_events'));
|
||||||
$this->register_action('search_events', array($this, 'search_events'));
|
$this->register_action('search_events', array($this, 'search_events'));
|
||||||
$this->register_action('export_events', array($this, 'export_events'));
|
$this->register_action('export_events', array($this, 'export_events'));
|
||||||
|
$this->register_action('upload', array($this, 'attachment_upload'));
|
||||||
|
$this->register_action('get-attachment', array($this, 'attachment_get'));
|
||||||
$this->register_action('randomdata', array($this, 'generate_randomdata'));
|
$this->register_action('randomdata', array($this, 'generate_randomdata'));
|
||||||
}
|
}
|
||||||
else if ($this->rc->task == 'settings') {
|
else if ($this->rc->task == 'settings') {
|
||||||
|
@ -167,10 +169,12 @@ class calendar extends rcube_plugin
|
||||||
$this->register_handler('plugin.alarm_select', array($this->ui, 'alarm_select'));
|
$this->register_handler('plugin.alarm_select', array($this->ui, 'alarm_select'));
|
||||||
$this->register_handler('plugin.snooze_select', array($this->ui, 'snooze_select'));
|
$this->register_handler('plugin.snooze_select', array($this->ui, 'snooze_select'));
|
||||||
$this->register_handler('plugin.recurrence_form', array($this->ui, 'recurrence_form'));
|
$this->register_handler('plugin.recurrence_form', array($this->ui, 'recurrence_form'));
|
||||||
|
$this->register_handler('plugin.attachments_form', array($this->ui, 'attachments_form'));
|
||||||
|
$this->register_handler('plugin.attachments_list', array($this->ui, 'attachments_list'));
|
||||||
$this->register_handler('plugin.edit_recurring_warning', array($this->ui, 'recurring_event_warning'));
|
$this->register_handler('plugin.edit_recurring_warning', array($this->ui, 'recurring_event_warning'));
|
||||||
$this->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template
|
$this->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template
|
||||||
|
|
||||||
$this->rc->output->add_label('low','normal','high');
|
$this->rc->output->add_label('low','normal','high','delete','cancel','uploading');
|
||||||
|
|
||||||
$this->rc->output->send("calendar.calendar");
|
$this->rc->output->send("calendar.calendar");
|
||||||
}
|
}
|
||||||
|
@ -431,11 +435,15 @@ class calendar extends rcube_plugin
|
||||||
case "new":
|
case "new":
|
||||||
// create UID for new event
|
// create UID for new event
|
||||||
$event['uid'] = $this->generate_uid();
|
$event['uid'] = $this->generate_uid();
|
||||||
$success = $this->driver->new_event($event);
|
$this->prepare_event($event);
|
||||||
|
if ($success = $this->driver->new_event($event))
|
||||||
|
$this->cleanup_event($event);
|
||||||
$reload = true;
|
$reload = true;
|
||||||
break;
|
break;
|
||||||
case "edit":
|
case "edit":
|
||||||
$success = $this->driver->edit_event($event);
|
$this->prepare_event($event);
|
||||||
|
if ($success = $this->driver->edit_event($event))
|
||||||
|
$this->cleanup_event($event);
|
||||||
$reload = true;
|
$reload = true;
|
||||||
break;
|
break;
|
||||||
case "resize":
|
case "resize":
|
||||||
|
@ -842,4 +850,250 @@ class calendar extends rcube_plugin
|
||||||
$this->rc->output->redirect('');
|
$this->rc->output->redirect('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for attachments upload
|
||||||
|
*/
|
||||||
|
public function attachment_upload()
|
||||||
|
{
|
||||||
|
$event = get_input_value('_id', RCUBE_INPUT_GPC);
|
||||||
|
$calendar = get_input_value('calendar', RCUBE_INPUT_GPC);
|
||||||
|
$uploadid = get_input_value('_uploadid', RCUBE_INPUT_GPC);
|
||||||
|
|
||||||
|
$eventid = $calendar.':'.$event;
|
||||||
|
|
||||||
|
if (!is_array($_SESSION['event_session']) || $_SESSION['event_session']['id'] != $eventid) {
|
||||||
|
$_SESSION['event_session'] = array();
|
||||||
|
$_SESSION['event_session']['id'] = $eventid;
|
||||||
|
$_SESSION['event_session']['attachments'] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear all stored output properties (like scripts and env vars)
|
||||||
|
$this->rc->output->reset();
|
||||||
|
|
||||||
|
if (is_array($_FILES['_attachments']['tmp_name'])) {
|
||||||
|
foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) {
|
||||||
|
// Process uploaded attachment if there is no error
|
||||||
|
$err = $_FILES['_attachments']['error'][$i];
|
||||||
|
|
||||||
|
if (!$err) {
|
||||||
|
$attachment = array(
|
||||||
|
'path' => $filepath,
|
||||||
|
'size' => $_FILES['_attachments']['size'][$i],
|
||||||
|
'name' => $_FILES['_attachments']['name'][$i],
|
||||||
|
'mimetype' => rc_mime_content_type($filepath, $_FILES['_attachments']['name'][$i], $_FILES['_attachments']['type'][$i]),
|
||||||
|
'group' => $eventid,
|
||||||
|
);
|
||||||
|
|
||||||
|
$attachment = $this->rc->plugins->exec_hook('attachment_upload', $attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$err && $attachment['status'] && !$attachment['abort']) {
|
||||||
|
$id = $attachment['id'];
|
||||||
|
|
||||||
|
// store new attachment in session
|
||||||
|
unset($attachment['status'], $attachment['abort']);
|
||||||
|
$_SESSION['event_session']['attachments'][$id] = $attachment;
|
||||||
|
|
||||||
|
if (($icon = $_SESSION['calendar_deleteicon']) && is_file($icon)) {
|
||||||
|
$button = html::img(array(
|
||||||
|
'src' => $icon,
|
||||||
|
'alt' => rcube_label('delete')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$button = Q(rcube_label('delete'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = html::a(array(
|
||||||
|
'href' => "#delete",
|
||||||
|
'onclick' => sprintf("return %s.remove_from_attachment_list('rcmfile%s')", JS_OBJECT_NAME, $id),
|
||||||
|
'title' => rcube_label('delete'),
|
||||||
|
), $button);
|
||||||
|
|
||||||
|
$content .= Q($attachment['name']);
|
||||||
|
|
||||||
|
$this->rc->output->command('add2attachment_list', "rcmfile$id", array(
|
||||||
|
'html' => $content,
|
||||||
|
'name' => $attachment['name'],
|
||||||
|
'mimetype' => $attachment['mimetype'],
|
||||||
|
'complete' => true), $uploadid);
|
||||||
|
}
|
||||||
|
else { // upload failed
|
||||||
|
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
|
||||||
|
$msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array(
|
||||||
|
'size' => show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
|
||||||
|
}
|
||||||
|
else if ($attachment['error']) {
|
||||||
|
$msg = $attachment['error'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$msg = rcube_label('fileuploaderror');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->rc->output->command('display_message', $msg, 'error');
|
||||||
|
$this->rc->output->command('remove_from_attachment_list', $uploadid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
// if filesize exceeds post_max_size then $_FILES array is empty,
|
||||||
|
// show filesizeerror instead of fileuploaderror
|
||||||
|
if ($maxsize = ini_get('post_max_size'))
|
||||||
|
$msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array(
|
||||||
|
'size' => show_bytes(parse_bytes($maxsize)))));
|
||||||
|
else
|
||||||
|
$msg = rcube_label('fileuploaderror');
|
||||||
|
|
||||||
|
$this->rc->output->command('display_message', $msg, 'error');
|
||||||
|
$this->rc->output->command('remove_from_attachment_list', $uploadid);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->rc->output->send('iframe');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for attachments download/displaying
|
||||||
|
*/
|
||||||
|
public function attachment_get()
|
||||||
|
{
|
||||||
|
$event = get_input_value('_event', RCUBE_INPUT_GPC);
|
||||||
|
$calendar = get_input_value('_cal', RCUBE_INPUT_GPC);
|
||||||
|
$id = get_input_value('_id', RCUBE_INPUT_GPC);
|
||||||
|
|
||||||
|
$event = array('id' => $event, 'calendar' => $calendar);
|
||||||
|
|
||||||
|
// show loading page
|
||||||
|
if (!empty($_GET['_preload'])) {
|
||||||
|
$url = str_replace('&_preload=1', '', $_SERVER['REQUEST_URI']);
|
||||||
|
$message = rcube_label('loadingdata');
|
||||||
|
|
||||||
|
header('Content-Type: text/html; charset=' . RCMAIL_CHARSET);
|
||||||
|
print "<html>\n<head>\n"
|
||||||
|
. '<meta http-equiv="refresh" content="0; url='.Q($url).'">' . "\n"
|
||||||
|
. '<meta http-equiv="content-type" content="text/html; charset='.RCMAIL_CHARSET.'">' . "\n"
|
||||||
|
. "</head>\n<body>\n$message\n</body>\n</html>";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_end_clean();
|
||||||
|
send_nocacheing_headers();
|
||||||
|
|
||||||
|
if (isset($_SESSION['calendar_attachment']))
|
||||||
|
$attachment = $_SESSION['calendar_attachment'];
|
||||||
|
else
|
||||||
|
$attachment = $_SESSION['calendar_attachment'] = $this->driver->get_attachment($id, $event);
|
||||||
|
|
||||||
|
// show part page
|
||||||
|
if (!empty($_GET['_frame'])) {
|
||||||
|
$this->rc->output->add_handlers(array('attachmentframe' => array($this, 'attachment_frame')));
|
||||||
|
$this->rc->output->send('calendar.attachment');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($_SESSION['calendar_attachment']);
|
||||||
|
|
||||||
|
if ($attachment) {
|
||||||
|
$mimetype = strtolower($attachment['mimetype']);
|
||||||
|
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
|
||||||
|
|
||||||
|
$browser = $this->rc->output->browser;
|
||||||
|
|
||||||
|
// send download headers
|
||||||
|
if ($_GET['_download']) {
|
||||||
|
header("Content-Type: application/octet-stream");
|
||||||
|
if ($browser->ie)
|
||||||
|
header("Content-Type: application/force-download");
|
||||||
|
}
|
||||||
|
else if ($ctype_primary == 'text') {
|
||||||
|
header("Content-Type: text/$ctype_secondary");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// $mimetype = rcmail_fix_mimetype($mimetype);
|
||||||
|
header("Content-Type: $mimetype");
|
||||||
|
header("Content-Transfer-Encoding: binary");
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = $this->driver->get_attachment_body($id, $event);
|
||||||
|
|
||||||
|
// display page, @TODO: support text/plain (and maybe some other text formats)
|
||||||
|
if ($mimetype == 'text/html' && empty($_GET['_download'])) {
|
||||||
|
$OUTPUT = new rcube_html_page();
|
||||||
|
// @TODO: use washtml on $body
|
||||||
|
$OUTPUT->write($body);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// don't kill the connection if download takes more than 30 sec.
|
||||||
|
@set_time_limit(0);
|
||||||
|
|
||||||
|
$filename = $attachment['name'];
|
||||||
|
$filename = preg_replace('[\r\n]', '', $filename);
|
||||||
|
|
||||||
|
if ($browser->ie && $browser->ver < 7)
|
||||||
|
$filename = rawurlencode(abbreviate_string($filename, 55));
|
||||||
|
else if ($browser->ie)
|
||||||
|
$filename = rawurlencode($filename);
|
||||||
|
else
|
||||||
|
$filename = addcslashes($filename, '"');
|
||||||
|
|
||||||
|
$disposition = !empty($_GET['_download']) ? 'attachment' : 'inline';
|
||||||
|
|
||||||
|
header("Content-Disposition: $disposition; filename=\"$filename\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we arrive here, the requested part was not found
|
||||||
|
header('HTTP/1.1 404 Not Found');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template object for attachment display frame
|
||||||
|
*/
|
||||||
|
public function attachment_frame($attrib)
|
||||||
|
{
|
||||||
|
$attachment = $_SESSION['calendar_attachment'];
|
||||||
|
|
||||||
|
$mimetype = strtolower($attachment['mimetype']);
|
||||||
|
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
|
||||||
|
|
||||||
|
$attrib['src'] = './?' . str_replace('_frame=', ($ctype_primary == 'text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING']);
|
||||||
|
|
||||||
|
return html::iframe($attrib);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares new/edited event properties before save
|
||||||
|
*/
|
||||||
|
private function prepare_event(&$event)
|
||||||
|
{
|
||||||
|
$eventid = $event['calendar'].':'.$event['id'];
|
||||||
|
|
||||||
|
$attachments = array();
|
||||||
|
if (is_array($_SESSION['event_session']) && $_SESSION['event_session']['id'] == $eventid) {
|
||||||
|
if (!empty($_SESSION['event_session']['attachments'])) {
|
||||||
|
foreach ($_SESSION['event_session']['attachments'] as $id => $attachment) {
|
||||||
|
if (is_array($event['attachments']) && in_array($id, $event['attachments'])) {
|
||||||
|
$attachments[$id] = $attachment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$event['attachments'] = $attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases some resources after successful event save
|
||||||
|
*/
|
||||||
|
private function cleanup_event(&$event)
|
||||||
|
{
|
||||||
|
// remove temp. attachment files
|
||||||
|
if (!empty($_SESSION['event_session']) && ($eventid = $_SESSION['event_session']['id'])) {
|
||||||
|
$this->rc->plugins->exec_hook('attachments_cleanup', array('group' => $eventid));
|
||||||
|
unset($_SESSION['event_session']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,78 @@ function rcube_calendar_ui(settings)
|
||||||
return fromto;
|
return fromto;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var load_attachment = function(event, att)
|
||||||
|
{
|
||||||
|
var qstring = '_id='+urlencode(att.id)+'&_event='+urlencode(event.id)+'&_cal='+urlencode(event.calendar);
|
||||||
|
|
||||||
|
// open attachment in frame if it's of a supported mimetype
|
||||||
|
if (id && att.mimetype && $.inArray(att.mimetype, rcmail.mimetypes)>=0) {
|
||||||
|
rcmail.attachment_win = window.open(rcmail.env.comm_path+'&_action=get-attachment&'+qstring+'&_frame=1', 'rcubeeventattachment');
|
||||||
|
if (rcmail.attachment_win) {
|
||||||
|
window.setTimeout(function() { rcmail.attachment_win.focus(); }, 10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rcmail.goto_url('get-attachment', qstring+'&_download=1', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// build event attachments list
|
||||||
|
var event_show_attachments = function(list, container, event, edit)
|
||||||
|
{
|
||||||
|
var i, id, len, img, content, li, elem,
|
||||||
|
ul = document.createElement('UL');
|
||||||
|
|
||||||
|
for (i=0, len=list.length; i<len; i++) {
|
||||||
|
li = document.createElement('LI');
|
||||||
|
elem = list[i];
|
||||||
|
|
||||||
|
if (edit) {
|
||||||
|
rcmail.env.attachments[elem.id] = elem;
|
||||||
|
// delete icon
|
||||||
|
content = document.createElement('A');
|
||||||
|
content.href = '#delete';
|
||||||
|
content.title = rcmail.gettext('delete');
|
||||||
|
$(content).click({id: elem.id}, function(e) { remove_attachment(this, e.data.id); return false; });
|
||||||
|
|
||||||
|
if (!rcmail.env.deleteicon)
|
||||||
|
content.innerHTML = rcmail.gettext('delete');
|
||||||
|
else {
|
||||||
|
img = document.createElement('IMG');
|
||||||
|
img.src = rcmail.env.deleteicon;
|
||||||
|
img.alt = rcmail.gettext('delete');
|
||||||
|
content.appendChild(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
li.appendChild(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// name/link
|
||||||
|
content = document.createElement('A');
|
||||||
|
content.innerHTML = list[i].name;
|
||||||
|
content.href = '#load';
|
||||||
|
$(content).click({event: event, att: elem}, function(e) {
|
||||||
|
load_attachment(e.data.event, e.data.att); return false; });
|
||||||
|
li.appendChild(content);
|
||||||
|
|
||||||
|
ul.appendChild(li);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edit && rcmail.gui_objects.attachmentlist) {
|
||||||
|
ul.id = rcmail.gui_objects.attachmentlist.id;
|
||||||
|
rcmail.gui_objects.attachmentlist = ul;
|
||||||
|
}
|
||||||
|
|
||||||
|
container.empty().append(ul);
|
||||||
|
};
|
||||||
|
|
||||||
|
var remove_attachment = function(elem, id)
|
||||||
|
{
|
||||||
|
$(elem.parentNode).hide();
|
||||||
|
rcmail.env.deleted_attachments.push(id);
|
||||||
|
delete rcmail.env.attachments[id];
|
||||||
|
};
|
||||||
|
|
||||||
// event details dialog (show only)
|
// event details dialog (show only)
|
||||||
var event_show_dialog = function(event)
|
var event_show_dialog = function(event)
|
||||||
{
|
{
|
||||||
|
@ -152,6 +224,17 @@ function rcube_calendar_ui(settings)
|
||||||
$('#event-sensitivity').show().children('.event-text').html(Q(sensitivitylabels[event.sensitivity]));
|
$('#event-sensitivity').show().children('.event-text').html(Q(sensitivitylabels[event.sensitivity]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create attachments list
|
||||||
|
if ($.isArray(event.attachments)) {
|
||||||
|
event_show_attachments(event.attachments, $('#event-attachments').children('.event-text'), event);
|
||||||
|
if (event.attachments.length > 0) {
|
||||||
|
$('#event-attachments').show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (calendar.attachments) {
|
||||||
|
// fetch attachments, some drivers doesn't set 'attachments' popr of the event
|
||||||
|
}
|
||||||
|
|
||||||
var buttons = {};
|
var buttons = {};
|
||||||
if (calendar.editable && event.editable !== false) {
|
if (calendar.editable && event.editable !== false) {
|
||||||
buttons[rcmail.gettext('edit', 'calendar')] = function() {
|
buttons[rcmail.gettext('edit', 'calendar')] = function() {
|
||||||
|
@ -307,6 +390,23 @@ function rcube_calendar_ui(settings)
|
||||||
else
|
else
|
||||||
$('#edit-recurring-warning').hide();
|
$('#edit-recurring-warning').hide();
|
||||||
|
|
||||||
|
// attachments
|
||||||
|
if (calendar.attachments) {
|
||||||
|
rcmail.enable_command('remove-attachment', !calendar.readonly);
|
||||||
|
rcmail.env.deleted_attachments = [];
|
||||||
|
// we're sharing some code for uploads handling with app.js
|
||||||
|
rcmail.env.attachments = [];
|
||||||
|
rcmail.env.compose_id = event.id; // for rcmail.async_upload_form()
|
||||||
|
|
||||||
|
if ($.isArray(event.attachments)) {
|
||||||
|
event_show_attachments(event.attachments, $('#edit-attachments'), event, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#edit-attachments > ul').empty();
|
||||||
|
// fetch attachments, some drivers doesn't set 'attachments' array for event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// buttons
|
// buttons
|
||||||
var buttons = {};
|
var buttons = {};
|
||||||
|
|
||||||
|
@ -334,7 +434,8 @@ function rcube_calendar_ui(settings)
|
||||||
priority: priority.val(),
|
priority: priority.val(),
|
||||||
sensitivity: sensitivity.val(),
|
sensitivity: sensitivity.val(),
|
||||||
recurrence: '',
|
recurrence: '',
|
||||||
alarms: ''
|
alarms: '',
|
||||||
|
deleted_attachments: rcmail.env.deleted_attachments
|
||||||
};
|
};
|
||||||
|
|
||||||
// serialize alarm settings
|
// serialize alarm settings
|
||||||
|
@ -348,6 +449,13 @@ function rcube_calendar_ui(settings)
|
||||||
data.alarms = offset[0] + val + offset[1] + ':' + alarm;
|
data.alarms = offset[0] + val + offset[1] + ':' + alarm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// uploaded attachments list
|
||||||
|
var attachments = [];
|
||||||
|
for (var i in rcmail.env.attachments)
|
||||||
|
if (i.match(/^rcmfile([0-9a-z]+)/))
|
||||||
|
attachments.push(RegExp.$1);
|
||||||
|
data.attachments = attachments;
|
||||||
|
|
||||||
// gather recurrence settings
|
// gather recurrence settings
|
||||||
var freq;
|
var freq;
|
||||||
if ((freq = recurrence.val()) != '') {
|
if ((freq = recurrence.val()) != '') {
|
||||||
|
|
|
@ -51,6 +51,13 @@
|
||||||
* 'sensitivity' => 0|1|2, // Event sensitivity (0=public, 1=private, 2=confidential)
|
* 'sensitivity' => 0|1|2, // Event sensitivity (0=public, 1=private, 2=confidential)
|
||||||
* 'alarms' => '-15M:DISPLAY', // Reminder settings inspired by valarm definition (e.g. display alert 15 minutes before event)
|
* 'alarms' => '-15M:DISPLAY', // Reminder settings inspired by valarm definition (e.g. display alert 15 minutes before event)
|
||||||
* 'savemode' => 'all|future|current|new', // How changes on recurring event should be handled
|
* 'savemode' => 'all|future|current|new', // How changes on recurring event should be handled
|
||||||
|
* 'attachments' => array( // List of attachments
|
||||||
|
* 'name' => 'File name',
|
||||||
|
* 'mimetype' => 'Content type',
|
||||||
|
* 'size' => 1..n, // in bytes
|
||||||
|
* 'id' => 'Attachment identifier'
|
||||||
|
* ),
|
||||||
|
* 'deleted_attachments' => array(), // array of attachment identifiers to delete when event is updated
|
||||||
* );
|
* );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -196,14 +203,49 @@ abstract class calendar_driver
|
||||||
abstract function dismiss_alarm($event_id, $snooze = 0);
|
abstract function dismiss_alarm($event_id, $snooze = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save an attachment related to the given event
|
* Get list of event's attachments.
|
||||||
|
* Drivers can return list of attachments as event property.
|
||||||
|
* If they will do not do this list_attachments() method will be used.
|
||||||
|
*
|
||||||
|
* @param array $event Hash array with event properties:
|
||||||
|
* id: Event identifier
|
||||||
|
* calendar: Calendar identifier
|
||||||
|
*
|
||||||
|
* @return array List of attachments, each as hash array:
|
||||||
|
* id: Attachment identifier
|
||||||
|
* name: Attachment name
|
||||||
|
* mimetype: MIME content type of the attachment
|
||||||
|
* size: Attachment size
|
||||||
*/
|
*/
|
||||||
public function add_attachment($attachment, $event_id) { }
|
public function list_attachments($event) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a specific attachment from the given event
|
* Get attachment properties
|
||||||
|
*
|
||||||
|
* @param string $id Attachment identifier
|
||||||
|
* @param array $event Hash array with event properties:
|
||||||
|
* id: Event identifier
|
||||||
|
* calendar: Calendar identifier
|
||||||
|
*
|
||||||
|
* @return array Hash array with attachment properties:
|
||||||
|
* id: Attachment identifier
|
||||||
|
* name: Attachment name
|
||||||
|
* mimetype: MIME content type of the attachment
|
||||||
|
* size: Attachment size
|
||||||
*/
|
*/
|
||||||
public function remove_attachment($attachment, $event_id) { }
|
public function get_attachment($id, $event) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get attachment body
|
||||||
|
*
|
||||||
|
* @param string $id Attachment identifier
|
||||||
|
* @param array $event Hash array with event properties:
|
||||||
|
* id: Event identifier
|
||||||
|
* calendar: Calendar identifier
|
||||||
|
*
|
||||||
|
* @return string Attachment body
|
||||||
|
*/
|
||||||
|
public function get_attachment_body($id, $event) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List availabale categories
|
* List availabale categories
|
||||||
|
|
|
@ -157,14 +157,7 @@ class database_driver extends calendar_driver
|
||||||
if (!$this->calendars[$prop['id']])
|
if (!$this->calendars[$prop['id']])
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// delete all events of this calendar
|
// events and attachments will be deleted by foreign key cascade
|
||||||
$query = $this->rc->db->query(
|
|
||||||
"DELETE FROM " . $this->db_events . "
|
|
||||||
WHERE calendar_id=?",
|
|
||||||
$prop['id']
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: also delete linked attachments
|
|
||||||
|
|
||||||
$query = $this->rc->db->query(
|
$query = $this->rc->db->query(
|
||||||
"DELETE FROM " . $this->db_calendars . "
|
"DELETE FROM " . $this->db_calendars . "
|
||||||
|
@ -214,10 +207,27 @@ class database_driver extends calendar_driver
|
||||||
$event['notifyat']
|
$event['notifyat']
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($success = $this->rc->db->insert_id($this->sequence_events))
|
$event_id = $this->rc->db->insert_id($this->sequence_events);
|
||||||
$this->_update_recurring($event);
|
|
||||||
|
|
||||||
return $success;
|
if ($event_id) {
|
||||||
|
// add attachments
|
||||||
|
if (!empty($event['attachments'])) {
|
||||||
|
foreach ($event['attachments'] as $attachment) {
|
||||||
|
$attachment = $this->rc->plugins->exec_hook('attachment_get', $attachment);
|
||||||
|
|
||||||
|
if (!$attachment['data']) {
|
||||||
|
$attachments['data'] = file_get_contents($attachment['path']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->add_attachment($attachment, $event_id);
|
||||||
|
unset($attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_update_recurring($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $event_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -405,6 +415,28 @@ class database_driver extends calendar_driver
|
||||||
);
|
);
|
||||||
|
|
||||||
$success = $this->rc->db->affected_rows($query);
|
$success = $this->rc->db->affected_rows($query);
|
||||||
|
|
||||||
|
// add attachments
|
||||||
|
if ($success && !empty($event['attachments'])) {
|
||||||
|
foreach ($event['attachments'] as $attachment) {
|
||||||
|
$attachment = $this->rc->plugins->exec_hook('attachment_get', $attachment);
|
||||||
|
|
||||||
|
if (!$attachment['data']) {
|
||||||
|
$attachments['data'] = file_get_contents($attachment['path']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->add_attachment($attachment, $event['id']);
|
||||||
|
unset($attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove attachments
|
||||||
|
if ($success && !empty($event['deleted_attachments'])) {
|
||||||
|
foreach ($event['deleted_attachments'] as $attachment) {
|
||||||
|
$this->remove_attachment($attachment, $event['id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($success && $update_recurring)
|
if ($success && $update_recurring)
|
||||||
$this->_update_recurring($event);
|
$this->_update_recurring($event);
|
||||||
|
|
||||||
|
@ -736,19 +768,110 @@ class database_driver extends calendar_driver
|
||||||
/**
|
/**
|
||||||
* Save an attachment related to the given event
|
* Save an attachment related to the given event
|
||||||
*/
|
*/
|
||||||
public function add_attachment($attachment, $event_id)
|
private function add_attachment($attachment, $event_id)
|
||||||
{
|
{
|
||||||
// TBD.
|
$query = $this->rc->db->query(sprintf(
|
||||||
return false;
|
"INSERT INTO " . $this->db_attachments .
|
||||||
|
" (event_id, filename, mimetype, size, data)" .
|
||||||
|
" VALUES (?, ?, ?, ?, ?)",
|
||||||
|
$event_id,
|
||||||
|
$attachment['name'],
|
||||||
|
$attachment['mimetype'],
|
||||||
|
strlen($attachment['data']),
|
||||||
|
base64_encode($attachment['data']),
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->rc->db->affected_rows($query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a specific attachment from the given event
|
* Remove a specific attachment from the given event
|
||||||
*/
|
*/
|
||||||
public function remove_attachment($attachment, $event_id)
|
private function remove_attachment($attachment_id, $event_id)
|
||||||
{
|
{
|
||||||
// TBD.
|
$query = $this->rc->db->query(
|
||||||
return false;
|
"DELETE FROM " . $this->db_attachments .
|
||||||
|
" WHERE attachment_id = ?" .
|
||||||
|
" AND event_id IN (SELECT event_id FROM " . $this->db_events .
|
||||||
|
" WHERE event_id = ?" .
|
||||||
|
" AND calendar_id IN (" . $this->calendar_ids . "))",
|
||||||
|
$attachment_id,
|
||||||
|
$event_id
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->rc->db->affected_rows($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List attachments of specified event
|
||||||
|
*/
|
||||||
|
public function list_attachments($event)
|
||||||
|
{
|
||||||
|
$attachments = array();
|
||||||
|
|
||||||
|
if (!empty($this->rc->user->ID)) {
|
||||||
|
$result = $this->rc->db->query(
|
||||||
|
"SELECT attachment_id AS id, filename AS name, mimetype, size " .
|
||||||
|
" FROM " . $this->db_attachments .
|
||||||
|
" WHERE user_id=?".
|
||||||
|
" AND event_id=?".
|
||||||
|
"ORDER BY filename",
|
||||||
|
$this->rc->user->ID,
|
||||||
|
$event['id']
|
||||||
|
);
|
||||||
|
|
||||||
|
while ($result && ($arr = $this->rc->db->fetch_assoc($result))) {
|
||||||
|
$attachments[] = $arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get attachment properties
|
||||||
|
*/
|
||||||
|
public function get_attachment($id, $event)
|
||||||
|
{
|
||||||
|
if (!empty($this->rc->user->ID)) {
|
||||||
|
$result = $this->rc->db->query(
|
||||||
|
"SELECT attachment_id AS id, filename AS name, mimetype, size " .
|
||||||
|
" FROM " . $this->db_attachments .
|
||||||
|
" WHERE attachment_id=?".
|
||||||
|
" AND event_id=?".
|
||||||
|
$id,
|
||||||
|
$event['id']
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($result && ($arr = $this->rc->db->fetch_assoc($result))) {
|
||||||
|
return $arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get attachment body
|
||||||
|
*/
|
||||||
|
public function get_attachment_body($id, $event)
|
||||||
|
{
|
||||||
|
if (!empty($this->rc->user->ID)) {
|
||||||
|
$result = $this->rc->db->query(
|
||||||
|
"SELECT data " .
|
||||||
|
" FROM " . $this->db_attachments .
|
||||||
|
" WHERE attachment_id=?".
|
||||||
|
" AND event_id=?".
|
||||||
|
$id,
|
||||||
|
$event['id']
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($result && ($arr = $this->rc->db->fetch_assoc($result))) {
|
||||||
|
return base64_decode($arr['data']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -23,6 +23,7 @@ class kolab_calendar
|
||||||
public $id;
|
public $id;
|
||||||
public $ready = false;
|
public $ready = false;
|
||||||
public $readonly = true;
|
public $readonly = true;
|
||||||
|
public $attachments = true;
|
||||||
|
|
||||||
private $cal;
|
private $cal;
|
||||||
private $storage;
|
private $storage;
|
||||||
|
@ -145,6 +146,15 @@ class kolab_calendar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the attachment body
|
||||||
|
*/
|
||||||
|
public function get_attachment_body($id)
|
||||||
|
{
|
||||||
|
return $this->storage->getAttachment($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for a single event object
|
* Getter for a single event object
|
||||||
*/
|
*/
|
||||||
|
@ -419,6 +429,20 @@ class kolab_calendar
|
||||||
$sensitivity_map = array_flip($this->sensitivity_map);
|
$sensitivity_map = array_flip($this->sensitivity_map);
|
||||||
$priority_map = array_flip($this->priority_map);
|
$priority_map = array_flip($this->priority_map);
|
||||||
|
|
||||||
|
// @TODO: Horde code assumes that there will be no more than
|
||||||
|
// one file with the same name, while this is not required by MIME format
|
||||||
|
// and not forced by the Calendar UI
|
||||||
|
if (!empty($rec['_attachments'])) {
|
||||||
|
foreach ($rec['_attachments'] as $name => $attachment) {
|
||||||
|
// @TODO: 'type' and 'key' are the only supported (no 'size')
|
||||||
|
$attachments[] = array(
|
||||||
|
'id' => $attachment['key'],
|
||||||
|
'mimetype' => $attachment['type'],
|
||||||
|
'name' => $name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'id' => $rec['uid'],
|
'id' => $rec['uid'],
|
||||||
'uid' => $rec['uid'],
|
'uid' => $rec['uid'],
|
||||||
|
@ -431,6 +455,7 @@ class kolab_calendar
|
||||||
'recurrence' => $rrule,
|
'recurrence' => $rrule,
|
||||||
'alarms' => $alarm_value . $alarm_unit,
|
'alarms' => $alarm_value . $alarm_unit,
|
||||||
'categories' => $rec['categories'],
|
'categories' => $rec['categories'],
|
||||||
|
'attachments' => $attachments,
|
||||||
'free_busy' => $rec['show-time-as'],
|
'free_busy' => $rec['show-time-as'],
|
||||||
'priority' => isset($priority_map[$rec['priority']]) ? $priority_map[$rec['priority']] : 1,
|
'priority' => isset($priority_map[$rec['priority']]) ? $priority_map[$rec['priority']] : 1,
|
||||||
'sensitivity' => $sensitivity_map[$rec['sensitivity']],
|
'sensitivity' => $sensitivity_map[$rec['sensitivity']],
|
||||||
|
@ -556,6 +581,17 @@ class kolab_calendar
|
||||||
$object['_is_all_day'] = 1;
|
$object['_is_all_day'] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in Horde attachments are indexed by name
|
||||||
|
$object['_attachments'] = array();
|
||||||
|
if (!empty($event['attachments'])) {
|
||||||
|
foreach ($event['attachments'] as $idx => $attachment) {
|
||||||
|
// Roundcube ID has nothing to Horde ID, remove it
|
||||||
|
unset($attachment['id']);
|
||||||
|
$object['_attachments'][$attachment['name']] = $attachment;
|
||||||
|
unset($event['attachments'][$idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class kolab_driver extends calendar_driver
|
||||||
// features this backend supports
|
// features this backend supports
|
||||||
public $alarms = true;
|
public $alarms = true;
|
||||||
public $attendees = false;
|
public $attendees = false;
|
||||||
public $attachments = false;
|
public $attachments = true;
|
||||||
public $categoriesimmutable = true;
|
public $categoriesimmutable = true;
|
||||||
|
|
||||||
private $rc;
|
private $rc;
|
||||||
|
@ -229,8 +229,20 @@ class kolab_driver extends calendar_driver
|
||||||
public function new_event($event)
|
public function new_event($event)
|
||||||
{
|
{
|
||||||
$cid = $event['calendar'] ? $event['calendar'] : reset(array_keys($this->calendars));
|
$cid = $event['calendar'] ? $event['calendar'] : reset(array_keys($this->calendars));
|
||||||
if ($storage = $this->calendars[$cid])
|
if ($storage = $this->calendars[$cid]) {
|
||||||
|
// handle attachments to add
|
||||||
|
if (!empty($event['attachments'])) {
|
||||||
|
foreach ($event['attachments'] as $idx => $attachment) {
|
||||||
|
// we'll read file contacts into memory, Horde/Kolab classes does the same
|
||||||
|
// So we cannot save memory, rcube_imap class can do this better
|
||||||
|
$attachment = $this->cal->rc->plugins->exec_hook('attachment_get', $attachment);
|
||||||
|
|
||||||
|
$event['attachments'][$idx]['content'] = $attachment['data'] ? $attachment['data'] : file_get_contents($attachment['path']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $storage->insert_event($event);
|
return $storage->insert_event($event);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -330,8 +342,39 @@ class kolab_driver extends calendar_driver
|
||||||
|
|
||||||
$success = false;
|
$success = false;
|
||||||
$savemode = 'all';
|
$savemode = 'all';
|
||||||
|
$attachments = array();
|
||||||
$old = $master = $storage->get_event($event['id']);
|
$old = $master = $storage->get_event($event['id']);
|
||||||
|
|
||||||
|
// delete existing attachment(s)
|
||||||
|
if (!empty($event['deleted_attachments'])) {
|
||||||
|
foreach ($event['deleted_attachments'] as $attachment) {
|
||||||
|
if (!empty($old['attachments'])) {
|
||||||
|
foreach ($old['attachments'] as $idx => $att) {
|
||||||
|
if ($att['id'] == $attachment) {
|
||||||
|
unset($old['attachments'][$idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle attachments to add
|
||||||
|
if (!empty($event['attachments'])) {
|
||||||
|
foreach ($event['attachments'] as $attachment) {
|
||||||
|
// we'll read file contacts into memory, Horde/Kolab classes does the same
|
||||||
|
// So we cannot save memory, rcube_imap class can do this better
|
||||||
|
$attachment = $this->cal->rc->plugins->exec_hook('attachment_get', $attachment);
|
||||||
|
|
||||||
|
$attachments[] = array(
|
||||||
|
'name' => $attachment['name'],
|
||||||
|
'type' => $attachment['mimetype'],
|
||||||
|
'content' => $attachment['data'] ? $attachment['data'] : file_get_contents($attachment['path']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$event['attachments'] = array_merge($old['attachments'], $attachments);
|
||||||
|
|
||||||
// modify a recurring event, check submitted savemode to do the right things
|
// modify a recurring event, check submitted savemode to do the right things
|
||||||
if ($old['recurrence'] || $old['recurrence_id']) {
|
if ($old['recurrence'] || $old['recurrence_id']) {
|
||||||
$master = $old['recurrence_id'] ? $storage->get_event($old['recurrence_id']) : $old;
|
$master = $old['recurrence_id'] ? $storage->get_event($old['recurrence_id']) : $old;
|
||||||
|
@ -527,21 +570,49 @@ class kolab_driver extends calendar_driver
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save an attachment related to the given event
|
* List attachments from the given event
|
||||||
*/
|
*/
|
||||||
public function add_attachment($attachment, $event_id)
|
public function list_attachments($event)
|
||||||
{
|
{
|
||||||
|
if (!($storage = $this->calendars[$event['calendar']]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$event = $storage->get_event($event['id']);
|
||||||
|
|
||||||
|
return $event['attachments'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a specific attachment from the given event
|
* Get attachment properties
|
||||||
*/
|
*/
|
||||||
public function remove_attachment($attachment, $event_id)
|
public function get_attachment($id, $event)
|
||||||
{
|
{
|
||||||
|
if (!($storage = $this->calendars[$event['calendar']]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$event = $storage->get_event($event['id']);
|
||||||
|
|
||||||
|
if ($event && !empty($event['attachments'])) {
|
||||||
|
foreach ($event['attachments'] as $att) {
|
||||||
|
if ($att['id'] == $id) {
|
||||||
|
return $att;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get attachment body
|
||||||
|
*/
|
||||||
|
public function get_attachment_body($id, $event)
|
||||||
|
{
|
||||||
|
if (!($storage = $this->calendars[$event['calendar']]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return $storage->get_attachment_body($id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List availabale categories
|
* List availabale categories
|
||||||
|
|
|
@ -461,4 +461,60 @@ class calendar_ui
|
||||||
|
|
||||||
return $select_prefix->show() . ' ' . $select_wday->show();
|
return $select_prefix->show() . ' ' . $select_wday->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the form for event attachments upload
|
||||||
|
*/
|
||||||
|
function attachments_form($attrib = array())
|
||||||
|
{
|
||||||
|
// add ID if not given
|
||||||
|
if (!$attrib['id'])
|
||||||
|
$attrib['id'] = 'rcmUploadForm';
|
||||||
|
|
||||||
|
// find max filesize value
|
||||||
|
$max_filesize = parse_bytes(ini_get('upload_max_filesize'));
|
||||||
|
$max_postsize = parse_bytes(ini_get('post_max_size'));
|
||||||
|
if ($max_postsize && $max_postsize < $max_filesize)
|
||||||
|
$max_filesize = $max_postsize;
|
||||||
|
|
||||||
|
$this->rc->output->set_env('max_filesize', $max_filesize);
|
||||||
|
|
||||||
|
$max_filesize = show_bytes($max_filesize);
|
||||||
|
|
||||||
|
$button = new html_inputfield(array('type' => 'button'));
|
||||||
|
$input = new html_inputfield(array(
|
||||||
|
'type' => 'file', 'name' => '_attachments[]',
|
||||||
|
'multiple' => 'multiple', 'size' => $attrib['attachmentfieldsize']));
|
||||||
|
|
||||||
|
return html::div($attrib,
|
||||||
|
html::div(null, $input->show()) .
|
||||||
|
html::div('buttons', $button->show(rcube_label('upload'), array('class' => 'button mainaction',
|
||||||
|
'onclick' => JS_OBJECT_NAME . ".upload_file(this.form)"))) .
|
||||||
|
html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate HTML element for attachments list
|
||||||
|
*/
|
||||||
|
function attachments_list($attrib = array())
|
||||||
|
{
|
||||||
|
if (!$attrib['id'])
|
||||||
|
$attrib['id'] = 'rcmAttachmentList';
|
||||||
|
|
||||||
|
$skin_path = $this->rc->config->get('skin_path');
|
||||||
|
if ($attrib['deleteicon']) {
|
||||||
|
$_SESSION['calendar_deleteicon'] = $skin_path . $attrib['deleteicon'];
|
||||||
|
$this->rc->output->set_env('deleteicon', $skin_path . $attrib['deleteicon']);
|
||||||
|
}
|
||||||
|
if ($attrib['cancelicon'])
|
||||||
|
$this->rc->output->set_env('cancelicon', $skin_path . $attrib['cancelicon']);
|
||||||
|
if ($attrib['loadingicon'])
|
||||||
|
$this->rc->output->set_env('loadingicon', $skin_path . $attrib['loadingicon']);
|
||||||
|
|
||||||
|
$this->rc->output->add_gui_object('attachmentlist', $attrib['id']);
|
||||||
|
|
||||||
|
return html::tag('ul', $attrib, '', html::$common_attrib);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -247,6 +247,71 @@ a.miniColors-trigger {
|
||||||
margin-top: -3px;
|
margin-top: -3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#attachmentcontainer
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
top: 80px;
|
||||||
|
left: 20px;
|
||||||
|
right: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachmentframe
|
||||||
|
{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 1px solid #999999;
|
||||||
|
background-color: #F9F9F9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachments-list ul
|
||||||
|
{
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
list-style-image: none;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachments-list ul li
|
||||||
|
{
|
||||||
|
height: 18px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding-left: 2px;
|
||||||
|
padding-top: 2px;
|
||||||
|
padding-right: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-o-text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachments-list ul li img
|
||||||
|
{
|
||||||
|
padding-right: 2px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachments-list ul li a
|
||||||
|
{
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachments-list ul li a:hover
|
||||||
|
{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#eventshow .attachments-list ul
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#eventshow .attachments-list ul li
|
||||||
|
{
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* jQuery UI overrides */
|
/* jQuery UI overrides */
|
||||||
|
|
||||||
#eventshow h1 {
|
#eventshow h1 {
|
||||||
|
|
52
plugins/calendar/skins/default/templates/attachment.html
Normal file
52
plugins/calendar/skins/default/templates/attachment.html
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title><roundcube:object name="pagetitle" /></title>
|
||||||
|
<roundcube:include file="/includes/links.html" />
|
||||||
|
</head>
|
||||||
|
<body class="extwin">
|
||||||
|
|
||||||
|
<roundcube:include file="/includes/header.html" />
|
||||||
|
|
||||||
|
<div id="partheader">
|
||||||
|
<!--
|
||||||
|
<roundcube:object name="attachmentControls" cellpadding="2" cellspacing="0" />
|
||||||
|
-->
|
||||||
|
<div style="position:absolute; top:2px; right:0; width:12em; text-align:right">
|
||||||
|
[<a href="#close" class="closelink" onclick="self.close()"><roundcube:label name="close" /></a>]
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="attachmentcontainer">
|
||||||
|
<roundcube:object name="attachmentFrame" id="attachmentframe" width="100%" height="100%" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title><roundcube:object name="pagetitle" /></title>
|
||||||
|
<roundcube:include file="/includes/links.html" />
|
||||||
|
</head>
|
||||||
|
<body class="extwin">
|
||||||
|
|
||||||
|
<roundcube:include file="/includes/header.html" />
|
||||||
|
|
||||||
|
<div id="partheader">
|
||||||
|
<!--
|
||||||
|
<roundcube:object name="attachmentControls" cellpadding="2" cellspacing="0" />
|
||||||
|
-->
|
||||||
|
<div style="position:absolute; top:2px; right:0; width:12em; text-align:right">
|
||||||
|
[<a href="#close" class="closelink" onclick="self.close()"><roundcube:label name="close" /></a>]
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="attachmentcontainer">
|
||||||
|
<roundcube:object name="attachmentFrame" id="attachmentframe" width="100%" height="100%" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -7,6 +7,7 @@
|
||||||
<script type="text/javascript" src="/functions.js"></script>
|
<script type="text/javascript" src="/functions.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="calendarmain">
|
<body class="calendarmain">
|
||||||
|
|
||||||
<roundcube:include file="/includes/taskbar.html" />
|
<roundcube:include file="/includes/taskbar.html" />
|
||||||
<roundcube:include file="/includes/header.html" />
|
<roundcube:include file="/includes/header.html" />
|
||||||
|
|
||||||
|
@ -75,10 +76,14 @@
|
||||||
<label><roundcube:label name="calendar.sensitivity" /></label>
|
<label><roundcube:label name="calendar.sensitivity" /></label>
|
||||||
<span class="event-text"></span>
|
<span class="event-text"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="event-section" id="event-attachments">
|
||||||
|
<label><roundcube:label name="attachments" /></label>
|
||||||
|
<span class="event-text attachments-list"></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="eventedit">
|
<div id="eventedit">
|
||||||
<form id="eventtabs" action="#">
|
<form id="eventtabs" action="#" method="post">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#event-tab-1"><roundcube:label name="calendar.tabsummary" /></a></li>
|
<li><a href="#event-tab-1"><roundcube:label name="calendar.tabsummary" /></a></li>
|
||||||
<li id="edit-tab-recurrence"><a href="#event-tab-2"><roundcube:label name="calendar.tabrecurrence" /></a></li>
|
<li id="edit-tab-recurrence"><a href="#event-tab-2"><roundcube:label name="calendar.tabrecurrence" /></a></li>
|
||||||
|
@ -163,9 +168,14 @@
|
||||||
<div id="event-tab-3">
|
<div id="event-tab-3">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- attachments list -->
|
<!-- attachments list (with upload form) -->
|
||||||
<div id="event-tab-4">
|
<div id="event-tab-4">
|
||||||
|
<div class="border-after" id="edit-attachments-form">
|
||||||
|
<roundcube:object name="plugin.attachments_form" id="calendar-attachment-form" attachmentFieldSize="30" />
|
||||||
|
</div>
|
||||||
|
<span id="edit-attachments" class="attachments-list">
|
||||||
|
<roundcube:object name="plugin.attachments_list" id="attachmentlist" deleteIcon="/images/icons/delete.png" cancelIcon="/images/icons/delete.png" loadingIcon="/images/display/loading_blue.gif" />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
class kolab_folders extends rcube_plugin
|
class kolab_folders extends rcube_plugin
|
||||||
{
|
{
|
||||||
|
public $task = '?(?!login).*';
|
||||||
|
|
||||||
public $types = array('mail', 'event', 'journal', 'task', 'note', 'contact');
|
public $types = array('mail', 'event', 'journal', 'task', 'note', 'contact');
|
||||||
public $mail_types = array('inbox', 'drafts', 'sentitems', 'outbox', 'wastebasket', 'junkemail');
|
public $mail_types = array('inbox', 'drafts', 'sentitems', 'outbox', 'wastebasket', 'junkemail');
|
||||||
private $rc;
|
private $rc;
|
||||||
|
|
Loading…
Add table
Reference in a new issue