Merge remote-tracking branch 'origin/master' into dev/perf
This commit is contained in:
commit
c04d787c10
22 changed files with 151 additions and 175 deletions
|
@ -6,14 +6,10 @@ server as backends for calendar and event storage. For both drivers, some
|
|||
initialization of the local database is necessary. To do so, execute the
|
||||
SQL commands in drivers/<yourchoice>/SQL/<yourdatabase>.initial.sql
|
||||
|
||||
The client-side calendar UI relies on the "fullcalendar" project by Adam Arshaw
|
||||
with extensions made for the use in Roundcube. All changes are published in
|
||||
an official fork at https://github.com/roundcube/fullcalendar
|
||||
|
||||
For some general calendar-based operations such as alarms handling or iCal
|
||||
parsing/exporting this plugins requires the `libcalendaring` plugin which
|
||||
is also part of the Kolab Roundcube Plugins repository. Make sure that plugin
|
||||
is installed and configured correctly.
|
||||
parsing/exporting and UI widgets/style this plugins requires the `libcalendaring`
|
||||
and `libkolab` plugins which are also part of the Kolab Roundcube Plugins repository.
|
||||
Make sure these plugins are installed and configured correctly.
|
||||
|
||||
For recurring event computation, some utility classes from the Horde project
|
||||
are used. They are packaged in a slightly modified version with this plugin.
|
||||
|
@ -27,7 +23,7 @@ library plugins. Thus in order to run the calendar plugin, you also need the
|
|||
following plugins installed:
|
||||
|
||||
* libcalendaring [1]
|
||||
* libkolab [1] (when using the 'kolab' driver)
|
||||
* libkolab [1]
|
||||
|
||||
|
||||
INSTALLATION
|
||||
|
@ -44,6 +40,7 @@ driver.
|
|||
$ cd /<path-to-roundcube>/plugins
|
||||
$ cp -r /tmp/roundcubemail-plugins-kolab/plugins/calendar .
|
||||
$ cp -r /tmp/roundcubemail-plugins-kolab/plugins/libcalendaring .
|
||||
$ cp -r /tmp/roundcubemail-plugins-kolab/plugins/libkolab .
|
||||
|
||||
2. Create calendar plugin configuration
|
||||
|
||||
|
@ -53,11 +50,15 @@ driver.
|
|||
|
||||
3. Initialize the calendar database tables
|
||||
|
||||
$ mysql roundcubemail < drivers/database/SQL/mysql.initial.sql
|
||||
|
||||
4. Enable the calendar plugin
|
||||
|
||||
$ cd ../../
|
||||
$ bin/initdb.sh --dir=plugins/calendar/drivers/database/SQL
|
||||
|
||||
4. Build css styles for the Elastic skin
|
||||
|
||||
$ lessc --relative-urls -x plugins/libkolab/skins/elastic/libkolab.less > plugins/libkolab/skins/elastic/libkolab.min.css
|
||||
|
||||
5. Enable the calendar plugin
|
||||
|
||||
$ edit config/config.inc.php
|
||||
|
||||
Add 'calendar' to the list of active plugins:
|
||||
|
@ -68,5 +69,4 @@ Add 'calendar' to the list of active plugins:
|
|||
);
|
||||
|
||||
|
||||
|
||||
[1] https://git.kolab.org/diffusion/RPK/
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
+ Edit: 3.12: Subject
|
||||
+ Edit: 3.13: Location
|
||||
+ Edit: 3.14: Start / End / All Day
|
||||
+ Edit: 3.15: Show time as: Busy, Free, Out of office
|
||||
+ Edit: 3.16: Reminder set
|
||||
+ Edit: 3.17: Priority: High/Low
|
||||
+ Edit: 3.18: Recurrence (in line with Kontact)
|
||||
+ Edit: 3.19: Attachment Upload
|
||||
+ Edit: 3.20: Print
|
||||
+ Add/Manage Attendees
|
||||
+ Edit: 3.21: Required / Optional / Resource specification
|
||||
+ Edit: 3.22: Conflict Handling (Free/Busy Check for attendees)
|
||||
+ View: 3.3: Display modes (agenda / day / week / month)
|
||||
+ Day / Week / Month
|
||||
+ List (Agenda) view
|
||||
+ Add selection for date range
|
||||
- Individual days selection
|
||||
+ Show list of calendars in a (hideable) drawer
|
||||
+ View: 3.1: Folder list
|
||||
+ View: 3.2: Add / Remove / Rename / Share Folders
|
||||
+ View: 3.6: Combined calendar view (Turn calendars on/off)
|
||||
+ View: 3.7: Small month overview calendar
|
||||
+ View: 3.5: Search
|
||||
- Filter by categories (similar to mail)
|
||||
+ View: 3.9: Alter event with drag/drop
|
||||
+ Option: 4.12: Set default reminder time
|
||||
+ Option: 3.23: Specify folder for new event (prefs)
|
||||
+ Option: Set date/time format in prefs
|
||||
+ Receive: 1.20: Invitation handling
|
||||
- Jump to calendar view from mail ("Show event")
|
||||
- Allow to re-send invitations
|
||||
- Implement iTIP delegation
|
||||
|
||||
+ View: 3.4: Fish-Eye View For Busy Days
|
||||
+ View: 3.8: Color according to calendar and category (similar to Kontact)
|
||||
|
||||
+ Support for multiple calendars (replace categories)
|
||||
+ Allow user to create/edit/delete calendars
|
||||
+ Colors for calendars should be user-configurable
|
||||
+ ICS parser/generator (http://code.google.com/p/qcal/)
|
||||
|
||||
- Script to send event alarms by email (in cronjob)
|
||||
- Export *with* attachments
|
||||
- Remember last visited view
|
||||
- Create/manage invdividual views
|
||||
+ Importing ICS files (upload, drag & drop)
|
||||
|
||||
|
|
@ -1361,7 +1361,7 @@ class calendar extends rcube_plugin
|
|||
public function itip_events($msgref)
|
||||
{
|
||||
$path = explode('/', $msgref);
|
||||
$msg = array_pop($path);
|
||||
$msg = array_pop($path);
|
||||
$mbox = join('/', $path);
|
||||
list($uid, $mime_id) = explode('#', $msg);
|
||||
$events = array();
|
||||
|
@ -1377,23 +1377,27 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
}
|
||||
*/
|
||||
$event['id'] = $event['uid'];
|
||||
$event['id'] = $event['uid'];
|
||||
$event['temporary'] = true;
|
||||
$event['readonly'] = true;
|
||||
$event['calendar'] = '--invitation--itip';
|
||||
$event['readonly'] = true;
|
||||
$event['calendar'] = '--invitation--itip';
|
||||
$event['className'] = 'fc-invitation-' . strtolower($partstat);
|
||||
$event['_mbox'] = $mbox;
|
||||
$event['_uid'] = $uid;
|
||||
$event['_part'] = $mime_id;
|
||||
$event['_mbox'] = $mbox;
|
||||
$event['_uid'] = $uid;
|
||||
$event['_part'] = $mime_id;
|
||||
|
||||
$events[] = $this->_client_event($event, true);
|
||||
|
||||
// add recurring instances
|
||||
if (!empty($event['recurrence'])) {
|
||||
foreach ($this->driver->get_recurring_events($event, $event['start']) as $recurring) {
|
||||
// Some installations can't handle all occurrences (aborting the request w/o an error in log)
|
||||
$end = clone $event['start'];
|
||||
$end->add(new DateInterval($event['recurrence']['FREQ'] == 'DAILY' ? 'P1Y' : 'P10Y'));
|
||||
|
||||
foreach ($this->driver->get_recurring_events($event, $event['start'], $end) as $recurring) {
|
||||
$recurring['temporary'] = true;
|
||||
$recurring['readonly'] = true;
|
||||
$recurring['calendar'] = '--invitation--itip';
|
||||
$recurring['readonly'] = true;
|
||||
$recurring['calendar'] = '--invitation--itip';
|
||||
$events[] = $this->_client_event($recurring, true);
|
||||
}
|
||||
}
|
||||
|
@ -1764,20 +1768,25 @@ class calendar extends rcube_plugin
|
|||
$settings = array();
|
||||
|
||||
// configuration
|
||||
$settings['default_view'] = (string) $this->rc->config->get('calendar_default_view', $this->defaults['calendar_default_view']);
|
||||
$settings['timeslots'] = (int) $this->rc->config->get('calendar_timeslots', $this->defaults['calendar_timeslots']);
|
||||
$settings['first_day'] = (int) $this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']);
|
||||
$settings['first_hour'] = (int) $this->rc->config->get('calendar_first_hour', $this->defaults['calendar_first_hour']);
|
||||
$settings['work_start'] = (int) $this->rc->config->get('calendar_work_start', $this->defaults['calendar_work_start']);
|
||||
$settings['work_end'] = (int) $this->rc->config->get('calendar_work_end', $this->defaults['calendar_work_end']);
|
||||
$settings['agenda_range'] = (int) $this->rc->config->get('calendar_agenda_range', $this->defaults['calendar_agenda_range']);
|
||||
$settings['event_coloring'] = (int) $this->rc->config->get('calendar_event_coloring', $this->defaults['calendar_event_coloring']);
|
||||
$settings['time_indicator'] = (int) $this->rc->config->get('calendar_time_indicator', $this->defaults['calendar_time_indicator']);
|
||||
$settings['invite_shared'] = (int) $this->rc->config->get('calendar_allow_invite_shared', $this->defaults['calendar_allow_invite_shared']);
|
||||
$settings['itip_notify'] = (int) $this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']);
|
||||
$settings['show_weekno'] = (int) $this->rc->config->get('calendar_show_weekno', $this->defaults['calendar_show_weekno']);
|
||||
$settings['default_calendar'] = $this->rc->config->get('calendar_default_calendar');
|
||||
$settings['default_view'] = (string)$this->rc->config->get('calendar_default_view', $this->defaults['calendar_default_view']);
|
||||
$settings['timeslots'] = (int)$this->rc->config->get('calendar_timeslots', $this->defaults['calendar_timeslots']);
|
||||
$settings['first_day'] = (int)$this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']);
|
||||
$settings['first_hour'] = (int)$this->rc->config->get('calendar_first_hour', $this->defaults['calendar_first_hour']);
|
||||
$settings['work_start'] = (int)$this->rc->config->get('calendar_work_start', $this->defaults['calendar_work_start']);
|
||||
$settings['work_end'] = (int)$this->rc->config->get('calendar_work_end', $this->defaults['calendar_work_end']);
|
||||
$settings['agenda_range'] = (int)$this->rc->config->get('calendar_agenda_range', $this->defaults['calendar_agenda_range']);
|
||||
$settings['event_coloring'] = (int)$this->rc->config->get('calendar_event_coloring', $this->defaults['calendar_event_coloring']);
|
||||
$settings['time_indicator'] = (int)$this->rc->config->get('calendar_time_indicator', $this->defaults['calendar_time_indicator']);
|
||||
$settings['invite_shared'] = (int)$this->rc->config->get('calendar_allow_invite_shared', $this->defaults['calendar_allow_invite_shared']);
|
||||
$settings['invitation_calendars'] = (bool)$this->rc->config->get('kolab_invitation_calendars', false);
|
||||
$settings['itip_notify'] = (int)$this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']);
|
||||
$settings['show_weekno'] = (int)$this->rc->config->get('calendar_show_weekno', $this->defaults['calendar_show_weekno']);
|
||||
$settings['invitation_calendars'] = (bool) $this->rc->config->get('kolab_invitation_calendars', false);
|
||||
|
||||
// 'table' view has been replaced by 'list' view
|
||||
if ($settings['default_view'] == 'table') {
|
||||
$settings['default_view'] = 'list';
|
||||
}
|
||||
|
||||
// get user identity to create default attendee
|
||||
if ($this->ui->screen == 'calendar') {
|
||||
|
@ -2916,14 +2925,15 @@ class calendar extends rcube_plugin
|
|||
|
||||
// get prepared inline UI for this event object
|
||||
if ($ical_objects->method) {
|
||||
$append = '';
|
||||
$append = '';
|
||||
$date_str = $this->rc->format_date($event['start'], $this->rc->config->get('date_format'), empty($event['start']->_dateonly));
|
||||
$date = new DateTime($event['start']->format('Y-m-d') . ' 12:00:00', new DateTimeZone('UTC'));
|
||||
|
||||
// prepare a small agenda preview to be filled with actual event data on async request
|
||||
if ($ical_objects->method == 'REQUEST') {
|
||||
$append = html::div('calendar-agenda-preview',
|
||||
html::tag('h3', 'preview-title', $this->gettext('agenda') . ' ' .
|
||||
html::span('date', $this->rc->format_date($event['start'], $this->rc->config->get('date_format')))
|
||||
) . '%before%' . $this->mail_agenda_event_row($event, 'current') . '%after%');
|
||||
html::tag('h3', 'preview-title', $this->gettext('agenda') . ' ' . html::span('date', $date_str))
|
||||
. '%before%' . $this->mail_agenda_event_row($event, 'current') . '%after%');
|
||||
}
|
||||
|
||||
$html .= html::div('calendar-invitebox invitebox boxinformation',
|
||||
|
@ -2933,7 +2943,7 @@ class calendar extends rcube_plugin
|
|||
$ical_objects->mime_id . ':' . $idx,
|
||||
'calendar',
|
||||
rcube_utils::anytodatetime($ical_objects->message_date),
|
||||
$this->rc->url(array('task' => 'calendar')) . '&view=agendaDay&date=' . $event['start']->format('U')
|
||||
$this->rc->url(array('task' => 'calendar')) . '&view=agendaDay&date=' . $date->format('U')
|
||||
) . $append
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3609,25 +3609,19 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
|
||||
var id = this.value;
|
||||
if (me.calendars[id]) { // add or remove event source on click
|
||||
var action;
|
||||
if (this.checked) {
|
||||
action = 'addEventSource';
|
||||
me.calendars[id].active = true;
|
||||
}
|
||||
else {
|
||||
action = 'removeEventSource';
|
||||
me.calendars[id].active = false;
|
||||
}
|
||||
|
||||
// add or remove event source on click
|
||||
if (me.calendars[id]) {
|
||||
// adjust checked state of original list item
|
||||
if (calendars_list.is_search()) {
|
||||
calendars_list.container.find('input[value="'+id+'"]').prop('checked', this.checked);
|
||||
}
|
||||
|
||||
me.calendars[id].active = this.checked;
|
||||
|
||||
// add/remove event source
|
||||
fc.fullCalendar(action, me.calendars[id]);
|
||||
rcmail.http_post('calendar', { action:'subscribe', c:{ id:id, active:me.calendars[id].active?1:0 } });
|
||||
fc.fullCalendar(this.checked ? 'addEventSource' : 'removeEventSource', me.calendars[id]);
|
||||
rcmail.http_post('calendar', {action: 'subscribe', c: {id: id, active: this.checked ? 1 : 0}});
|
||||
}
|
||||
})
|
||||
.on('keypress', 'input[type=checkbox]', function(e) {
|
||||
|
@ -3690,8 +3684,7 @@ function rcube_calendar_ui(settings)
|
|||
if (rcmail.env.itip_events && rcmail.env.itip_events.length) {
|
||||
me.calendars['--invitation--itip'] = {
|
||||
events: rcmail.env.itip_events,
|
||||
color: '#fff',
|
||||
textColor: '#333',
|
||||
color: 'ffffff',
|
||||
editable: false,
|
||||
rights: 'lrs',
|
||||
attendees: true
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"description": "Calendar plugin",
|
||||
"homepage": "https://git.kolab.org/diffusion/RPK/",
|
||||
"license": "AGPLv3",
|
||||
"version": "3.4.5",
|
||||
"version": "3.4.6",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Thomas Bruederli",
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// backend type (database, google, kolab)
|
||||
// backend type (database, kolab)
|
||||
$config['calendar_driver'] = "database";
|
||||
|
||||
// default calendar view (agendaDay, agendaWeek, month)
|
||||
|
|
|
@ -14,7 +14,7 @@ CREATE TABLE IF NOT EXISTS `kolab_alarms` (
|
|||
PRIMARY KEY(`alarm_id`,`user_id`),
|
||||
CONSTRAINT `fk_kolab_alarms_user_id` FOREIGN KEY (`user_id`)
|
||||
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */;
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `itipinvitations` (
|
||||
`token` VARCHAR(64) NOT NULL,
|
||||
|
|
|
@ -8,4 +8,4 @@ CREATE TABLE `kolab_alarms` (
|
|||
PRIMARY KEY(`event_id`),
|
||||
CONSTRAINT `fk_kolab_alarms_user_id` FOREIGN KEY (`user_id`)
|
||||
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */;
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
|
|
@ -116,17 +116,21 @@ class resources_driver_ldap extends resources_driver
|
|||
{
|
||||
$rec['ID'] = rcube_ldap::dn_decode($rec['ID']);
|
||||
|
||||
if (is_array($rec['attributes']) && $rec['attributes'][0]) {
|
||||
$attributes = array();
|
||||
$attributes = array();
|
||||
|
||||
foreach ($rec['attributes'] as $sattr) {
|
||||
foreach ((array) $rec['attributes'] as $sattr) {
|
||||
$sattr = trim($sattr);
|
||||
if ($sattr && $sattr[0] === '{') {
|
||||
$attr = @json_decode($sattr, true);
|
||||
$attributes += $attr;
|
||||
}
|
||||
|
||||
$rec['attributes'] = $attributes;
|
||||
else if ($sattr && empty($rec['description'])) {
|
||||
$rec['description'] = $sattr;
|
||||
}
|
||||
}
|
||||
|
||||
$rec['attributes'] = $attributes;
|
||||
|
||||
// force $rec['members'] to be an array
|
||||
if (!empty($rec['members']) && !is_array($rec['members'])) {
|
||||
$rec['members'] = array($rec['members']);
|
||||
|
|
|
@ -33,11 +33,11 @@
|
|||
<div class="form-group row" id="edit-alarms">
|
||||
<label for="edit-alarm-item" class="col-sm-2 col-form-label"><roundcube:label name="calendar.alarms" /></label>
|
||||
<div class="col-sm-10 alarms-input">
|
||||
<div class="edit-alarm-item first">
|
||||
<div class="edit-alarm-item input-group first">
|
||||
<roundcube:object name="plugin.alarm_select" id="edit-alarm-item" />
|
||||
<span class="edit-alarm-buttons">
|
||||
<a href="#add" class="icon button btn create add-alarm"><span class="inner"><roundcube:label name="libcalendaring.addalarm" /></span></a>
|
||||
<a href="#delete" class="icon button btn delete delete-alarm"><span class="inner"><roundcube:label name="libcalendaring.removealarm" /></span></a>
|
||||
<span class="edit-alarm-buttons input-group-append">
|
||||
<a href="#add" class="icon button btn add add-alarm input-group-text"><span class="inner"><roundcube:label name="libcalendaring.addalarm" /></span></a>
|
||||
<a href="#delete" class="icon button btn delete delete-alarm input-group-text"><span class="inner"><roundcube:label name="libcalendaring.removealarm" /></span></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"description": "Library providing common functions for calendaring plugins",
|
||||
"homepage": "https://git.kolab.org/diffusion/RPK/",
|
||||
"license": "AGPLv3",
|
||||
"version": "3.4.5",
|
||||
"version": "3.4.6",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Thomas Bruederli",
|
||||
|
|
|
@ -348,6 +348,11 @@ function rcube_libcalendaring(settings)
|
|||
if (!color_map[color]) {
|
||||
color_map[color] = '#fff';
|
||||
|
||||
// Convert 3-char to 6-char
|
||||
if (/^#?([a-f0-9]{1})([a-f0-9]{1})([a-f0-9]{1})$/i.test(color)) {
|
||||
color = '#' + RegExp.$1 + RegExp.$1 + RegExp.$2 + RegExp.$2 + RegExp.$3 + RegExp.$3;
|
||||
}
|
||||
|
||||
if (/^#?([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i.test(color)) {
|
||||
// use information about brightness calculation found at
|
||||
// http://javascriptrules.com/2009/08/05/css-color-brightness-contrast-using-javascript/
|
||||
|
|
|
@ -315,8 +315,8 @@ class libcalendaring extends rcube_plugin
|
|||
$time_format = self::to_php_date_format($this->rc->config->get('calendar_time_format', $this->defaults['calendar_time_format']));
|
||||
|
||||
if ($event['allday']) {
|
||||
$fromto = $this->rc->format_date($event['start'], $date_format);
|
||||
if (($todate = $this->rc->format_date($event['end'], $date_format)) != $fromto)
|
||||
$fromto = $this->rc->format_date($event['start'], $date_format, false);
|
||||
if (($todate = $this->rc->format_date($event['end'], $date_format, false)) != $fromto)
|
||||
$fromto .= ' - ' . $todate;
|
||||
}
|
||||
else if ($duration < 86400 && $event['start']->format('d') == $event['end']->format('d')) {
|
||||
|
@ -344,7 +344,7 @@ class libcalendaring extends rcube_plugin
|
|||
{
|
||||
unset($attrib['name']);
|
||||
|
||||
$input_value = new html_inputfield(array('name' => 'alarmvalue[]', 'class' => 'edit-alarm-value form-control input-group-prepend', 'size' => 3));
|
||||
$input_value = new html_inputfield(array('name' => 'alarmvalue[]', 'class' => 'edit-alarm-value form-control', 'size' => 3));
|
||||
$input_date = new html_inputfield(array('name' => 'alarmdate[]', 'class' => 'edit-alarm-date form-control', 'size' => 10));
|
||||
$input_time = new html_inputfield(array('name' => 'alarmtime[]', 'class' => 'edit-alarm-time form-control', 'size' => 6));
|
||||
$select_type = new html_select(array('name' => 'alarmtype[]', 'class' => 'edit-alarm-type form-control', 'id' => $attrib['id']));
|
||||
|
|
|
@ -430,7 +430,7 @@ class libvcalendar implements Iterator
|
|||
case 'DTEND':
|
||||
case 'DUE':
|
||||
$propmap = array('DTSTART' => 'start', 'DTEND' => 'end', 'DUE' => 'due');
|
||||
$event[$propmap[$prop->name]] = self::convert_datetime($prop);
|
||||
$event[$propmap[$prop->name]] = self::convert_datetime($prop);
|
||||
break;
|
||||
|
||||
case 'TRANSP':
|
||||
|
@ -694,16 +694,14 @@ class libvcalendar implements Iterator
|
|||
|
||||
// assign current timezone to event start/end
|
||||
if ($event['start'] instanceof DateTime) {
|
||||
if ($this->timezone)
|
||||
$event['start']->setTimezone($this->timezone);
|
||||
$this->_apply_timezone($event['start']);
|
||||
}
|
||||
else {
|
||||
unset($event['start']);
|
||||
}
|
||||
|
||||
if ($event['end'] instanceof DateTime) {
|
||||
if ($this->timezone)
|
||||
$event['end']->setTimezone($this->timezone);
|
||||
$this->_apply_timezone($event['end']);
|
||||
}
|
||||
else {
|
||||
unset($event['end']);
|
||||
|
@ -728,6 +726,27 @@ class libvcalendar implements Iterator
|
|||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply user timezone to DateTime object
|
||||
*/
|
||||
private function _apply_timezone(&$date)
|
||||
{
|
||||
if (empty($this->timezone)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For date-only we'll keep the date and time intact
|
||||
if ($date->_dateonly) {
|
||||
$dt = new DateTime(null, $this->timezone);
|
||||
$dt->setDate($date->format('Y'), $date->format('n'), $date->format('j'));
|
||||
$dt->setTime($date->format('G'), $date->format('i'), 0);
|
||||
$date = $dt;
|
||||
}
|
||||
else {
|
||||
$date->setTimezone($this->timezone);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given vfreebusy component into an array representation
|
||||
*/
|
||||
|
@ -816,7 +835,6 @@ class libvcalendar implements Iterator
|
|||
if (empty($prop)) {
|
||||
return $as_array ? array() : null;
|
||||
}
|
||||
|
||||
else if ($prop instanceof VObject\Property\iCalendar\DateTime) {
|
||||
if (count($prop->getDateTimes()) > 1) {
|
||||
$dt = array();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"description": "Plugin to setup a basic environment for the interaction with a Kolab server.",
|
||||
"homepage": "https://git.kolab.org/diffusion/RPK/",
|
||||
"license": "AGPLv3",
|
||||
"version": "3.4.5",
|
||||
"version": "3.4.6",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Thomas Bruederli",
|
||||
|
|
|
@ -322,16 +322,10 @@ fieldset.categories .input-group {
|
|||
margin-top: 1.1rem;
|
||||
}
|
||||
|
||||
&.fc-invitation-needs-action {
|
||||
border: 1px dashed #5757c7;
|
||||
}
|
||||
|
||||
&.fc-invitation-tentative {
|
||||
border: 1px dashed #eb8900;
|
||||
}
|
||||
|
||||
&.fc-invitation-needs-action,
|
||||
&.fc-invitation-tentative,
|
||||
&.fc-invitation-declined {
|
||||
border: 1px dashed #c00;
|
||||
border: 1px dashed #999;
|
||||
}
|
||||
|
||||
&.fc-event-ns-other.fc-invitation-declined {
|
||||
|
@ -1255,6 +1249,10 @@ body.task-calendar {
|
|||
}
|
||||
}
|
||||
|
||||
#rcmfd_alarmvalue {
|
||||
max-width: 80px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: @screen-width-small) {
|
||||
#agendaoptions {
|
||||
padding-top: .5rem;
|
||||
|
|
|
@ -389,18 +389,30 @@
|
|||
& + .edit-alarm-item {
|
||||
margin-top: .25rem;
|
||||
}
|
||||
|
||||
&.first .delete-alarm,
|
||||
&:not(.first) .add-alarm {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-alarm-buttons {
|
||||
a {
|
||||
line-height: 1;
|
||||
padding: .375em .25em;
|
||||
margin: 0 .25rem;
|
||||
border-top-right-radius: .25rem !important;
|
||||
border-bottom-right-radius: .25rem !important;
|
||||
|
||||
&:before {
|
||||
margin: 0;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&.add:before {
|
||||
content: @fa-var-plus;
|
||||
}
|
||||
}
|
||||
|
||||
.inner {
|
||||
|
@ -408,16 +420,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
.edit-alarm-item.first .delete-alarm {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.edit-alarm-item:not(.first) .add-alarm {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.edit-alarm-type {
|
||||
flex: 1;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
|
||||
&:focus {
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-alarm-set {
|
||||
|
@ -426,26 +436,14 @@
|
|||
}
|
||||
|
||||
.edit-alarm-values {
|
||||
margin-left: .25rem;
|
||||
flex: 5;
|
||||
|
||||
&.offset-default {
|
||||
select.edit-alarm-related {
|
||||
border-radius: 0 .25rem .25rem 0;
|
||||
}
|
||||
.form-control {
|
||||
border-radius: 0;
|
||||
}
|
||||
&.offset-ontime {
|
||||
select.edit-alarm-offset {
|
||||
border-radius: .25rem 0 0 .25rem;
|
||||
}
|
||||
select.edit-alarm-related {
|
||||
border-radius: 0 .25rem .25rem 0;
|
||||
}
|
||||
}
|
||||
&.offset-ondate {
|
||||
select.edit-alarm-offset {
|
||||
border-radius: .25rem 0 0 .25rem;
|
||||
}
|
||||
|
||||
:first-child {
|
||||
border-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
right: 0;
|
||||
min-width: 2em;
|
||||
line-height: 1.4rem;
|
||||
margin: (@listing-line-height - 1.4rem)/2;
|
||||
margin: (@listing-line-height - 1.4 * @page-font-size)/2;
|
||||
padding: 0 .3em;
|
||||
border-radius: .4em;
|
||||
background: @color-list-secondary;
|
||||
|
@ -217,7 +217,7 @@
|
|||
|
||||
html.touch & {
|
||||
line-height: 2rem;
|
||||
margin: (@listing-touch-line-height - 2rem)/2;
|
||||
margin: (@listing-touch-line-height - 2 * @page-font-size)/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"description": "Task management plugin",
|
||||
"homepage": "https://git.kolab.org/diffusion/RPK/",
|
||||
"license": "AGPLv3",
|
||||
"version": "3.4.5",
|
||||
"version": "3.4.6",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Thomas Bruederli",
|
||||
|
|
|
@ -34,11 +34,11 @@
|
|||
<div class="form-group row" id="taskedit-alarms">
|
||||
<label for="edit-alarm-item" class="col-sm-2 col-form-label"><roundcube:label name="tasklist.alarms" /></label>
|
||||
<div class="col-sm-10 alarms-input">
|
||||
<div class="edit-alarm-item first">
|
||||
<div class="edit-alarm-item input-group first">
|
||||
<roundcube:object name="plugin.alarm_select" id="edit-alarm-item" />
|
||||
<span class="edit-alarm-buttons">
|
||||
<a href="#add" class="icon btn button create add-alarm"><span class="inner"><roundcube:label name="libcalendaring.addalarm" /></span></a>
|
||||
<a href="#delete" class="icon btn button delete delete-alarm"><span class="inner"><roundcube:label name="libcalendaring.removealarm" /></span></a>
|
||||
<span class="edit-alarm-buttons input-group-append">
|
||||
<a href="#add" class="icon btn button add add-alarm input-group-text"><span class="inner"><roundcube:label name="libcalendaring.addalarm" /></span></a>
|
||||
<a href="#delete" class="icon btn button delete delete-alarm input-group-text"><span class="inner"><roundcube:label name="libcalendaring.removealarm" /></span></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3050,8 +3050,6 @@ function rcube_tasklist_ui(settings)
|
|||
data = form.serializeJSON();
|
||||
if (list.id)
|
||||
data.id = list.id;
|
||||
if (form.find('#taskedit-tasklistname').is(':checked'))
|
||||
data.showalarms = 1;
|
||||
|
||||
saving_lock = rcmail.set_busy(true, 'tasklist.savingdata');
|
||||
rcmail.http_post('tasklist', {action: (list.id ? 'edit' : 'new'), l: data});
|
||||
|
@ -3172,7 +3170,7 @@ function rcube_tasklist_ui(settings)
|
|||
me.tasklists[prop.id] = prop;
|
||||
$(li).find('input').first().val(prop.id);
|
||||
$(li).find('.listname').first().html(Q(prop.name));
|
||||
tasklists_widget.update(id, { id:prop.id, html:li.children().first() });
|
||||
tasklists_widget.update(id, {id: prop.id, html: $(li).children().first()});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ class tasklist_ui
|
|||
'showalarms' => array(
|
||||
'id' => 'taskedit-showalarms',
|
||||
'label' => $this->plugin->gettext('showalarms'),
|
||||
'value' => html::tag('input', array('id' => 'taskedit-showalarms', 'name' => 'color', 'type' => 'checkbox')),
|
||||
'value' => html::tag('input', array('id' => 'taskedit-showalarms', 'name' => 'showalarms', 'type' => 'checkbox', 'value' => 1)),
|
||||
),
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue