diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 20ca8828..a79db6ca 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -135,6 +135,9 @@ class calendar extends rcube_plugin $this->register_action('randomdata', array($this, 'generate_randomdata')); $this->register_action('print', array($this,'print_view')); $this->register_action('mailimportevent', array($this, 'mail_import_event')); + $this->register_action('mailtoevent', array($this, 'mail_message2event')); + $this->register_action('inlineui', array($this, 'get_inline_ui')); + $this->register_action('check-recent', array($this, 'check_recent')); // remove undo information... if ($undo = $_SESSION['calendar_event_undo']) { @@ -158,6 +161,19 @@ class calendar extends rcube_plugin $this->add_hook('message_load', array($this, 'mail_message_load')); $this->add_hook('template_object_messagebody', array($this, 'mail_messagebody_html')); } + + // add 'Create event' item to message menu + if ($this->api->output->type == 'html') { + $this->api->add_content(html::tag('li', null, + $this->api->output->button(array( + 'command' => 'calendar-create-from-mail', + 'label' => 'calendar.createfrommail', + 'type' => 'link', + 'classact' => 'calendarlink active', + 'class' => 'calendarlink', + ))), + 'messagemenu'); + } } // add hook to display alarms @@ -227,27 +243,7 @@ class calendar extends rcube_plugin // Add JS files to the page header $this->ui->addJS(); - $this->register_handler('plugin.calendar_css', array($this->ui, 'calendar_css')); - $this->register_handler('plugin.calendar_list', array($this->ui, 'calendar_list')); - $this->register_handler('plugin.calendar_select', array($this->ui, 'calendar_select')); - $this->register_handler('plugin.category_select', array($this->ui, 'category_select')); - $this->register_handler('plugin.freebusy_select', array($this->ui, 'freebusy_select')); - $this->register_handler('plugin.priority_select', array($this->ui, 'priority_select')); - $this->register_handler('plugin.sensitivity_select', array($this->ui, 'sensitivity_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.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.attendees_list', array($this->ui, 'attendees_list')); - $this->register_handler('plugin.attendees_form', array($this->ui, 'attendees_form')); - $this->register_handler('plugin.attendees_freebusy_table', array($this->ui, 'attendees_freebusy_table')); - $this->register_handler('plugin.edit_attendees_notify', array($this->ui, 'edit_attendees_notify')); - $this->register_handler('plugin.edit_recurring_warning', array($this->ui, 'recurring_event_warning')); - $this->register_handler('plugin.event_rsvp_buttons', array($this->ui, 'event_rsvp_buttons')); - $this->register_handler('plugin.angenda_options', array($this->ui, 'angenda_options')); - $this->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template - + $this->ui->init_templates(); $this->rc->output->add_label('low','normal','high','delete','cancel','uploading','noemailwarning'); // initialize attendees autocompletion @@ -798,6 +794,15 @@ class calendar extends rcube_plugin } } + /** + * Handler for check-recent requests which are accidentally sent to calendar taks + */ + function check_recent() + { + // NOP + $this->rc->output->send(); + } + /** * Construct the ics file for exporting events to iCalendar format; */ @@ -1230,7 +1235,7 @@ class calendar extends rcube_plugin $calendar = get_input_value('calendar', RCUBE_INPUT_GPC); $uploadid = get_input_value('_uploadid', RCUBE_INPUT_GPC); - $eventid = $calendar.':'.$event; + $eventid = 'cal:'.$event; if (!is_array($_SESSION['event_session']) || $_SESSION['event_session']['id'] != $eventid) { $_SESSION['event_session'] = array(); @@ -1442,7 +1447,7 @@ class calendar extends rcube_plugin */ private function prepare_event(&$event, $action) { - $eventid = $event['calendar'].':'.$event['id']; + $eventid = 'cal:'.$event['id']; $attachments = array(); if (is_array($_SESSION['event_session']) && $_SESSION['event_session']['id'] == $eventid) { @@ -1456,7 +1461,7 @@ class calendar extends rcube_plugin } $event['attachments'] = $attachments; - + // check for organizer in attendees if ($event['attendees']) { $emails = $this->get_user_emails(); @@ -1487,6 +1492,7 @@ class calendar extends rcube_plugin private function cleanup_event(&$event) { // remove temp. attachment files + $eventid = 'cal:'.$event['id']; if (!empty($_SESSION['event_session']) && ($eventid = $_SESSION['event_session']['id'])) { $this->rc->plugins->exec_hook('attachments_cleanup', array('group' => $eventid)); unset($_SESSION['event_session']); @@ -1697,6 +1703,29 @@ class calendar extends rcube_plugin $this->rc->output->send("calendar.print"); } + /** + * + */ + public function get_inline_ui() + { + foreach (array('save','cancel','savingdata') as $label) + $texts['calendar.'.$label] = $this->gettext($label); + + $texts['calendar.new_event'] = $this->gettext('createfrommail'); + + $this->ui->init_templates(); + $this->ui->calendar_list(); # set env['calendars'] + echo $this->api->output->parse('calendar.eventedit', false, false); + echo html::tag('script', array('type' => 'text/javascript'), + "rcmail.set_env('calendars', " . json_encode($this->api->output->env['calendars']) . ");\n". + "rcmail.set_env('deleteicon', '" . $this->api->output->env['deleteicon'] . "');\n". + "rcmail.set_env('cancelicon', '" . $this->api->output->env['cancelicon'] . "');\n". + "rcmail.set_env('loadingicon', '" . $this->api->output->env['loadingicon'] . "');\n". + "rcmail.add_label(" . json_encode($texts) . ");\n" + ); + exit; + } + /** * Compare two event objects and return differing properties * @@ -2078,6 +2107,67 @@ class calendar extends rcube_plugin } + /** + * Read email message and return contents for a new event based on that message + */ + public function mail_message2event() + { + $uid = get_input_value('_uid', RCUBE_INPUT_POST); + $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); + $event = array(); + + // establish imap connection + $this->rc->imap_connect(); + $this->rc->imap->set_mailbox($mbox); + $message = new rcube_message($uid); + + if ($message->headers) { + $event['title'] = trim($message->subject); + $event['description'] = trim($message->first_text_part()); + + // copy mail attachments to event + if ($message->attachments) { + $eventid = 'cal:'; + 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(); + } + + foreach ((array)$message->attachments as $part) { + $attachment = array( + 'data' => $this->rc->imap->get_message_part($uid, $part->mime_id, $part), + 'size' => $part->size, + 'name' => $part->filename, + 'mimetype' => $part->mimetype, + 'group' => $eventid, + ); + + $attachment = $this->rc->plugins->exec_hook('attachment_save', $attachment); + + if ($attachment['status'] && !$attachment['abort']) { + $id = $attachment['id']; + + // store new attachment in session + unset($attachment['status'], $attachment['abort'], $attachment['data']); + $_SESSION['event_session']['attachments'][$id] = $attachment; + + $attachment['id'] = 'rcmfile' . $attachment['id']; # add prefix to consider it 'new' + $event['attachments'][] = $attachment; + } + } + } + + $this->rc->output->command('plugin.mail2event_dialog', $event); + } + else { + $this->rc->output->command('display_message', $this->gettext('messageopenerror'), 'error'); + } + + $this->rc->output->send(); + } + + /** * Checks if specified message part is a vcalendar data * diff --git a/plugins/calendar/calendar_base.js b/plugins/calendar/calendar_base.js index eec2dbe5..1767faa6 100644 --- a/plugins/calendar/calendar_base.js +++ b/plugins/calendar/calendar_base.js @@ -18,6 +18,8 @@ function rcube_calendar(settings) { // member vars + this.ui; + this.ui_loaded = false; this.settings = settings; this.alarm_ids = []; this.alarm_dialog = null; @@ -156,6 +158,49 @@ function rcube_calendar(settings) this.dismiss_link = null; }; + // create new event from current mail message + this.create_from_mail = function() + { + var uid; + if ((uid = rcmail.get_single_uid())) { + // load calendar UI (scripts and edit dialog template) + if (!this.ui_loaded) { + $.when( + $.getScript('./plugins/calendar/calendar_ui.js'), + $.get(rcmail.url('calendar/inlineui'), function(html){ $(document.body).append(html); }, 'html') + ).then(function() { + // register attachments form + rcmail.gui_object('attachmentlist', 'attachmentlist'); + + // disable attendees feature (autocompletion and stuff is not initialized) + for (var c in rcmail.env.calendars) + rcmail.env.calendars[c].attendees = false; + + me.ui_loaded = true; + me.ui = new rcube_calendar_ui(me.settings); + me.create_from_mail(); // start over + }); + return; + } + else { + // get message contents for event dialog + var lock = rcmail.set_busy(true, 'loading'); + rcmail.http_post('calendar/mailtoevent', { + '_mbox': rcmail.env.mailbox, + '_uid': uid + }, lock); + } + } + }; + + // callback function triggered from server with contents for the new event + this.mail2event_dialog = function(event) + { + if (event.title) { + this.ui.add_event(event); + rcmail.message_list.blur(); + } + }; } // static methods @@ -222,6 +267,23 @@ window.rcmail && rcmail.addEventListener('init', function(evt) { $('#'+p.action+'-'+p.id).show(); }); + + // register create-from-mail command to message_commands array + if (rcmail.env.task == 'mail') { + // place link above 'view source' + $('#messagemenu a.calendarlink').parent().insertBefore($('#messagemenu a.sourcelink').parent()); + + rcmail.register_command('calendar-create-from-mail', function() { cal.create_from_mail() }); + rcmail.addEventListener('plugin.mail2event_dialog', function(p){ cal.mail2event_dialog(p) }); + rcmail.addEventListener('plugin.unlock_saving', function(p){ rcmail.set_busy(false, null, cal.ui.saving_lock); }); + + if (rcmail.env.action != 'show') { + rcmail.env.message_commands.push('calendar-create-from-mail'); + rcmail.add_element($('')); + } + else + rcmail.enable_command('calendar-create-from-mail', true); + } } rcmail.addEventListener('plugin.ping_url', function(p){ diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index 72c89bce..c2598944 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -723,6 +723,10 @@ function rcube_calendar_ui(settings) // activate the first tab $('#eventtabs').tabs('select', 0); + + // hack: set task to 'calendar' to make all dialog actions work correctly + var comm_path_before = rcmail.env.comm_path; + rcmail.env.comm_path = comm_path_before.replace(/_task=[a-z]+/, '_task=calendar'); var editform = $("#eventedit"); @@ -738,6 +742,7 @@ function rcube_calendar_ui(settings) rcmail.ksearch_blur(); rcmail.ksearch_destroy(); freebusy_data = {}; + rcmail.env.comm_path = comm_path_before; // restore comm_path }, buttons: buttons, minWidth: 500, @@ -1494,7 +1499,7 @@ function rcube_calendar_ui(settings) var update_event = function(action, data) { me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata'); - rcmail.http_post('event', { action:action, e:data }); + rcmail.http_post('calendar/event', { action:action, e:data }); // render event temporarily into the calendar if ((data.start && data.end) || data.id) { @@ -1771,15 +1776,17 @@ function rcube_calendar_ui(settings) }; // public method to bring up the new event dialog - this.add_event = function() { + this.add_event = function(templ) { if (this.selected_calendar) { var now = new Date(); - var date = fc.fullCalendar('getDate') || now; + var date = fc.fullCalendar('getDate'); + if (typeof date != 'Date') + date = now; date.setHours(now.getHours()+1); date.setMinutes(0); var end = new Date(date.getTime()); end.setHours(date.getHours()+1); - event_edit_dialog('new', { start:date, end:end, allDay:false, calendar:this.selected_calendar }); + event_edit_dialog('new', $.extend({ start:date, end:end, allDay:false, calendar:this.selected_calendar }, templ || {})); } }; @@ -2391,7 +2398,7 @@ function rcube_calendar_ui(settings) }, beforeShowDay: function(date) { var view = fc.fullCalendar('getView'); - var active = date.getTime() >= view.visStart.getTime() && date.getTime() < view.visEnd.getTime(); + var active = view.visStart && date.getTime() >= view.visStart.getTime() && date.getTime() < view.visEnd.getTime(); return [ true, (active ? 'ui-datepicker-activerange ui-datepicker-active-' + view.name : ''), '']; } })) // set event handler for clicks on calendar week cell of the datepicker widget diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php index 62cf0b4d..c5ed6774 100644 --- a/plugins/calendar/lib/calendar_ui.php +++ b/plugins/calendar/lib/calendar_ui.php @@ -63,7 +63,34 @@ class calendar_ui $this->ready = true; } - + + /** + * Register handler methods for the template engine + */ + public function init_templates() + { + $this->cal->register_handler('plugin.calendar_css', array($this, 'calendar_css')); + $this->cal->register_handler('plugin.calendar_list', array($this, 'calendar_list')); + $this->cal->register_handler('plugin.calendar_select', array($this, 'calendar_select')); + $this->cal->register_handler('plugin.category_select', array($this, 'category_select')); + $this->cal->register_handler('plugin.freebusy_select', array($this, 'freebusy_select')); + $this->cal->register_handler('plugin.priority_select', array($this, 'priority_select')); + $this->cal->register_handler('plugin.sensitivity_select', array($this, 'sensitivity_select')); + $this->cal->register_handler('plugin.alarm_select', array($this, 'alarm_select')); + $this->cal->register_handler('plugin.snooze_select', array($this, 'snooze_select')); + $this->cal->register_handler('plugin.recurrence_form', array($this, 'recurrence_form')); + $this->cal->register_handler('plugin.attachments_form', array($this, 'attachments_form')); + $this->cal->register_handler('plugin.attachments_list', array($this, 'attachments_list')); + $this->cal->register_handler('plugin.attendees_list', array($this, 'attendees_list')); + $this->cal->register_handler('plugin.attendees_form', array($this, 'attendees_form')); + $this->cal->register_handler('plugin.attendees_freebusy_table', array($this, 'attendees_freebusy_table')); + $this->cal->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify')); + $this->cal->register_handler('plugin.edit_recurring_warning', array($this, 'recurring_event_warning')); + $this->cal->register_handler('plugin.event_rsvp_buttons', array($this, 'event_rsvp_buttons')); + $this->cal->register_handler('plugin.angenda_options', array($this, 'angenda_options')); + $this->cal->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template + } + /** * Adds CSS stylesheets to the page header */ diff --git a/plugins/calendar/localization/de_CH.inc b/plugins/calendar/localization/de_CH.inc index 208db617..ad97c098 100644 --- a/plugins/calendar/localization/de_CH.inc +++ b/plugins/calendar/localization/de_CH.inc @@ -67,6 +67,7 @@ $labels['searchlaterdates'] = 'Spätere Termine suchen »'; $labels['andnmore'] = '$nr weitere...'; $labels['showmore'] = 'Mehr anzeigen...'; $labels['togglerole'] = 'Klick zum Ändern der Rolle'; +$labels['createfrommail'] = 'Als Termin speichern'; // agenda view $labels['listrange'] = 'Angezeigter Bereich:'; diff --git a/plugins/calendar/localization/de_DE.inc b/plugins/calendar/localization/de_DE.inc index 6aa5bfbe..e1452d63 100644 --- a/plugins/calendar/localization/de_DE.inc +++ b/plugins/calendar/localization/de_DE.inc @@ -67,6 +67,7 @@ $labels['searchlaterdates'] = 'Spätere Termine suchen »'; $labels['andnmore'] = '$nr weitere...'; $labels['showmore'] = 'Mehr anzeigen...'; $labels['togglerole'] = 'Klick zum Ändern der Rolle'; +$labels['createfrommail'] = 'Als Termin speichern'; // agenda view $labels['listrange'] = 'Angezeigter Bereich:'; diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc index 29458a1e..ce0bfe0d 100644 --- a/plugins/calendar/localization/en_US.inc +++ b/plugins/calendar/localization/en_US.inc @@ -67,6 +67,7 @@ $labels['searchlaterdates'] = 'Search for later events »'; $labels['andnmore'] = '$nr more...'; $labels['showmore'] = 'Show more...'; $labels['togglerole'] = 'Click to toggle role'; +$labels['createfrommail'] = 'Save as event'; // agenda view $labels['listrange'] = 'Range to display:'; diff --git a/plugins/calendar/skins/default/calendar.css b/plugins/calendar/skins/default/calendar.css index d8497fcf..2c0c7978 100644 --- a/plugins/calendar/skins/default/calendar.css +++ b/plugins/calendar/skins/default/calendar.css @@ -1162,9 +1162,12 @@ fieldset #calendarcategories div { margin-bottom: 0.3em; } - /* Invitation UI in mail */ +#messagemenu li a.calendarlink { + background: url(images/calendars.png) 7px -109px no-repeat; +} + div.calendar-invitebox { min-height: 20px; margin: 5px 8px; diff --git a/plugins/calendar/skins/default/images/calendars.gif b/plugins/calendar/skins/default/images/calendars.gif index 35314095..cf12ebdf 100644 Binary files a/plugins/calendar/skins/default/images/calendars.gif and b/plugins/calendar/skins/default/images/calendars.gif differ diff --git a/plugins/calendar/skins/default/images/calendars.png b/plugins/calendar/skins/default/images/calendars.png index 76005d7f..feb39451 100644 Binary files a/plugins/calendar/skins/default/images/calendars.png and b/plugins/calendar/skins/default/images/calendars.png differ diff --git a/plugins/calendar/skins/default/templates/calendar.html b/plugins/calendar/skins/default/templates/calendar.html index a878d392..4098e5dd 100644 --- a/plugins/calendar/skins/default/templates/calendar.html +++ b/plugins/calendar/skins/default/templates/calendar.html @@ -89,109 +89,7 @@
-
- - -
-
- -
- -
-
- -
- -
-
- -
- -
-
- - -   - -
-
- -   - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- - - -
- -
-
- -
-
- -
-
-
- -
+
diff --git a/plugins/calendar/skins/default/templates/eventedit.html b/plugins/calendar/skins/default/templates/eventedit.html new file mode 100644 index 00000000..35484788 --- /dev/null +++ b/plugins/calendar/skins/default/templates/eventedit.html @@ -0,0 +1,103 @@ +
+
+
    +
  • +
  • +
  • +
  • +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ + +   + +
+
+ +   + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ + + +
+ +
+
+ +
+
+ +
+
+
+ +
\ No newline at end of file