diff --git a/plugins/calendar/calendar.js b/plugins/calendar/calendar.js
index d14c2b95..103e06c9 100644
--- a/plugins/calendar/calendar.js
+++ b/plugins/calendar/calendar.js
@@ -46,6 +46,21 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
var day_clicked = day_clicked_ts = 0;
var ignore_click = false;
+ // create a nice human-readable string for the date/time range
+ var event_date_text = function(event) {
+ var fromto, duration = event.end.getTime() / 1000 - event.start.getTime() / 1000;
+ if (event.allDay)
+ fromto = $.fullCalendar.formatDate(event.start, settings['date_format']) + (duration > 86400 ? ' — ' + $.fullCalendar.formatDate(event.end, settings['date_format']) : '');
+ else if (duration < 86400 && event.start.getDay() == event.end.getDay())
+ fromto = $.fullCalendar.formatDate(event.start, settings['date_format']) + ' ' + $.fullCalendar.formatDate(event.start, settings['time_format']) + ' — '
+ + $.fullCalendar.formatDate(event.end, settings['time_format']);
+ else
+ fromto = $.fullCalendar.formatDate(event.start, settings['date_format']) + ' ' + $.fullCalendar.formatDate(event.start, settings['time_format']) + ' — '
+ + $.fullCalendar.formatDate(event.end, settings['date_format']) + ' ' + $.fullCalendar.formatDate(event.end, settings['time_format']);
+
+ return fromto;
+ };
+
// event details dialog (show only)
var event_show_dialog = function(event) {
var $dialog = $("#eventshow");
@@ -59,17 +74,8 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
if (event.description)
$('#event-description').show().children('.event-text').html(nl2br(Q(event.description))); // TODO: format HTML with clickable links and stuff
- // TODO: create a nice human-readable string for the date/time range
- var fromto, duration = event.end.getTime() / 1000 - event.start.getTime() / 1000;
- if (event.allDay)
- fromto = $.fullCalendar.formatDate(event.start, settings['date_format']) + ' — ' + $.fullCalendar.formatDate(event.end, settings['date_format']);
- else if (duration < 86400 && event.start.getDay() == event.end.getDay())
- fromto = $.fullCalendar.formatDate(event.start, settings['date_format']) + ' ' + $.fullCalendar.formatDate(event.start, settings['time_format']) + ' — '
- + $.fullCalendar.formatDate(event.end, settings['time_format']);
- else
- fromto = $.fullCalendar.formatDate(event.start, settings['date_format']) + ' ' + $.fullCalendar.formatDate(event.start, settings['time_format']) + ' — '
- + $.fullCalendar.formatDate(event.end, settings['date_format']) + ' ' + $.fullCalendar.formatDate(event.end, settings['time_format']);
- $('#event-date').html(Q(fromto)).show();
+ // render from-to in a nice human-readable way
+ $('#event-date').html(Q(event_date_text(event))).show();
if (event.recurrence && event.recurrence_text)
$('#event-repeat').show().children('.event-text').html(Q(event.recurrence_text));
@@ -416,6 +422,47 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
return false;
};
+
+ // display a notification for the given pending alarms
+ this.display_alarms = function(alarms) {
+ // clear old alert first
+ $('#alarm-display').dialog('destroy');
+
+ var event_ids = [];
+ var display = $('
').attr('id', 'alarm-display');
+ for (var html, alarm, i=0; i < alarms.length; i++) {
+ alarm = alarms[i];
+ alarm.start = new Date(alarm.start);
+ alarm.end = new Date(alarm.end);
+ event_ids.push(alarm.id);
+
+ html = '
' + Q(alarm.title) + '
';
+ html += '
' + Q(alarm.location) + '
';
+ html += '
' + Q(event_date_text(alarm)) + '
';
+ $('
').addClass('alarm-item').html(html).appendTo(display);
+ }
+
+ display.appendTo(document.body).dialog({
+ modal: true,
+ resizable: true,
+ closeOnEscape: false,
+ dialogClass: 'alert',
+ title: rcmail.gettext('alarmtitle', 'calendar'),
+ buttons: {
+ "Snooze": function() {
+ $(this).dialog('close');
+ },
+ "Dismiss": function() {
+ $(this).dialog('close');
+ }
+ },
+ close: function() {
+ $(this).dialog('destroy');
+ // TODO: submit dismissed event_ids to server
+ $(this).remove();
+ }
+ }).data('event_ids', event_ids.join(','));
+ };
// create list of event sources AKA calendars
@@ -618,19 +665,19 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
} // end rcube_calendar class
-
+
// configure toobar buttons
rcmail.register_command('plugin.addevent', function(){ cal.add_event(); }, true);
// export events
rcmail.register_command('plugin.export', function(){ rcmail.goto_url('plugin.export_events', { source:cal.selected_calendar }); }, true);
rcmail.enable_command('plugin.export', true);
+
+ // register callback commands
+ rcmail.addEventListener('plugin.display_alarms', function(alarms){ cal.display_alarms(alarms); });
// reload calendar
- rcmail.addEventListener('plugin.reload_calendar', reload_calendar);
- function reload_calendar() {
- $('#calendar').fullCalendar('refetchEvents');
- }
+ rcmail.addEventListener('plugin.reload_calendar', function() { $('#calendar').fullCalendar('refetchEvents'); });
var formattime = function(hour, minutes) {
diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
index a4342a82..c84a45e0 100644
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -74,6 +74,7 @@ class calendar extends rcube_plugin
$this->register_action('plugin.load_events', array($this, 'load_events'));
$this->register_action('plugin.event', array($this, 'event'));
$this->register_action('plugin.export_events', array($this, 'export_events'));
+ $this->add_hook('keep_alive', array($this, 'keep_alive'));
// set user's timezone
if ($this->rc->config->get('timezone') === 'auto')
@@ -360,6 +361,20 @@ class calendar extends rcube_plugin
exit;
}
+ /**
+ * Handler for keep-alive requests
+ * This will check for pending notifications and pass them to the client
+ */
+ function keep_alive($attr)
+ {
+ $alarms = $this->driver->pending_alarms(time());
+ #if ($alarms)
+ # $this->rc->output->command('plugin.display_alarms', $this->_alarms_output($alarms));
+ }
+
+ /**
+ *
+ */
function export_events()
{
$start = get_input_value('start', RCUBE_INPUT_GET);
@@ -375,6 +390,9 @@ class calendar extends rcube_plugin
exit;
}
+ /**
+ *
+ */
function load_settings()
{
$settings = array();
@@ -478,6 +496,28 @@ class calendar extends rcube_plugin
return json_encode($json);
}
+
+ /**
+ * Generate reduced and streamlined output for pending alarms
+ */
+ private function _alarms_output($alarms)
+ {
+ $out = array();
+ foreach ($alarms as $alarm) {
+ $out[] = array(
+ 'id' => $alarm['id'],
+ 'start' => $alarm['start'],
+ 'end' => $alarm['end'],
+ 'allDay' => ($event['all_day'] == 1)?true:false,
+ 'title' => $alarm['title'],
+ 'location' => $alarm['location'],
+ 'calendar' => $alarm['calendar'],
+ );
+ }
+
+ return $out;
+ }
+
/**
* Render localized text for alarm settings
*/
diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc
index 835dead0..7cb773e1 100644
--- a/plugins/calendar/localization/en_US.inc
+++ b/plugins/calendar/localization/en_US.inc
@@ -65,6 +65,7 @@ $labels['trigger+D'] = 'days after';
$labels['addalarm'] = 'add alarm';
$labels['defaultalarmtype'] = 'Default reminder setting';
$labels['defaultalarmoffset'] = 'Default reminder time';
+$labels['alarmtitle'] = 'Upcoming events';
// event dialog tabs
$labels['tabsummary'] = 'Summary';
diff --git a/plugins/calendar/skins/default/calendar.css b/plugins/calendar/skins/default/calendar.css
index e9ea1c5d..281b90c1 100644
--- a/plugins/calendar/skins/default/calendar.css
+++ b/plugins/calendar/skins/default/calendar.css
@@ -341,6 +341,20 @@ a.dropdown-link:after {
min-height: 20em;
}
+.alarm-item {
+ margin: 0.4em 0 1em 0;
+}
+
+.alarm-item .event-title {
+ font-size: 14px;
+ margin: 0.1em 0 0.3em 0;
+}
+
+.alarm-item div.event-section {
+ margin-top: 0.1em;
+ margin-bottom: 0.3em;
+}
+
.ui-dialog-buttonset a.dropdown-link {
margin-right: 1em;
}