Merge remote-tracking branch 'origin/master' into dev/perf

This commit is contained in:
Jeroen van Meeuwen (Kolab Systems) 2019-06-03 14:19:46 +02:00
commit c04d787c10
22 changed files with 151 additions and 175 deletions

View file

@ -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/

View file

@ -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)

View file

@ -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
);
}

View file

@ -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

View file

@ -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",

View file

@ -25,7 +25,7 @@
+-------------------------------------------------------------------------+
*/
// backend type (database, google, kolab)
// backend type (database, kolab)
$config['calendar_driver'] = "database";
// default calendar view (agendaDay, agendaWeek, month)

View file

@ -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,

View file

@ -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 */;

View file

@ -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']);

View file

@ -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>

View file

@ -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",

View file

@ -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/

View file

@ -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']));

View file

@ -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();

View file

@ -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",

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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",

View file

@ -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>

View file

@ -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()});
}
}

View file

@ -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)),
),
);