Fixed saving and rendering of recurring events in Kolab backend + add (limited) support for monthly and yearly recurrence
This commit is contained in:
parent
507712e533
commit
df120c4f26
5 changed files with 254 additions and 85 deletions
|
@ -447,8 +447,8 @@ class calendar extends rcube_plugin
|
|||
|
||||
if ($success)
|
||||
$this->rc->output->show_message('successfullysaved', 'confirmation');
|
||||
else if ($removed)
|
||||
$this->rc->output->show_message('calendar.successremoval', 'confirmation');
|
||||
else if ($removed)
|
||||
$this->rc->output->show_message('calendar.successremoval', 'confirmation');
|
||||
else
|
||||
$this->rc->output->show_message('calendar.errorsaving', 'error');
|
||||
|
||||
|
|
|
@ -162,6 +162,16 @@ class kolab_calendar
|
|||
public function get_event($id)
|
||||
{
|
||||
$this->_fetch_events();
|
||||
|
||||
// event not found, maybe a recurring instance is requested
|
||||
if (!$this->events[$id]) {
|
||||
$master_id = preg_replace('/-\d+$/', '', $id);
|
||||
if ($this->events[$master_id] && $this->events[$master_id]['recurrence']) {
|
||||
$master = $this->events[$master_id];
|
||||
$this->_get_recurring_events($master, $master['start'], $master['start'] + 86400 * 365, $id);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->events[$id];
|
||||
}
|
||||
|
||||
|
@ -174,9 +184,6 @@ class kolab_calendar
|
|||
*/
|
||||
public function list_events($start, $end, $search = null)
|
||||
{
|
||||
// use Horde classes to compute recurring instances
|
||||
require_once 'Horde/Date/Recurrence.php';
|
||||
|
||||
$this->_fetch_events();
|
||||
|
||||
$events = array();
|
||||
|
@ -205,33 +212,9 @@ class kolab_calendar
|
|||
$events[] = $event;
|
||||
}
|
||||
|
||||
// resolve recurring events (maybe move to _fetch_events() for general use?)
|
||||
// resolve recurring events
|
||||
if ($event['recurrence']) {
|
||||
$recurrence = new Horde_Date_Recurrence($event['start']);
|
||||
$recurrence->fromRRule20(calendar::to_rrule($event['recurrence']));
|
||||
|
||||
foreach ((array)$event['recurrence']['EXDATE'] as $exdate)
|
||||
$recurrence->addException(date('Y', $exdate), date('n', $exdate), date('j', $exdate));
|
||||
|
||||
$duration = $event['end'] - $event['start'];
|
||||
$next = new Horde_Date($event['start']);
|
||||
$i = 1;
|
||||
while ($next = $recurrence->nextActiveRecurrence(array('year' => $next->year, 'month' => $next->month, 'mday' => $next->mday + 1, 'hour' => $next->hour, 'min' => $next->min, 'sec' => $next->sec))) {
|
||||
$rec_start = $next->timestamp();
|
||||
$rec_end = $rec_start + $duration;
|
||||
|
||||
// add to output if in range
|
||||
if ($rec_start <= $end && $rec_end >= $start) {
|
||||
$rec_event = $event;
|
||||
$rec_event['id'] .= '-' . $i++;
|
||||
$rec_event['recurrence_id'] = $event['id'];
|
||||
$rec_event['start'] = $rec_start;
|
||||
$rec_event['end'] = $rec_end;
|
||||
$events[] = $rec_event;
|
||||
}
|
||||
else if ($rec_start > $end) // stop loop if out of range
|
||||
break;
|
||||
}
|
||||
$events = array_merge($events, $this->_get_recurring_events($event, $start, $end));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,6 +317,52 @@ class kolab_calendar
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create instances of a recurring event
|
||||
*/
|
||||
private function _get_recurring_events($event, $start, $end, $event_id = null)
|
||||
{
|
||||
// use Horde classes to compute recurring instances
|
||||
require_once 'Horde/Date/Recurrence.php';
|
||||
|
||||
$recurrence = new Horde_Date_Recurrence($event['start']);
|
||||
$recurrence->fromRRule20(calendar::to_rrule($event['recurrence']));
|
||||
|
||||
foreach ((array)$event['recurrence']['EXDATE'] as $exdate)
|
||||
$recurrence->addException(date('Y', $exdate), date('n', $exdate), date('j', $exdate));
|
||||
|
||||
$events = array();
|
||||
$duration = $event['end'] - $event['start'];
|
||||
$next = new Horde_Date($event['start']);
|
||||
$i = 0;
|
||||
while ($next = $recurrence->nextActiveRecurrence(array('year' => $next->year, 'month' => $next->month, 'mday' => $next->mday + 1, 'hour' => $next->hour, 'min' => $next->min, 'sec' => $next->sec))) {
|
||||
$rec_start = $next->timestamp();
|
||||
$rec_end = $rec_start + $duration;
|
||||
$rec_id = $event['id'] . '-' . ++$i;
|
||||
|
||||
// add to output if in range
|
||||
if (($rec_start <= $end && $rec_end >= $start) || ($event_id && $rec_id == $event_id)) {
|
||||
$rec_event = $event;
|
||||
$rec_event['id'] = $rec_id;
|
||||
$rec_event['recurrence_id'] = $event['id'];
|
||||
$rec_event['start'] = $rec_start;
|
||||
$rec_event['end'] = $rec_end;
|
||||
$rec_event['_instance'] = $i;
|
||||
$events[] = $rec_event;
|
||||
|
||||
if ($rec_id == $event_id) {
|
||||
$this->events[$rec_id] = $rec_event;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ($rec_start > $end) // stop loop if out of range
|
||||
break;
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from Kolab_Format to internal representation
|
||||
*/
|
||||
|
@ -394,7 +423,7 @@ class kolab_calendar
|
|||
|
||||
if ($recurrence['exclusion']) {
|
||||
foreach ((array)$recurrence['exclusion'] as $excl)
|
||||
$rrule['EXDATE'][] = strtotime($excl) - $this->cal->timezone * 3600 - date('Z'); // shift to user's timezone
|
||||
$rrule['EXDATE'][] = strtotime($excl . date(' H:i:s', $rec['start-date'])); // use time of event start
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,9 +457,12 @@ class kolab_calendar
|
|||
{
|
||||
$priority_map = $this->priority_map;
|
||||
$daymap = array('MO'=>'monday','TU'=>'tuesday','WE'=>'wednesday','TH'=>'thursday','FR'=>'friday','SA'=>'saturday','SU'=>'sunday');
|
||||
$monthmap = array('', 'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december');
|
||||
$tz_offset = $this->cal->timezone * 3600;
|
||||
|
||||
$object = array(
|
||||
// kolab => roundcube
|
||||
'uid' => $event['uid'],
|
||||
'summary' => $event['title'],
|
||||
'location' => $event['location'],
|
||||
'body' => $event['description'],
|
||||
|
@ -478,20 +510,22 @@ class kolab_calendar
|
|||
}
|
||||
|
||||
//weekly
|
||||
if ($ra['FREQ']=='WEEKLY') {
|
||||
$weekdays = split(",", $ra['BYDAY']);
|
||||
foreach ($weekdays as $days) {
|
||||
$weekly[] = $daymap[$days];
|
||||
if ($ra['FREQ'] == 'WEEKLY') {
|
||||
if ($ra['BYDAY']) {
|
||||
foreach (split(",", $ra['BYDAY']) as $day)
|
||||
$object['recurrence']['day'][] = $daymap[$day];
|
||||
}
|
||||
else {
|
||||
// use weekday of start date if empty
|
||||
$object['recurrence']['day'][] = strtolower(gmdate('l', $event['start'] + $tz_offset));
|
||||
}
|
||||
|
||||
$object['recurrence']['day'] = $weekly;
|
||||
}
|
||||
|
||||
//monthly (temporary hack to follow current Horde logic)
|
||||
if ($ra['FREQ']=='MONTHLY') {
|
||||
if ($ra['BYDAY'] == 'NaN') {
|
||||
$object['recurrence']['daynumber']=1;
|
||||
$object['recurrence']['day'] = array(date('L', $event['start']));
|
||||
if ($ra['FREQ'] == 'MONTHLY') {
|
||||
if ($ra['BYDAY'] && preg_match('/(-?[1-4])([A-Z]+)/', $ra['BYDAY'], $m)) {
|
||||
$object['recurrence']['daynumber'] = $m[1];
|
||||
$object['recurrence']['day'] = array($daymap[$m[2]]);
|
||||
$object['recurrence']['cycle'] = 'monthly';
|
||||
$object['recurrence']['type'] = 'weekday';
|
||||
}
|
||||
|
@ -502,17 +536,36 @@ class kolab_calendar
|
|||
}
|
||||
}
|
||||
|
||||
//year ???
|
||||
//yearly
|
||||
if ($ra['FREQ'] == 'YEARLY') {
|
||||
if (!$ra['BYMONTH'])
|
||||
$ra['BYMONTH'] = gmdate('n', $event['start'] + $tz_offset);
|
||||
|
||||
$object['recurrence']['cycle'] = 'yearly';
|
||||
$object['recurrence']['month'] = $monthmap[intval($ra['BYMONTH'])];
|
||||
|
||||
if ($ra['BYDAY'] && preg_match('/(-?[1-4])([A-Z]+)/', $ra['BYDAY'], $m)) {
|
||||
$object['recurrence']['type'] = 'weekday';
|
||||
$object['recurrence']['daynumber'] = $m[1];
|
||||
$object['recurrence']['day'] = array($daymap[$m[2]]);
|
||||
}
|
||||
else {
|
||||
$object['recurrence']['type'] = 'monthday';
|
||||
$object['recurrence']['daynumber'] = gmdate('j', $event['start'] + $tz_offset);
|
||||
}
|
||||
}
|
||||
|
||||
//exclusions
|
||||
$object['recurrence']['exclusion'] = (array)$ra['EXDATE'];
|
||||
foreach ((array)$ra['EXDATE'] as $excl) {
|
||||
$object['recurrence']['exclusion'][] = gmdate('Y-m-d', $excl + $tz_offset);
|
||||
}
|
||||
}
|
||||
|
||||
// whole day event
|
||||
if ($event['allday']) {
|
||||
$object['end-date'] += 60; // end is at 23:59 => jump to the next day
|
||||
$object['end-date'] += $this->cal->timezone * 3600 - date('Z'); // shift 00 times from user's timezone to server's timezone
|
||||
$object['start-date'] += $this->cal->timezone * 3600 - date('Z'); // because Horde_Kolab_Format_Date::encodeDate() uses strftime()
|
||||
$object['end-date'] += $tz_offset - date('Z'); // shift 00 times from user's timezone to server's timezone
|
||||
$object['start-date'] += $tz_offset - date('Z'); // because Horde_Kolab_Format_Date::encodeDate() uses strftime()
|
||||
$object['_is_all_day'] = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -207,14 +207,14 @@ class kolab_driver extends calendar_driver
|
|||
{
|
||||
if ($prop['id'] && ($cal = $this->calendars[$prop['id']])) {
|
||||
$folder = $cal->get_realname();
|
||||
if (rcube_kolab::folder_delete($folder)) {
|
||||
if (rcube_kolab::folder_delete($folder)) {
|
||||
// remove color in user prefs (temp. solution)
|
||||
$prefs['kolab_calendars'] = $this->rc->config->get('kolab_calendars', array());
|
||||
unset($prefs['kolab_calendars'][$prop['id']]);
|
||||
|
||||
$this->rc->user->save_prefs($prefs);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -243,10 +243,7 @@ class kolab_driver extends calendar_driver
|
|||
*/
|
||||
public function edit_event($event)
|
||||
{
|
||||
if ($storage = $this->calendars[$event['calendar']])
|
||||
return $storage->update_event($event);
|
||||
|
||||
return false;
|
||||
return $this->update_event($event);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,7 +255,7 @@ class kolab_driver extends calendar_driver
|
|||
public function move_event($event)
|
||||
{
|
||||
if (($storage = $this->calendars[$event['calendar']]) && ($ev = $storage->get_event($event['id'])))
|
||||
return $storage->update_event($event + $ev);
|
||||
return $this->update_event($event + $ev);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -272,7 +269,7 @@ class kolab_driver extends calendar_driver
|
|||
public function resize_event($event)
|
||||
{
|
||||
if (($storage = $this->calendars[$event['calendar']]) && ($ev = $storage->get_event($event['id'])))
|
||||
return $storage->update_event($event + $ev);
|
||||
return $this->update_event($event + $ev);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -286,10 +283,141 @@ class kolab_driver extends calendar_driver
|
|||
*/
|
||||
public function remove_event($event)
|
||||
{
|
||||
if (($storage = $this->calendars[$event['calendar']]) && ($ev = $storage->get_event($event['id'])))
|
||||
return $storage->delete_event($event);
|
||||
$success = false;
|
||||
|
||||
if (($storage = $this->calendars[$event['calendar']]) && ($event = $storage->get_event($event['id']))) {
|
||||
$savemode = 'all';
|
||||
$master = $event;
|
||||
|
||||
// read master if deleting a recurring event
|
||||
if ($event['recurrence'] || $event['recurrence_id']) {
|
||||
$master = $event['recurrence_id'] ? $storage->get_event($event['recurrence_id']) : $event;
|
||||
$savemode = $event['savemode'];
|
||||
}
|
||||
|
||||
switch ($savemode) {
|
||||
case 'current':
|
||||
// add exception to master event
|
||||
$master['recurrence']['EXDATE'][] = $event['start'];
|
||||
$success = $storage->update_event($master);
|
||||
break;
|
||||
|
||||
case 'future':
|
||||
if ($master['id'] != $event['id']) {
|
||||
// set until-date on master event
|
||||
$master['recurrence']['UNTIL'] = $event['start'] - 86400;
|
||||
unset($master['recurrence']['COUNT']);
|
||||
$success = $storage->update_event($master);
|
||||
break;
|
||||
}
|
||||
|
||||
default: // 'all' is default
|
||||
$success = $storage->delete_event($master);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to update an event object depending on the given savemode
|
||||
*/
|
||||
private function update_event($event)
|
||||
{
|
||||
if (!($storage = $this->calendars[$event['calendar']]))
|
||||
return false;
|
||||
|
||||
$success = false;
|
||||
$savemode = 'all';
|
||||
$old = $master = $storage->get_event($event['id']);
|
||||
|
||||
// modify a recurring event, check submitted savemode to do the right things
|
||||
if ($old['recurrence'] || $old['recurrence_id']) {
|
||||
$master = $old['recurrence_id'] ? $storage->get_event($old['recurrence_id']) : $old;
|
||||
$savemode = $event['savemode'];
|
||||
}
|
||||
|
||||
// keep saved exceptions (not submitted by the client)
|
||||
if ($old['recurrence']['EXDATE'])
|
||||
$event['recurrence']['EXDATE'] = $old['recurrence']['EXDATE'];
|
||||
|
||||
switch ($savemode) {
|
||||
case 'new':
|
||||
// save submitted data as new (non-recurring) event
|
||||
$event['recurrence'] = array();
|
||||
$event['uid'] = $this->cal->generate_uid();
|
||||
$success = $storage->insert_event($event);
|
||||
break;
|
||||
|
||||
case 'current':
|
||||
// add exception to master event
|
||||
$master['recurrence']['EXDATE'][] = $old['start'];
|
||||
$storage->update_event($master);
|
||||
|
||||
// insert new event for this occurence
|
||||
$event += $old;
|
||||
$event['recurrence'] = array();
|
||||
$event['uid'] = $this->cal->generate_uid();
|
||||
$success = $storage->insert_event($event);
|
||||
break;
|
||||
|
||||
case 'future':
|
||||
if ($master['id'] != $event['id']) {
|
||||
// set until-date on master event
|
||||
$master['recurrence']['UNTIL'] = $old['start'] - 86400;
|
||||
unset($master['recurrence']['COUNT']);
|
||||
$storage->update_event($master);
|
||||
|
||||
// save this instance as new recurring event
|
||||
$event += $old;
|
||||
$event['uid'] = $this->cal->generate_uid();
|
||||
|
||||
// if recurrence COUNT, update value to the correct number of future occurences
|
||||
if ($event['recurrence']['COUNT']) {
|
||||
$event['recurrence']['COUNT'] -= $old['_instance'];
|
||||
}
|
||||
|
||||
// remove fixed weekday, will be re-set to the new weekday in kolab_calendar::insert_event()
|
||||
if (strlen($event['recurrence']['BYDAY']) == 2)
|
||||
unset($event['recurrence']['BYDAY']);
|
||||
if ($event['recurrence']['BYMONTH'])
|
||||
unset($event['recurrence']['BYMONTH']);
|
||||
|
||||
$success = $storage->insert_event($event);
|
||||
break;
|
||||
}
|
||||
|
||||
default: // 'all' is default
|
||||
$event['id'] = $master['id'];
|
||||
$event['uid'] = $master['uid'];
|
||||
|
||||
// use start date from master but try to be smart on time or duration changes
|
||||
$old_start_date = date('Y-m-d', $old['start']);
|
||||
$old_start_time = date('H:i:s', $old['start']);
|
||||
$old_duration = $old['end'] - $old['start'];
|
||||
|
||||
$new_start_date = date('Y-m-d', $event['start']);
|
||||
$new_start_time = date('H:i:s', $event['start']);
|
||||
$new_duration = $event['end'] - $event['start'];
|
||||
|
||||
// shifted or resized
|
||||
if ($old_start_date == $new_start_date || $old_duration == $new_duration) {
|
||||
$event['start'] = $master['start'] + ($event['start'] - $old['start']);
|
||||
$event['end'] = $event['start'] + $new_duration;
|
||||
|
||||
// remove fixed weekday, will be re-set to the new weekday in kolab_calendar::update_event()
|
||||
if (strlen($event['recurrence']['BYDAY']) == 2)
|
||||
unset($event['recurrence']['BYDAY']);
|
||||
if ($event['recurrence']['BYMONTH'])
|
||||
unset($event['recurrence']['BYMONTH']);
|
||||
}
|
||||
|
||||
$success = $storage->update_event($event);
|
||||
break;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -321,7 +321,7 @@ class calendar_ui
|
|||
$select->add($this->calendar->gettext('daily'), 'DAILY');
|
||||
$select->add($this->calendar->gettext('weekly'), 'WEEKLY');
|
||||
$select->add($this->calendar->gettext('monthly'), 'MONTHLY');
|
||||
// $select->add($this->calendar->gettext('yearly'), 'YEARLY');
|
||||
$select->add($this->calendar->gettext('yearly'), 'YEARLY');
|
||||
$html = html::label('edit-frequency', $this->calendar->gettext('frequency')) . $select->show('');
|
||||
break;
|
||||
|
||||
|
@ -350,39 +350,24 @@ class calendar_ui
|
|||
case 'monthly':
|
||||
$select = $this->interval_selector(array('name' => 'interval', 'class' => 'edit-recurrence-interval', 'id' => 'edit-recurrence-interval-monthly'));
|
||||
$html = html::div($attrib, html::label(null, $this->calendar->gettext('every')) . $select->show(1) . html::span('label-after', $this->calendar->gettext('months')));
|
||||
// day of month selection
|
||||
|
||||
//hidden fields to emulate user selection:
|
||||
$input_bymonthday = new html_hiddenfield(array('name' => 'bymonthday', 'value' => 1));
|
||||
$input_byday = new html_hiddenfield(array('name' => 'byday', 'value' => 1));
|
||||
$input_bydayp = new html_hiddenfield(array('name' => 'bydayprefix', 'value' => 1));
|
||||
|
||||
$radio = new html_radiobutton(array('name' => 'repeatmode', 'class' => 'edit-recurrence-monthly-mode'));
|
||||
$table = new html_table(array('cols' => 2, 'border' => 0, 'cellpadding' => 0, 'class' => 'formtable'));
|
||||
$table->add('label', html::label(null, $radio->show('', array('value' => 'BYDAY')) . ' ' . $this->calendar->gettext('on_the_same_weekday')));
|
||||
$table->add('label', html::label(null, $radio->show('', array('value' => 'BYMONTHDAY')) . ' ' . $this->calendar->gettext('on_the_same_date')));
|
||||
$html .= $input_byday->show();
|
||||
$html .= $input_bymonthday->show();
|
||||
$html .= $input_bydayp->show();
|
||||
$html .= html::div($attrib, $table->show());
|
||||
|
||||
/*
|
||||
|
||||
/* multiple month selection is not supported by Kolab
|
||||
$checkbox = new html_radiobutton(array('name' => 'bymonthday', 'class' => 'edit-recurrence-monthly-bymonthday'));
|
||||
for ($monthdays = '', $d = 1; $d <= 31; $d++) {
|
||||
$monthdays .= html::label(array('class' => 'monthday'), $checkbox->show('', array('value' => $d)) . $d);
|
||||
$monthdays .= $d % 7 ? ' ' : html::br();
|
||||
}
|
||||
|
||||
*/
|
||||
// rule selectors
|
||||
$radio = new html_radiobutton(array('name' => 'repeatmode', 'class' => 'edit-recurrence-monthly-mode'));
|
||||
$table = new html_table(array('cols' => 2, 'border' => 0, 'cellpadding' => 0, 'class' => 'formtable'));
|
||||
$table->add('label topalign', html::label(null, $radio->show('BYMONTHDAY', array('value' => 'BYMONTHDAY')) . ' ' . $this->calendar->gettext('each')));
|
||||
$table->add('label', html::label(null, $radio->show('BYMONTHDAY', array('value' => 'BYMONTHDAY')) . ' ' . $this->calendar->gettext('onsamedate'))); // $this->calendar->gettext('each')
|
||||
$table->add(null, $monthdays);
|
||||
$table->add('label', html::label(null, $radio->show('', array('value' => 'BYDAY')) . ' ' . $this->calendar->gettext('onevery')));
|
||||
$table->add(null, $this->rrule_selectors($attrib['part']));
|
||||
|
||||
$html .= html::div($attrib, $table->show());
|
||||
*/
|
||||
|
||||
break;
|
||||
|
||||
// annually recurrence form
|
||||
|
@ -391,9 +376,10 @@ class calendar_ui
|
|||
$html = html::div($attrib, html::label(null, $this->calendar->gettext('every')) . $select->show(1) . html::span('label-after', $this->calendar->gettext('years')));
|
||||
// month selector
|
||||
$monthmap = array('','jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec');
|
||||
$checkbox = new html_checkbox(array('name' => 'bymonth', 'class' => 'edit-recurrence-yearly-bymonth'));
|
||||
$boxtype = is_a($this->calendar->driver, 'kolab_driver') ? 'radio' : 'checkbox';
|
||||
$checkbox = new html_inputfield(array('type' => $boxtype, 'name' => 'bymonth', 'class' => 'edit-recurrence-yearly-bymonth'));
|
||||
for ($months = '', $m = 1; $m <= 12; $m++) {
|
||||
$months .= html::label(array('class' => 'month'), $checkbox->show('', array('value' => $m)) . $this->calendar->gettext($monthmap[$m]));
|
||||
$months .= html::label(array('class' => 'month'), $checkbox->show(null, array('value' => $m)) . $this->calendar->gettext($monthmap[$m]));
|
||||
$months .= $m % 4 ? ' ' : html::br();
|
||||
}
|
||||
$html .= html::div($attrib + array('id' => 'edit-recurrence-yearly-bymonthblock'), $months);
|
||||
|
@ -453,10 +439,13 @@ class calendar_ui
|
|||
$this->calendar->gettext('first'),
|
||||
$this->calendar->gettext('second'),
|
||||
$this->calendar->gettext('third'),
|
||||
$this->calendar->gettext('fourth'),
|
||||
$this->calendar->gettext('last')
|
||||
$this->calendar->gettext('fourth')
|
||||
),
|
||||
array(1, 2, 3, 4, -1));
|
||||
array(1, 2, 3, 4));
|
||||
|
||||
// Kolab doesn't support 'last' but others do.
|
||||
if (!is_a($this->calendar->driver, 'kolab_driver'))
|
||||
$select_prefix->add($this->calendar->gettext('last'), -1);
|
||||
|
||||
$select_wday = new html_select(array('name' => 'byday', 'id' => "edit-recurrence-$part-byday"));
|
||||
if ($noselect) $select_wday->add($noselect, '');
|
||||
|
|
|
@ -58,8 +58,6 @@ $labels['prev_month'] = 'Previous month';
|
|||
$labels['next_year'] = 'Next year';
|
||||
$labels['next_month'] = 'Next month';
|
||||
$labels['choose_date'] = 'Choose date';
|
||||
$labels['on_the_same_date'] = 'on the same date';
|
||||
$labels['on_the_same_weekday'] = 'on the same weekday';
|
||||
|
||||
|
||||
// alarm/reminder settings
|
||||
|
@ -121,6 +119,7 @@ $labels['bydays'] = 'On';
|
|||
$labels['until'] = 'the';
|
||||
$labels['each'] = 'Each';
|
||||
$labels['onevery'] = 'On every';
|
||||
$labels['onsamedate'] = 'On the same date';
|
||||
$labels['forever'] = 'forever';
|
||||
$labels['recurrencend'] = 'until';
|
||||
$labels['forntimes'] = 'for $nr time(s)';
|
||||
|
|
Loading…
Add table
Reference in a new issue