- Store relation to message when creating event from email (#4161)

- Move common functions to libcalendaring
- Assign dialog button classes directly
This commit is contained in:
Thomas Bruederli 2015-01-14 09:27:48 +01:00
parent 0a51ccd5a4
commit b02e2c3b8f
11 changed files with 270 additions and 66 deletions

View file

@ -1636,6 +1636,15 @@ class calendar extends rcube_plugin
$event['attachments'][$k]['classname'] = rcube_utils::file2class($attachment['mimetype'], $attachment['name']);
}
// convert link URIs references into structs
if (array_key_exists('links', $event)) {
foreach ((array)$event['links'] as $i => $link) {
if (strpos($link, 'imap://') === 0 && ($msgref = $this->driver->get_message_reference($link))) {
$event['links'][$i] = $msgref;
}
}
}
// check for organizer in attendees list
$organizer = null;
foreach ((array)$event['attendees'] as $i => $attendee) {
@ -1824,6 +1833,13 @@ class calendar extends rcube_plugin
$event['attachments'] = $attachments;
// convert link references into simple URIs
if (array_key_exists('links', $event)) {
$event['links'] = array_map(function($link) {
return is_array($link) ? $link['uri'] : strval($link);
}, (array)$event['links']);
}
// check for organizer in attendees
if ($action == 'new' || $action == 'edit') {
if (!$event['attendees'])
@ -2933,8 +2949,14 @@ class calendar extends rcube_plugin
$event['title'] = trim($message->subject);
$event['description'] = trim($message->first_text_part());
$this->load_driver();
// add a reference to the email message
if ($msgref = $this->driver->get_message_reference($message->headers, $mbox)) {
$event['links'] = array($msgref);
}
// copy mail attachments to event
if ($message->attachments) {
else if ($message->attachments) {
$eventid = 'cal:';
if (!is_array($_SESSION[self::SESSION_KEY]) || $_SESSION[self::SESSION_KEY]['id'] != $eventid) {
$_SESSION[self::SESSION_KEY] = array();

View file

@ -187,6 +187,7 @@ function rcube_calendar_ui(settings)
var fromunixtime = this.fromunixtime;
var parseISO8601 = this.parseISO8601;
var date2servertime = this.date2ISO8601;
var render_message_links = this.render_message_links;
/*** private methods ***/
@ -471,6 +472,13 @@ function rcube_calendar_ui(settings)
// fetch attachments, some drivers doesn't set 'attachments' prop of the event?
}
// build attachments list
$('#event-links').hide();
if ($.isArray(event.links) && event.links.length) {
render_message_links(event.links || [], $('#event-links').children('.event-text'), false, 'calendar');
$('#event-links').show();
}
// list event attendees
if (calendar.attendees && event.attendees) {
// sort resources to the end
@ -546,20 +554,30 @@ function rcube_calendar_ui(settings)
$('#event-rsvp .itip-reply-comment textarea').hide().val('');
}
var buttons = {};
var buttons = [];
if (!temp && calendar.editable && event.editable !== false) {
buttons[rcmail.gettext('edit', 'calendar')] = function() {
event_edit_dialog('edit', event);
};
buttons[rcmail.gettext('delete', 'calendar')] = function() {
me.delete_event(event);
$dialog.dialog('close');
};
buttons.push({
text: rcmail.gettext('edit', 'calendar'),
click: function() {
event_edit_dialog('edit', event);
}
});
buttons.push({
text: rcmail.gettext('delete', 'calendar'),
'class': 'delete',
click: function() {
me.delete_event(event);
$dialog.dialog('close');
}
});
}
else {
buttons[rcmail.gettext('close', 'calendar')] = function(){
$dialog.dialog('close');
};
buttons.push({
text: rcmail.gettext('close', 'calendar'),
click: function(){
$dialog.dialog('close');
}
});
}
// open jquery UI dialog
@ -712,6 +730,14 @@ function rcube_calendar_ui(settings)
$('<option>').attr('value', event.categories).text(event.categories).appendTo(categories).prop('selected', true);
}
if ($.isArray(event.links) && event.links.length) {
render_message_links(event.links, $('#edit-event-links .event-text'), true, 'calendar');
$('#edit-event-links').show();
}
else {
$('#edit-event-links').hide();
}
// show warning if editing a recurring event
if (event.id && event.recurrence) {
var sel = event.thisandfuture ? 'future' : (event.isexception ? 'current' : 'all');
@ -778,10 +804,13 @@ function rcube_calendar_ui(settings)
};
// init dialog buttons
var buttons = {};
var buttons = [];
// save action
buttons[rcmail.gettext('save', 'calendar')] = function() {
buttons.push({
text: rcmail.gettext('save', 'calendar'),
'class': 'mainaction',
click: function() {
var start = parse_datetime(allday.checked ? '12:00' : starttime.val(), startdate.val());
var end = parse_datetime(allday.checked ? '13:00' : endtime.val(), enddate.val());
@ -809,6 +838,7 @@ function rcube_calendar_ui(settings)
recurrence: me.serialize_recurrence(endtime.val()),
valarms: me.serialize_alarms('#edit-alarms'),
attendees: event_attendees,
links: me.selected_event.links,
deleted_attachments: rcmail.env.deleted_attachments,
attachments: []
};
@ -865,18 +895,26 @@ function rcube_calendar_ui(settings)
update_event(action, data);
$dialog.dialog("close");
};
} // end click:
});
if (event.id) {
buttons[rcmail.gettext('delete', 'calendar')] = function() {
me.delete_event(event);
$dialog.dialog('close');
};
buttons.push({
text: rcmail.gettext('delete', 'calendar'),
'class': 'delete',
click: function() {
me.delete_event(event);
$dialog.dialog('close');
}
});
}
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
$dialog.dialog("close");
};
buttons.push({
text: rcmail.gettext('cancel', 'calendar'),
click: function() {
$dialog.dialog("close");
}
});
// show/hide tabs according to calendar's feature support
$('#edit-tab-attendees')[(calendar.attendees?'show':'hide')]();
@ -900,7 +938,6 @@ function rcube_calendar_ui(settings)
title: rcmail.gettext((action == 'edit' ? 'edit_event' : 'new_event'), 'calendar'),
open: function() {
editform.attr('aria-hidden', 'false');
$dialog.parent().find('.ui-dialog-buttonset .ui-button').first().addClass('mainaction');
},
close: function() {
editform.hide().attr('aria-hidden', 'true').appendTo(document.body);
@ -2415,6 +2452,17 @@ function rcube_calendar_ui(settings)
$.each(listitems, function(idx, item) { mylist.append(item); });
}
// remove the link reference matching the given uri
function remove_link(elem)
{
var $elem = $(elem), uri = $elem.attr('data-uri');
me.selected_event.links = $.grep(me.selected_event.links, function(link) { return link.uri != uri; });
// remove UI list item
$elem.hide().closest('li').addClass('deleted');
}
// post the given event data to server
var update_event = function(action, data, add)
{
@ -4054,6 +4102,20 @@ function rcube_calendar_ui(settings)
return false;
})
// register click handler for message links
$('#edit-event-links, #event-links').on('click', 'li a.messagelink', function(e) {
rcmail.open_window(this.href);
if (!rcube_event.is_keyboard(e) && this.blur)
this.blur();
return false;
});
// register click handler for message delete buttons
$('#edit-event-links').on('click', 'li a.delete', function(e) {
remove_link(e.target);
return false;
});
$('#agenda-listrange').change(function(e){
settings['agenda_range'] = parseInt($(this).val());
fc.fullCalendar('option', 'listRange', settings['agenda_range']).fullCalendar('render');

View file

@ -377,6 +377,21 @@ abstract class calendar_driver
*/
public function get_attachment_body($id, $event) { }
/**
* Build a struct representing the given message reference
*
* @param object|string $uri_or_headers rcube_message_header instance holding the message headers
* or an URI from a stored link referencing a mail message.
* @param string $folder IMAP folder the message resides in
*
* @return array An struct referencing the given IMAP message
*/
public function get_message_reference($uri_or_headers, $folder = null)
{
// to be implemented by the derived classes
return false;
}
/**
* List availabale categories
* The default implementation reads them from config/user prefs

View file

@ -391,6 +391,10 @@ class kolab_calendar extends kolab_storage_folder_api
if (!is_array($event))
return false;
// email links are stored separately
$links = $event['links'];
unset($event['links']);
//generate new event from RC input
$object = $this->_from_rcube_event($event);
$saved = $this->storage->save($object, 'event');
@ -404,6 +408,9 @@ class kolab_calendar extends kolab_storage_folder_api
$saved = false;
}
else {
// save links in configuration.relation object
$this->save_links($event['uid'], $links);
$event['id'] = $event['uid'];
$this->events = array($event['uid'] => $this->_to_rcube_event($object));
}
@ -425,6 +432,10 @@ class kolab_calendar extends kolab_storage_folder_api
if (!$old || PEAR::isError($old))
return false;
// email links are stored separately
$links = $event['links'];
unset($event['links']);
$object = $this->_from_rcube_event($event, $old);
$saved = $this->storage->save($object, 'event', $event['id']);
@ -436,6 +447,9 @@ class kolab_calendar extends kolab_storage_folder_api
true, false);
}
else {
// save links in configuration.relation object
$this->save_links($event['uid'], $links);
$updated = true;
$this->events[$event['id']] = $this->_to_rcube_event($object);
@ -491,6 +505,29 @@ class kolab_calendar extends kolab_storage_folder_api
return false;
}
/**
* Find messages linked with an event
*/
protected function get_links($uid)
{
$storage = kolab_storage_config::get_instance();
return $storage->get_object_links($uid);
}
/**
*
*/
protected function save_links($uid, $links)
{
// make sure we have a valid array
if (empty($links)) {
$links = array();
}
$storage = kolab_storage_config::get_instance();
$remove = array_diff($storage->get_object_links($uid), $links);
return $storage->save_object_links($uid, $links, $remove);
}
/**
* Create instances of a recurring event
@ -635,6 +672,7 @@ class kolab_calendar extends kolab_storage_folder_api
{
$record['id'] = $record['uid'];
$record['calendar'] = $this->id;
$record['links'] = $this->get_links($record['uid']);
return kolab_driver::to_rcube_event($record);
}

View file

@ -1215,6 +1215,24 @@ class kolab_driver extends calendar_driver
return $cal->storage->get_attachment($event['id'], $id);
}
/**
* Build a struct representing the given message reference
*
* @see calendar_driver::get_message_reference()
*/
public function get_message_reference($uri_or_headers, $folder = null)
{
if (is_object($uri_or_headers)) {
$uri_or_headers = kolab_storage_config::get_message_uri($uri_or_headers, $folder);
}
if (is_string($uri_or_headers)) {
return kolab_storage_config::get_message_reference($uri_or_headers, 'event');
}
return false;
}
/**
* List availabale categories
* The default implementation reads them from config/user prefs
@ -1403,7 +1421,6 @@ class kolab_driver extends calendar_driver
return $record;
}
/**
* Provide a list of revisions for the given event
*

View file

@ -87,6 +87,7 @@ $labels['sensitivity'] = 'Privacy';
$labels['public'] = 'public';
$labels['private'] = 'private';
$labels['confidential'] = 'confidential';
$labels['links'] = 'Reference';
$labels['alarms'] = 'Reminder';
$labels['comment'] = 'Comment';
$labels['created'] = 'Created';
@ -95,6 +96,7 @@ $labels['unknown'] = 'Unknown';
$labels['eventoptions'] = 'Options';
$labels['generated'] = 'generated at';
$labels['eventhistory'] = 'History';
$labels['removelink'] = 'Remove email reference';
$labels['printdescriptions'] = 'Print descriptions';
$labels['parentcalendar'] = 'Insert inside';
$labels['searchearlierdates'] = '« Search for earlier events';

View file

@ -958,6 +958,37 @@ div.form-section,
text-overflow: ellipsis;
}
#event-links .attachmentslist {
display: inline-block;
}
#event-links label,
#edit-event-links label {
float: left;
margin-top: 0.3em;
padding-right: 0.75em;
}
#edit-event-links .event-text {
margin-left: 8em;
min-height: 22px;
}
#edit-event-links .attachmentslist li.message a.messagelink,
#event-links .attachmentslist li.message a.messagelink {
padding: 0 0 0 24px;
}
#edit-event-links .attachmentslist li a.delete {
top: 0;
background-position: -6px -378px;
}
#edit-event-links .attachmentslist li.deleted a.messagelink,
#edit-event-links .attachmentslist li.deleted a.messagelink:hover {
text-decoration: line-through;
}
#eventedit .formtable td.label {
min-width: 6em;
}

View file

@ -135,6 +135,11 @@
<label><roundcube:label name="calendar.sensitivity" /></label>
<span class="event-text"></span>
</div>
<div class="event-section" id="event-links">
<label><roundcube:label name="calendar.links" /></label>
<span class="event-text"></span>
<br style="clear:left">
</div>
<div class="event-section" id="event-attachments">
<label><roundcube:label name="attachments" /></label>
<div class="event-text"></div>

View file

@ -70,6 +70,11 @@
<label for="edit-sensitivity"><roundcube:label name="calendar.sensitivity" /></label>
<roundcube:object name="plugin.sensitivity_select" id="edit-sensitivity" />
</div>
<div class="event-section" id="edit-event-links">
<label><roundcube:label name="calendar.links" /></label>
<div class="event-text"></div>
<br style="clear:left">
</div>
</div>
<!-- recurrence settings -->
<div id="event-panel-recurrence">

View file

@ -788,6 +788,39 @@ function rcube_libcalendaring(settings)
}
};
// Render message reference links to the given container
this.render_message_links = function(links, container, edit, plugin)
{
var ul = $('<ul>').addClass('attachmentslist');
$.each(links, function(i, link) {
if (!link.mailurl)
return true; // continue
var li = $('<li>').addClass('link')
.addClass('message eml')
.append($('<a>')
.attr('href', link.mailurl)
.addClass('messagelink')
.text(link.subject || link.uri)
)
.appendTo(ul);
// add icon to remove the link
if (edit) {
$('<a>')
.attr('href', '#delete')
.attr('title', rcmail.gettext('removelink', plugin))
.attr('data-uri', link.uri)
.addClass('delete')
.text(rcmail.gettext('delete'))
.appendTo(li);
}
});
container.empty().append(ul);
}
}
////// static methods

View file

@ -129,6 +129,7 @@ function rcube_tasklist_ui(settings)
var parse_datetime = this.parse_datetime;
var date2unixtime = this.date2unixtime;
var fromunixtime = this.fromunixtime;
var render_message_links = this.render_message_links;
/**
* initialize the tasks UI
@ -597,6 +598,12 @@ function rcube_tasklist_ui(settings)
return false;
});
// register click handler for message delete buttons
$('#taskedit-links').on('click', 'li a.delete', function(e) {
remove_link(e.target);
return false;
});
// handle global document clicks: close popup menus
$(document.body).click(clear_popups);
@ -1840,7 +1847,7 @@ function rcube_tasklist_ui(settings)
// build attachments list
$('#task-links').hide();
if ($.isArray(rec.links) && rec.links.length) {
task_show_links(rec.links || [], $('#task-links').children('.task-text'));
render_message_links(rec.links || [], $('#task-links').children('.task-text'), false, 'tasklist');
$('#task-links').show();
}
@ -2052,7 +2059,7 @@ function rcube_tasklist_ui(settings)
me.set_alarms_edit('#taskedit-alarms', action != 'new' && rec.valarms ? rec.valarms : []);
if ($.isArray(rec.links) && rec.links.length) {
task_show_links(rec.links, $('#taskedit-links .task-text'), true);
render_message_links(rec.links, $('#taskedit-links .task-text'), true, 'tasklist');
$('#taskedit-links').show();
}
else {
@ -2358,48 +2365,15 @@ function rcube_tasklist_ui(settings)
/**
*
*/
function task_show_links(links, container, edit)
function remove_link(elem)
{
var dellink, ul = $('<ul>').addClass('attachmentslist');
var $elem = $(elem), uri = $elem.attr('data-uri');
$.each(links, function(i, link) {
var li = $('<li>').addClass('link')
.addClass('message eml')
.append($('<a>')
.attr('href', link.mailurl)
.addClass('messagelink')
.text(link.subject || link.uri)
)
.appendTo(ul);
// add icon to remove the link
if (edit) {
$('<a>')
.attr('href', '#delete')
.attr('title', rcmail.gettext('removelink','tasklist'))
.addClass('delete')
.text(rcmail.gettext('delete'))
.click({ uri:link.uri }, function(e) {
remove_link(this, e.data.uri);
return false;
})
.appendTo(li);
}
});
container.empty().append(ul);
}
/**
*
*/
function remove_link(elem, uri)
{
// remove the link item matching the given uri
me.selected_task.links = $.grep(me.selected_task.links, function(link) { return link.uri != uri; });
// remove UI list item
$(elem).hide().closest('li').addClass('deleted');
$elem.hide().closest('li').addClass('deleted');
}
/**