Synchronized with upstream from git.kolab.org (v3.2.16)
This commit is contained in:
parent
84fde2ba4a
commit
a0aacd4a73
42 changed files with 1514 additions and 789 deletions
393
calendar.php
393
calendar.php
|
@ -58,9 +58,10 @@ class calendar extends rcube_plugin
|
|||
'calendar_itip_after_action' => 0,
|
||||
);
|
||||
|
||||
private $ical;
|
||||
private $itip;
|
||||
private $driver;
|
||||
// These are implemented with __get()
|
||||
// private $ical;
|
||||
// private $itip;
|
||||
// private $driver;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -68,27 +69,13 @@ class calendar extends rcube_plugin
|
|||
*/
|
||||
function init()
|
||||
{
|
||||
$this->require_plugin('libcalendaring');
|
||||
|
||||
$this->rc = rcube::get_instance();
|
||||
$this->lib = libcalendaring::get_instance();
|
||||
|
||||
$this->register_task('calendar', 'calendar');
|
||||
|
||||
// load calendar configuration
|
||||
$this->load_config();
|
||||
|
||||
// load localizations
|
||||
$this->add_texts('localization/', $this->rc->task == 'calendar' && (!$this->rc->action || $this->rc->action == 'print'));
|
||||
|
||||
$this->timezone = $this->lib->timezone;
|
||||
$this->gmt_offset = $this->lib->gmt_offset;
|
||||
$this->dst_active = $this->lib->dst_active;
|
||||
$this->timezone_offset = $this->gmt_offset / 3600 - $this->dst_active;
|
||||
|
||||
require($this->home . '/lib/calendar_ui.php');
|
||||
$this->ui = new calendar_ui($this);
|
||||
|
||||
// catch iTIP confirmation requests that don're require a valid session
|
||||
if ($this->rc->action == 'attend' && !empty($_REQUEST['_t'])) {
|
||||
$this->add_hook('startup', array($this, 'itip_attend_response'));
|
||||
|
@ -96,7 +83,7 @@ class calendar extends rcube_plugin
|
|||
else if ($this->rc->action == 'feed' && !empty($_REQUEST['_cal'])) {
|
||||
$this->add_hook('startup', array($this, 'ical_feed_export'));
|
||||
}
|
||||
else {
|
||||
else if ($this->rc->task != 'login') {
|
||||
// default startup routine
|
||||
$this->add_hook('startup', array($this, 'startup'));
|
||||
}
|
||||
|
@ -104,6 +91,26 @@ class calendar extends rcube_plugin
|
|||
$this->add_hook('user_delete', array($this, 'user_delete'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup basic plugin environment and UI
|
||||
*/
|
||||
protected function setup()
|
||||
{
|
||||
$this->require_plugin('libcalendaring');
|
||||
|
||||
$this->lib = libcalendaring::get_instance();
|
||||
$this->timezone = $this->lib->timezone;
|
||||
$this->gmt_offset = $this->lib->gmt_offset;
|
||||
$this->dst_active = $this->lib->dst_active;
|
||||
$this->timezone_offset = $this->gmt_offset / 3600 - $this->dst_active;
|
||||
|
||||
// load localizations
|
||||
$this->add_texts('localization/', $this->rc->task == 'calendar' && (!$this->rc->action || $this->rc->action == 'print'));
|
||||
|
||||
require($this->home . '/lib/calendar_ui.php');
|
||||
$this->ui = new calendar_ui($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Startup hook
|
||||
*/
|
||||
|
@ -113,6 +120,8 @@ class calendar extends rcube_plugin
|
|||
if ($this->rc->config->get('calendar_disabled', false) || !$this->rc->config->get('calendar_enabled', true))
|
||||
return;
|
||||
|
||||
$this->setup();
|
||||
|
||||
// load Calendar user interface
|
||||
if (!$this->rc->output->ajax_call && (!$this->rc->output->env['framed'] || $args['action'] == 'preview')) {
|
||||
$this->ui->init();
|
||||
|
@ -260,11 +269,15 @@ class calendar extends rcube_plugin
|
|||
/**
|
||||
* Get properties of the calendar this user has specified as default
|
||||
*/
|
||||
public function get_default_calendar($sensitivity = null)
|
||||
public function get_default_calendar($sensitivity = null, $calendars = null)
|
||||
{
|
||||
if ($calendars === null) {
|
||||
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL | calendar_driver::FILTER_WRITEABLE);
|
||||
}
|
||||
|
||||
$default_id = $this->rc->config->get('calendar_default_calendar');
|
||||
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL | calendar_driver::FILTER_WRITEABLE);
|
||||
$calendar = $calendars[$default_id] ?: null;
|
||||
$calendar = $calendars[$default_id] ?: null;
|
||||
|
||||
if (!$calendar || $sensitivity) {
|
||||
foreach ($calendars as $cal) {
|
||||
if ($sensitivity && $cal['subtype'] == $sensitivity) {
|
||||
|
@ -299,7 +312,6 @@ class calendar extends rcube_plugin
|
|||
|
||||
$this->ui->init_templates();
|
||||
$this->rc->output->add_label('lowest','low','normal','high','highest','delete','cancel','uploading','noemailwarning','close');
|
||||
$this->rc->output->add_label('libcalendaring.itipaccepted','libcalendaring.itiptentative','libcalendaring.itipdeclined','libcalendaring.itipdelegated','libcalendaring.expandattendeegroup','libcalendaring.expandattendeegroupnodata');
|
||||
|
||||
// initialize attendees autocompletion
|
||||
$this->rc->autocomplete_init();
|
||||
|
@ -307,7 +319,6 @@ class calendar extends rcube_plugin
|
|||
$this->rc->output->set_env('timezone', $this->timezone->getName());
|
||||
$this->rc->output->set_env('calendar_driver', $this->rc->config->get('calendar_driver'), false);
|
||||
$this->rc->output->set_env('calendar_resources', (bool)$this->rc->config->get('calendar_resources_driver'));
|
||||
$this->rc->output->set_env('mscolors', jqueryui::get_color_values());
|
||||
$this->rc->output->set_env('identities-selector', $this->ui->identity_select(array('id' => 'edit-identities-list', 'aria-label' => $this->gettext('roleorganizer'))));
|
||||
|
||||
$view = rcube_utils::get_input_value('view', rcube_utils::INPUT_GPC);
|
||||
|
@ -465,40 +476,42 @@ class calendar extends rcube_plugin
|
|||
// loading driver is expensive, don't do it if not needed
|
||||
$this->load_driver();
|
||||
|
||||
if (!isset($no_override['calendar_default_alarm_type'])) {
|
||||
if (!isset($no_override['calendar_default_alarm_type']) || !isset($no_override['calendar_default_alarm_offset'])) {
|
||||
if (!$p['current']) {
|
||||
$p['blocks']['view']['content'] = true;
|
||||
return $p;
|
||||
}
|
||||
|
||||
$field_id = 'rcmfd_alarm';
|
||||
$select_type = new html_select(array('name' => '_alarm_type', 'id' => $field_id));
|
||||
$select_type->add($this->gettext('none'), '');
|
||||
foreach ($this->driver->alarm_types as $type)
|
||||
$select_type->add($this->gettext(strtolower("alarm{$type}option"), 'libcalendaring'), $type);
|
||||
$alarm_type = $alarm_offset = '';
|
||||
|
||||
if (!isset($no_override['calendar_default_alarm_type'])) {
|
||||
$field_id = 'rcmfd_alarm';
|
||||
$select_type = new html_select(array('name' => '_alarm_type', 'id' => $field_id));
|
||||
$select_type->add($this->gettext('none'), '');
|
||||
|
||||
foreach ($this->driver->alarm_types as $type) {
|
||||
$select_type->add($this->rc->gettext(strtolower("alarm{$type}option"), 'libcalendaring'), $type);
|
||||
}
|
||||
|
||||
$alarm_type = $select_type->show($this->rc->config->get('calendar_default_alarm_type', ''));
|
||||
}
|
||||
|
||||
if (!isset($no_override['calendar_default_alarm_offset'])) {
|
||||
$field_id = 'rcmfd_alarm';
|
||||
$input_value = new html_inputfield(array('name' => '_alarm_value', 'id' => $field_id . 'value', 'size' => 3));
|
||||
$select_offset = new html_select(array('name' => '_alarm_offset', 'id' => $field_id . 'offset'));
|
||||
|
||||
foreach (array('-M','-H','-D','+M','+H','+D') as $trigger) {
|
||||
$select_offset->add($this->rc->gettext('trigger' . $trigger, 'libcalendaring'), $trigger);
|
||||
}
|
||||
|
||||
$preset = libcalendaring::parse_alarm_value($this->rc->config->get('calendar_default_alarm_offset', '-15M'));
|
||||
$alarm_offset = $input_value->show($preset[0]) . ' ' . $select_offset->show($preset[1]);
|
||||
}
|
||||
|
||||
$p['blocks']['view']['options']['alarmtype'] = array(
|
||||
'title' => html::label($field_id, rcube::Q($this->gettext('defaultalarmtype'))),
|
||||
'content' => $select_type->show($this->rc->config->get('calendar_default_alarm_type', '')),
|
||||
);
|
||||
}
|
||||
|
||||
if (!isset($no_override['calendar_default_alarm_offset'])) {
|
||||
if (!$p['current']) {
|
||||
$p['blocks']['view']['content'] = true;
|
||||
return $p;
|
||||
}
|
||||
|
||||
$field_id = 'rcmfd_alarm';
|
||||
$input_value = new html_inputfield(array('name' => '_alarm_value', 'id' => $field_id . 'value', 'size' => 3));
|
||||
$select_offset = new html_select(array('name' => '_alarm_offset', 'id' => $field_id . 'offset'));
|
||||
foreach (array('-M','-H','-D','+M','+H','+D') as $trigger)
|
||||
$select_offset->add($this->gettext('trigger' . $trigger, 'libcalendaring'), $trigger);
|
||||
|
||||
$preset = libcalendaring::parse_alarm_value($this->rc->config->get('calendar_default_alarm_offset', '-15M'));
|
||||
$p['blocks']['view']['options']['alarmoffset'] = array(
|
||||
'title' => html::label($field_id . 'value', rcube::Q($this->gettext('defaultalarmoffset'))),
|
||||
'content' => $input_value->show($preset[0]) . ' ' . $select_offset->show($preset[1]),
|
||||
'content' => $alarm_type . ' ' . $alarm_offset,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -510,7 +523,7 @@ class calendar extends rcube_plugin
|
|||
// default calendar selection
|
||||
$field_id = 'rcmfd_default_calendar';
|
||||
$select_cal = new html_select(array('name' => '_default_calendar', 'id' => $field_id, 'is_escaped' => true));
|
||||
foreach ((array)$this->driver->list_calendars(calendar_driver::FILTER_PERSONAL) as $id => $prop) {
|
||||
foreach ((array)$this->driver->list_calendars(calendar_driver::FILTER_PERSONAL | calendar_driver::FILTER_ACTIVE) as $id => $prop) {
|
||||
$select_cal->add($prop['name'], strval($id));
|
||||
if ($prop['default'])
|
||||
$default_calendar = $id;
|
||||
|
@ -655,13 +668,13 @@ class calendar extends rcube_plugin
|
|||
$select_type = new html_select(array('name' => '_birthdays_alarm_type', 'id' => $field_id) + $input_attrib);
|
||||
$select_type->add($this->gettext('none'), '');
|
||||
foreach ($this->driver->alarm_types as $type) {
|
||||
$select_type->add($this->gettext(strtolower("alarm{$type}option"), 'libcalendaring'), $type);
|
||||
$select_type->add($this->rc->gettext(strtolower("alarm{$type}option"), 'libcalendaring'), $type);
|
||||
}
|
||||
|
||||
$input_value = new html_inputfield(array('name' => '_birthdays_alarm_value', 'id' => $field_id . 'value', 'size' => 3) + $input_attrib);
|
||||
$select_offset = new html_select(array('name' => '_birthdays_alarm_offset', 'id' => $field_id . 'offset') + $input_attrib);
|
||||
foreach (array('-M','-H','-D') as $trigger)
|
||||
$select_offset->add($this->gettext('trigger' . $trigger, 'libcalendaring'), $trigger);
|
||||
$select_offset->add($this->rc->gettext('trigger' . $trigger, 'libcalendaring'), $trigger);
|
||||
|
||||
$preset = libcalendaring::parse_alarm_value($this->rc->config->get('calendar_birthdays_alarm_offset', '-1D'));
|
||||
$p['blocks']['birthdays']['options']['birthdays_alarmoffset'] = array(
|
||||
|
@ -786,6 +799,22 @@ class calendar extends rcube_plugin
|
|||
case "subscribe":
|
||||
if (!$this->driver->subscribe_calendar($cal))
|
||||
$this->rc->output->show_message($this->gettext('errorsaving'), 'error');
|
||||
else {
|
||||
$calendars = $this->driver->list_calendars();
|
||||
$calendar = $calendars[$cal['id']];
|
||||
|
||||
// find parent folder and check if it's a "user calendar"
|
||||
// if it's also activated we need to refresh it (#5340)
|
||||
while ($calendar['parent']) {
|
||||
if (isset($calendars[$calendar['parent']]))
|
||||
$calendar = $calendars[$calendar['parent']];
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if ($calendar['id'] != $cal['id'] && $calendar['active'] && $calendar['group'] == "other user")
|
||||
$this->rc->output->command('plugin.refresh_source', $calendar['id']);
|
||||
}
|
||||
return;
|
||||
case "search":
|
||||
$results = array();
|
||||
|
@ -989,6 +1018,7 @@ class calendar extends rcube_plugin
|
|||
$ev['attendees'] = $event['attendees'];
|
||||
$ev['free_busy'] = $event['free_busy'];
|
||||
$ev['_savemode'] = $event['_savemode'];
|
||||
$ev['comment'] = $reply_comment;
|
||||
|
||||
// send invitation to delegatee + add it as attendee
|
||||
if ($status == 'delegated' && $event['to']) {
|
||||
|
@ -1025,7 +1055,6 @@ class calendar extends rcube_plugin
|
|||
if (!$noreply) {
|
||||
$itip = $this->load_itip();
|
||||
$itip->set_sender_email($reply_sender);
|
||||
$event['comment'] = $reply_comment;
|
||||
$event['thisandfuture'] = $event['_savemode'] == 'future';
|
||||
if ($organizer && $itip->send_itip_message($event, 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status))
|
||||
$this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $organizer['name'] ? $organizer['name'] : $organizer['email']))), 'confirmation');
|
||||
|
@ -1410,7 +1439,7 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
|
||||
/**
|
||||
* Handler for check-recent requests which are accidentally sent to calendar taks
|
||||
* Handler for check-recent requests which are accidentally sent to calendar
|
||||
*/
|
||||
function check_recent()
|
||||
{
|
||||
|
@ -1437,7 +1466,7 @@ class calendar extends rcube_plugin
|
|||
{
|
||||
// Upload progress update
|
||||
if (!empty($_GET['_progress'])) {
|
||||
rcube_upload_progress();
|
||||
$this->rc->upload_progress();
|
||||
}
|
||||
|
||||
@set_time_limit(0);
|
||||
|
@ -1503,11 +1532,11 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
else {
|
||||
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
|
||||
$msg = $this->gettext(array('name' => 'filesizeerror', 'vars' => array(
|
||||
'size' => show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
|
||||
$msg = $this->rc->gettext(array('name' => 'filesizeerror', 'vars' => array(
|
||||
'size' => $this->rc->show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
|
||||
}
|
||||
else {
|
||||
$msg = $this->gettext('fileuploaderror');
|
||||
$msg = $this->rc->gettext('fileuploaderror');
|
||||
}
|
||||
|
||||
$this->rc->output->command('plugin.import_error', array('message' => $msg));
|
||||
|
@ -1649,6 +1678,7 @@ class calendar extends rcube_plugin
|
|||
|
||||
// sanity check user
|
||||
if ($this->rc->user->get_username() == $user) {
|
||||
$this->setup();
|
||||
$this->load_driver();
|
||||
$this->export_events(false);
|
||||
}
|
||||
|
@ -1662,7 +1692,6 @@ class calendar extends rcube_plugin
|
|||
exit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -1719,7 +1748,7 @@ class calendar extends rcube_plugin
|
|||
foreach ($events as $event) {
|
||||
$json[] = $this->_client_event($event, $addcss);
|
||||
}
|
||||
return json_encode($json);
|
||||
return rcube_output::json_serialize($json);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1740,15 +1769,21 @@ class calendar extends rcube_plugin
|
|||
|
||||
foreach ((array)$event['attachments'] as $k => $attachment) {
|
||||
$event['attachments'][$k]['classname'] = rcube_utils::file2class($attachment['mimetype'], $attachment['name']);
|
||||
|
||||
unset($event['attachments'][$k]['data'], $event['attachments'][$k]['content']);
|
||||
|
||||
if (!$attachment['id']) {
|
||||
$event['attachments'][$k]['id'] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// convert link URIs references into structs
|
||||
if (array_key_exists('links', $event)) {
|
||||
foreach ((array)$event['links'] as $i => $link) {
|
||||
if (strpos($link, 'imap://') === 0 && ($msgref = $this->driver->get_message_reference($link))) {
|
||||
$event['links'][$i] = $msgref;
|
||||
foreach ((array) $event['links'] as $i => $link) {
|
||||
if (strpos($link, 'imap://') === 0 && ($msgref = $this->driver->get_message_reference($link))) {
|
||||
$event['links'][$i] = $msgref;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for organizer in attendees list
|
||||
|
@ -1890,7 +1925,19 @@ class calendar extends rcube_plugin
|
|||
$rev = rcube_utils::get_input_value('_rev', rcube_utils::INPUT_GPC);
|
||||
|
||||
$event = array('id' => $event_id, 'calendar' => $calendar, 'rev' => $rev);
|
||||
$attachment = $this->driver->get_attachment($id, $event);
|
||||
|
||||
if ($calendar == '--invitation--itip') {
|
||||
$uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GPC);
|
||||
$part = rcube_utils::get_input_value('_part', rcube_utils::INPUT_GPC);
|
||||
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC);
|
||||
|
||||
$event = $this->lib->mail_get_itip_object($mbox, $uid, $part, 'event');
|
||||
$attachment = $event['attachments'][$id];
|
||||
$attachment['body'] = &$attachment['data'];
|
||||
}
|
||||
else {
|
||||
$attachment = $this->driver->get_attachment($id, $event);
|
||||
}
|
||||
|
||||
// show part page
|
||||
if (!empty($_GET['_frame'])) {
|
||||
|
@ -1901,7 +1948,10 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
// deliver attachment content
|
||||
else if ($attachment) {
|
||||
$attachment['body'] = $this->driver->get_attachment_body($id, $event);
|
||||
if ($calendar != '--invitation--itip') {
|
||||
$attachment['body'] = $this->driver->get_attachment_body($id, $event);
|
||||
}
|
||||
|
||||
$this->lib->attachment_get($attachment);
|
||||
}
|
||||
|
||||
|
@ -1925,8 +1975,8 @@ class calendar extends rcube_plugin
|
|||
private function write_preprocess(&$event, $action)
|
||||
{
|
||||
// convert dates into DateTime objects in user's current timezone
|
||||
$event['start'] = new DateTime($event['start'], $this->timezone);
|
||||
$event['end'] = new DateTime($event['end'], $this->timezone);
|
||||
$event['start'] = new DateTime($event['start'], $this->timezone);
|
||||
$event['end'] = new DateTime($event['end'], $this->timezone);
|
||||
$event['allday'] = (bool)$event['allday'];
|
||||
|
||||
// start/end is all we need for 'move' action (#1480)
|
||||
|
@ -1976,7 +2026,7 @@ class calendar extends rcube_plugin
|
|||
foreach ((array)$event['attendees'] as $i => $attendee) {
|
||||
if ($attendee['role'] == 'ORGANIZER')
|
||||
$organizer = $i;
|
||||
if ($attendee['email'] == in_array(strtolower($attendee['email']), $emails))
|
||||
if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails))
|
||||
$owner = $i;
|
||||
if (!isset($attendee['rsvp']))
|
||||
$event['attendees'][$i]['rsvp'] = true;
|
||||
|
@ -1984,17 +2034,28 @@ class calendar extends rcube_plugin
|
|||
$event['attendees'][$i]['rsvp'] = $attendee['rsvp'] == 'true' || $attendee['rsvp'] == '1';
|
||||
}
|
||||
|
||||
if (!empty($event['_identity'])) {
|
||||
$identity = $this->rc->user->get_identity($event['_identity']);
|
||||
}
|
||||
|
||||
// set new organizer identity
|
||||
if ($organizer !== false && !empty($event['_identity']) && ($identity = $this->rc->user->get_identity($event['_identity']))) {
|
||||
if ($organizer !== false && $identity) {
|
||||
$event['attendees'][$organizer]['name'] = $identity['name'];
|
||||
$event['attendees'][$organizer]['email'] = $identity['email'];
|
||||
}
|
||||
|
||||
// set owner as organizer if yet missing
|
||||
if ($organizer === false && $owner !== false) {
|
||||
else if ($organizer === false && $owner !== false) {
|
||||
$event['attendees'][$owner]['role'] = 'ORGANIZER';
|
||||
unset($event['attendees'][$owner]['rsvp']);
|
||||
}
|
||||
// fallback to the selected identity
|
||||
else if ($organizer === false && $identity) {
|
||||
$event['attendees'][] = array(
|
||||
'role' => 'ORGANIZER',
|
||||
'name' => $identity['name'],
|
||||
'email' => $identity['email'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// mapping url => vurl because of the fullcalendar client script
|
||||
|
@ -2128,6 +2189,7 @@ class calendar extends rcube_plugin
|
|||
|
||||
// if the backend has free-busy information
|
||||
$fblist = $this->driver->get_freebusy_list($email, $start, $end);
|
||||
|
||||
if (is_array($fblist)) {
|
||||
$status = 'FREE';
|
||||
|
||||
|
@ -2141,7 +2203,7 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
|
||||
// let this information be cached for 5min
|
||||
send_future_expire_header(300);
|
||||
$this->rc->output->future_expire_header(300);
|
||||
|
||||
echo $status;
|
||||
exit;
|
||||
|
@ -2177,13 +2239,26 @@ class calendar extends rcube_plugin
|
|||
$dts = new DateTime('@'.$start);
|
||||
$dts->setTimezone($this->timezone);
|
||||
}
|
||||
|
||||
|
||||
$fblist = $this->driver->get_freebusy_list($email, $start, $end);
|
||||
$slots = array();
|
||||
|
||||
$slots = '';
|
||||
|
||||
// prepare freebusy list before use (for better performance)
|
||||
if (is_array($fblist)) {
|
||||
foreach ($fblist as $idx => $slot) {
|
||||
list($from, $to, ) = $slot;
|
||||
|
||||
// check for possible all-day times
|
||||
if (gmdate('His', $from) == '000000' && gmdate('His', $to) == '235959') {
|
||||
// shift into the user's timezone for sane matching
|
||||
$fblist[$idx][0] -= $this->gmt_offset;
|
||||
$fblist[$idx][1] -= $this->gmt_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build a list from $start till $end with blocks representing the fb-status
|
||||
for ($s = 0, $t = $start; $t <= $end; $s++) {
|
||||
$status = self::FREEBUSY_UNKNOWN;
|
||||
$t_end = $t + $interval * 60;
|
||||
$dt = new DateTime('@'.$t);
|
||||
$dt->setTimezone($this->timezone);
|
||||
|
@ -2191,16 +2266,10 @@ class calendar extends rcube_plugin
|
|||
// determine attendee's status
|
||||
if (is_array($fblist)) {
|
||||
$status = self::FREEBUSY_FREE;
|
||||
|
||||
foreach ($fblist as $slot) {
|
||||
list($from, $to, $type) = $slot;
|
||||
|
||||
// check for possible all-day times
|
||||
if (gmdate('His', $from) == '000000' && gmdate('His', $to) == '235959') {
|
||||
// shift into the user's timezone for sane matching
|
||||
$from -= $this->gmt_offset;
|
||||
$to -= $this->gmt_offset;
|
||||
}
|
||||
|
||||
if ($from < $t_end && $to > $t) {
|
||||
$status = isset($type) ? $type : self::FREEBUSY_BUSY;
|
||||
if ($status == self::FREEBUSY_BUSY) // can't get any worse :-)
|
||||
|
@ -2208,9 +2277,12 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
$slots[$s] = $status;
|
||||
$times[$s] = intval($dt->format($strformat));
|
||||
else {
|
||||
$status = self::FREEBUSY_UNKNOWN;
|
||||
}
|
||||
|
||||
// use most compact format, assume $status is one digit/character
|
||||
$slots .= $status;
|
||||
$t = $t_end;
|
||||
}
|
||||
|
||||
|
@ -2218,15 +2290,14 @@ class calendar extends rcube_plugin
|
|||
$dte->setTimezone($this->timezone);
|
||||
|
||||
// let this information be cached for 5min
|
||||
send_future_expire_header(300);
|
||||
$this->rc->output->future_expire_header(300);
|
||||
|
||||
echo json_encode(array(
|
||||
echo rcube_output::json_serialize(array(
|
||||
'email' => $email,
|
||||
'start' => $dts->format('c'),
|
||||
'end' => $dte->format('c'),
|
||||
'interval' => $interval,
|
||||
'slots' => $slots,
|
||||
'times' => $times,
|
||||
));
|
||||
exit;
|
||||
}
|
||||
|
@ -2288,12 +2359,12 @@ class calendar extends rcube_plugin
|
|||
$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('calendars', " . rcube_output::json_serialize($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.gui_object('attachmentlist', '" . $this->ui->attachmentlist_id . "');\n".
|
||||
"rcmail.add_label(" . json_encode($texts) . ");\n"
|
||||
"rcmail.add_label(" . rcube_output::json_serialize($texts) . ");\n"
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
@ -2457,6 +2528,27 @@ class calendar extends rcube_plugin
|
|||
|
||||
/**** Event invitation plugin hooks ****/
|
||||
|
||||
/**
|
||||
* Find an event in user calendars
|
||||
*/
|
||||
protected function find_event($event, &$mode)
|
||||
{
|
||||
$this->load_driver();
|
||||
|
||||
// We search for writeable calendars in personal namespace by default
|
||||
$mode = calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_PERSONAL;
|
||||
$result = $this->driver->get_event($event, $mode);
|
||||
// ... now check shared folders if not found
|
||||
if (!$result) {
|
||||
$result = $this->driver->get_event($event, calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_SHARED);
|
||||
if ($result) {
|
||||
$mode |= calendar_driver::FILTER_SHARED;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for calendar/itip-status requests
|
||||
*/
|
||||
|
@ -2464,16 +2556,20 @@ class calendar extends rcube_plugin
|
|||
{
|
||||
$data = rcube_utils::get_input_value('data', rcube_utils::INPUT_POST, true);
|
||||
|
||||
// find local copy of the referenced event
|
||||
$this->load_driver();
|
||||
$existing = $this->driver->get_event($data, calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_PERSONAL);
|
||||
|
||||
$itip = $this->load_itip();
|
||||
$response = $itip->get_itip_status($data, $existing);
|
||||
// find local copy of the referenced event (in personal namespace)
|
||||
$existing = $this->find_event($data, $mode);
|
||||
$is_shared = $mode & calendar_driver::FILTER_SHARED;
|
||||
$itip = $this->load_itip();
|
||||
$response = $itip->get_itip_status($data, $existing);
|
||||
|
||||
// get a list of writeable calendars to save new events to
|
||||
if (!$existing && !$data['nosave'] && $response['action'] == 'rsvp' || $response['action'] == 'import') {
|
||||
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL);
|
||||
if ((!$existing || $is_shared)
|
||||
&& !$data['nosave']
|
||||
&& ($response['action'] == 'rsvp' || $response['action'] == 'import')
|
||||
) {
|
||||
$calendars = $this->driver->list_calendars($mode);
|
||||
$calendar_select = new html_select(array('name' => 'calendar', 'id' => 'itip-saveto', 'is_escaped' => true));
|
||||
$calendar_select->add('--', '');
|
||||
$numcals = 0;
|
||||
|
@ -2483,14 +2579,14 @@ class calendar extends rcube_plugin
|
|||
$numcals++;
|
||||
}
|
||||
}
|
||||
if ($numcals <= 1)
|
||||
if ($numcals < 1)
|
||||
$calendar_select = null;
|
||||
}
|
||||
|
||||
if ($calendar_select) {
|
||||
$default_calendar = $this->get_default_calendar($data['sensitivity']);
|
||||
$default_calendar = $this->get_default_calendar($data['sensitivity'], $calendars);
|
||||
$response['select'] = html::span('folder-select', $this->gettext('saveincalendar') . ' ' .
|
||||
$calendar_select->show($default_calendar['id']));
|
||||
$calendar_select->show($is_shared ? $existing['calendar'] : $default_calendar['id']));
|
||||
}
|
||||
else if ($data['nosave']) {
|
||||
$response['select'] = html::tag('input', array('type' => 'hidden', 'name' => 'calendar', 'id' => 'itip-saveto', 'value' => ''));
|
||||
|
@ -2539,9 +2635,10 @@ class calendar extends rcube_plugin
|
|||
$uid = rcube_utils::get_input_value('uid', rcube_utils::INPUT_POST);
|
||||
$instance = rcube_utils::get_input_value('_instance', rcube_utils::INPUT_POST);
|
||||
$savemode = rcube_utils::get_input_value('_savemode', rcube_utils::INPUT_POST);
|
||||
$listmode = calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_PERSONAL;
|
||||
|
||||
// search for event if only UID is given
|
||||
if ($event = $this->driver->get_event(array('uid' => $uid, '_instance' => $instance), calendar_driver::FILTER_WRITEABLE)) {
|
||||
if ($event = $this->driver->get_event(array('uid' => $uid, '_instance' => $instance), $listmode)) {
|
||||
$event['_savemode'] = $savemode;
|
||||
$success = $this->driver->remove_event($event, true);
|
||||
}
|
||||
|
@ -2559,6 +2656,8 @@ class calendar extends rcube_plugin
|
|||
*/
|
||||
public function itip_attend_response($p)
|
||||
{
|
||||
$this->setup();
|
||||
|
||||
if ($p['action'] == 'attend') {
|
||||
$this->ui->init();
|
||||
|
||||
|
@ -2772,17 +2871,17 @@ class calendar extends rcube_plugin
|
|||
$noreply = $noreply || $status == 'needs-action' || $itip_sending === 0;
|
||||
$instance = rcube_utils::get_input_value('_instance', rcube_utils::INPUT_POST);
|
||||
$savemode = rcube_utils::get_input_value('_savemode', rcube_utils::INPUT_POST);
|
||||
$comment = rcube_utils::get_input_value('_comment', rcube_utils::INPUT_POST);
|
||||
|
||||
$error_msg = $this->gettext('errorimportingevent');
|
||||
$success = false;
|
||||
$delegate = null;
|
||||
$success = false;
|
||||
|
||||
if ($status == 'delegated') {
|
||||
$delegates = rcube_mime::decode_address_list(rcube_utils::get_input_value('_to', rcube_utils::INPUT_POST, true), 1, false);
|
||||
$delegate = reset($delegates);
|
||||
|
||||
if (empty($delegate) || empty($delegate['mailto'])) {
|
||||
$this->rc->output->command('display_message', $this->gettext('libcalendaring.delegateinvalidaddress'), 'error');
|
||||
$this->rc->output->command('display_message', $this->rc->gettext('libcalendaring.delegateinvalidaddress'), 'error');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2791,29 +2890,37 @@ class calendar extends rcube_plugin
|
|||
if ($event = $this->lib->mail_get_itip_object($mbox, $uid, $mime_id, 'event')) {
|
||||
// forward iTip request to delegatee
|
||||
if ($delegate) {
|
||||
$rsvpme = intval(rcube_utils::get_input_value('_rsvp', rcube_utils::INPUT_POST));
|
||||
$rsvpme = rcube_utils::get_input_value('_rsvp', rcube_utils::INPUT_POST);
|
||||
$itip = $this->load_itip();
|
||||
|
||||
$itip = $this->load_itip();
|
||||
if ($itip->delegate_to($event, $delegate, $rsvpme ? true : false)) {
|
||||
$event['comment'] = $comment;
|
||||
|
||||
if ($itip->delegate_to($event, $delegate, !empty($rsvpme))) {
|
||||
$this->rc->output->show_message('calendar.itipsendsuccess', 'confirmation');
|
||||
}
|
||||
else {
|
||||
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
|
||||
}
|
||||
|
||||
unset($event['comment']);
|
||||
|
||||
// the delegator is set to non-participant, thus save as non-blocking
|
||||
$event['free_busy'] = 'free';
|
||||
}
|
||||
|
||||
$mode = calendar_driver::FILTER_PERSONAL
|
||||
| calendar_driver::FILTER_SHARED
|
||||
| calendar_driver::FILTER_WRITEABLE;
|
||||
|
||||
// find writeable calendar to store event
|
||||
$cal_id = !empty($_REQUEST['_folder']) ? rcube_utils::get_input_value('_folder', rcube_utils::INPUT_POST) : null;
|
||||
$dontsave = ($_REQUEST['_folder'] === '' && $event['_method'] == 'REQUEST');
|
||||
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL);
|
||||
$calendar = $calendars[$cal_id];
|
||||
$cal_id = rcube_utils::get_input_value('_folder', rcube_utils::INPUT_POST);
|
||||
$dontsave = $cal_id === '' && $event['_method'] == 'REQUEST';
|
||||
$calendars = $this->driver->list_calendars($mode);
|
||||
$calendar = $calendars[$cal_id];
|
||||
|
||||
// select default calendar except user explicitly selected 'none'
|
||||
if (!$calendar && !$dontsave)
|
||||
$calendar = $this->get_default_calendar($event['sensitivity']);
|
||||
$calendar = $this->get_default_calendar($event['sensitivity'], $calendars);
|
||||
|
||||
$metadata = array(
|
||||
'uid' => $event['uid'],
|
||||
|
@ -2861,9 +2968,16 @@ class calendar extends rcube_plugin
|
|||
// save to calendar
|
||||
if ($calendar && $calendar['editable']) {
|
||||
// check for existing event with the same UID
|
||||
$existing = $this->driver->get_event($event, calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_PERSONAL);
|
||||
$existing = $this->find_event($event, $mode);
|
||||
|
||||
// we'll create a new copy if user decided to change the calendar
|
||||
if ($existing && $cal_id && $calendar && $calendar['id'] != $existing['calendar']) {
|
||||
$existing = null;
|
||||
}
|
||||
|
||||
if ($existing) {
|
||||
$calendar = $calendars[$existing['calendar']];
|
||||
|
||||
// forward savemode for correct updates of recurring events
|
||||
$existing['_savemode'] = $savemode ?: $event['_savemode'];
|
||||
|
||||
|
@ -2874,14 +2988,14 @@ class calendar extends rcube_plugin
|
|||
$existing_attendee_emails = array();
|
||||
foreach ($existing['attendees'] as $i => $attendee) {
|
||||
$existing_attendee_emails[] = $attendee['email'];
|
||||
if ($event['_sender'] && ($attendee['email'] == $event['_sender'] || $attendee['email'] == $event['_sender_utf'])) {
|
||||
if ($this->itip->compare_email($attendee['email'], $event['_sender'], $event['_sender_utf'])) {
|
||||
$existing_attendee = $i;
|
||||
}
|
||||
}
|
||||
$event_attendee = null;
|
||||
$update_attendees = array();
|
||||
foreach ($event['attendees'] as $attendee) {
|
||||
if ($event['_sender'] && ($attendee['email'] == $event['_sender'] || $attendee['email'] == $event['_sender_utf'])) {
|
||||
if ($this->itip->compare_email($attendee['email'], $event['_sender'], $event['_sender_utf'])) {
|
||||
$event_attendee = $attendee;
|
||||
$update_attendees[] = $attendee;
|
||||
$metadata['fallback'] = $attendee['status'];
|
||||
|
@ -2892,11 +3006,11 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
}
|
||||
// also copy delegate attendee
|
||||
else if (!empty($attendee['delegated-from']) &&
|
||||
(stripos($attendee['delegated-from'], $event['_sender']) !== false ||
|
||||
stripos($attendee['delegated-from'], $event['_sender_utf']) !== false)) {
|
||||
else if (!empty($attendee['delegated-from'])
|
||||
&& $this->itip->compare_email($attendee['delegated-from'], $event['_sender'], $event['_sender_utf'])
|
||||
) {
|
||||
$update_attendees[] = $attendee;
|
||||
if (!in_array($attendee['email'], $existing_attendee_emails)) {
|
||||
if (!in_array_nocase($attendee['email'], $existing_attendee_emails)) {
|
||||
$existing['attendees'][] = $attendee;
|
||||
}
|
||||
}
|
||||
|
@ -2936,24 +3050,20 @@ class calendar extends rcube_plugin
|
|||
$event['id'] = $existing['id'];
|
||||
$event['calendar'] = $existing['calendar'];
|
||||
|
||||
// preserve my participant status for regular updates
|
||||
if (empty($status)) {
|
||||
$emails = $this->get_user_emails();
|
||||
foreach ($event['attendees'] as $i => $attendee) {
|
||||
if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) {
|
||||
foreach ($existing['attendees'] as $j => $_attendee) {
|
||||
if ($attendee['email'] == $_attendee['email']) {
|
||||
$event['attendees'][$i] = $existing['attendees'][$j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// merge attendees status
|
||||
// e.g. preserve my participant status for regular updates
|
||||
$this->lib->merge_attendees($event, $existing, $status);
|
||||
|
||||
// set status=CANCELLED on CANCEL messages
|
||||
if ($event['_method'] == 'CANCEL')
|
||||
$event['status'] = 'CANCELLED';
|
||||
|
||||
// update attachments list, allow attachments update only on REQUEST (#5342)
|
||||
if ($event['_method'] == 'REQUEST')
|
||||
$event['deleted_attachments'] = true;
|
||||
else
|
||||
unset($event['attachments']);
|
||||
|
||||
// show me as free when declined (#1670)
|
||||
if ($status == 'declined' || $event['status'] == 'CANCELLED' || $event_attendee['role'] == 'NON-PARTICIPANT')
|
||||
$event['free_busy'] = 'free';
|
||||
|
@ -3039,7 +3149,7 @@ class calendar extends rcube_plugin
|
|||
|
||||
// send iTip reply
|
||||
if ($event['_method'] == 'REQUEST' && $organizer && !$noreply && !in_array(strtolower($organizer['email']), $emails) && !$error_msg) {
|
||||
$event['comment'] = rcube_utils::get_input_value('_comment', rcube_utils::INPUT_POST);
|
||||
$event['comment'] = $comment;
|
||||
$itip = $this->load_itip();
|
||||
$itip->set_sender_email($reply_sender);
|
||||
if ($itip->send_itip_message($event, 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status))
|
||||
|
@ -3051,7 +3161,6 @@ class calendar extends rcube_plugin
|
|||
$this->rc->output->send();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for calendar/itip-remove requests
|
||||
*/
|
||||
|
@ -3104,7 +3213,7 @@ class calendar extends rcube_plugin
|
|||
|
||||
// establish imap connection
|
||||
$imap = $this->rc->get_storage();
|
||||
$imap->set_mailbox($mbox);
|
||||
$imap->set_folder($mbox);
|
||||
|
||||
if ($uid && $mime_id) {
|
||||
$part = $imap->get_message_part($uid, $mime_id);
|
||||
|
@ -3164,7 +3273,7 @@ class calendar extends rcube_plugin
|
|||
|
||||
// establish imap connection
|
||||
$imap = $this->rc->get_storage();
|
||||
$imap->set_mailbox($mbox);
|
||||
$imap->set_folder($mbox);
|
||||
$message = new rcube_message($uid);
|
||||
|
||||
if ($message->headers) {
|
||||
|
@ -3241,7 +3350,12 @@ class calendar extends rcube_plugin
|
|||
$tmp_path = tempnam($this->rc->config->get('temp_dir'), 'rcmAttmntCal');
|
||||
file_put_contents($tmp_path, $this->get_ical()->export(array($event), '', false, array($this->driver, 'get_attachment_body')));
|
||||
|
||||
$args['attachments'][] = array('path' => $tmp_path, 'name' => $filename . '.ics', 'mimetype' => 'text/calendar');
|
||||
$args['attachments'][] = array(
|
||||
'path' => $tmp_path,
|
||||
'name' => $filename . '.ics',
|
||||
'mimetype' => 'text/calendar',
|
||||
'size' => filesize($tmp_path),
|
||||
);
|
||||
$args['param']['subject'] = $event['title'];
|
||||
}
|
||||
}
|
||||
|
@ -3284,6 +3398,7 @@ class calendar extends rcube_plugin
|
|||
$table_itipinvitations = $db->table_name('itipinvitations', true);
|
||||
$db->query("DELETE FROM $table_itipinvitations WHERE `user_id` = ?", $args['user']->ID);
|
||||
|
||||
$this->setup();
|
||||
$this->load_driver();
|
||||
return $this->driver->user_delete($args);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ function rcube_calendar(settings)
|
|||
rcube_libcalendaring.call(this, settings);
|
||||
|
||||
// member vars
|
||||
this.ui;
|
||||
this.ui_loaded = false;
|
||||
this.selected_attachment = null;
|
||||
|
||||
|
@ -50,29 +49,29 @@ function rcube_calendar(settings)
|
|||
$.when(
|
||||
$.getScript(rcmail.assets_path('plugins/calendar/calendar_ui.js')),
|
||||
$.getScript(rcmail.assets_path('plugins/calendar/lib/js/fullcalendar.js')),
|
||||
$.get(rcmail.url('calendar/inlineui'), function(html){ $(document.body).append(html); }, 'html')
|
||||
$.get(rcmail.url('calendar/inlineui'), function(html) { $(document.body).append(html); }, 'html')
|
||||
).then(function() {
|
||||
// disable attendees feature (autocompletion and stuff is not initialized)
|
||||
for (var c in rcmail.env.calendars)
|
||||
rcmail.env.calendars[c].attendees = rcmail.env.calendars[c].resources = false;
|
||||
|
||||
|
||||
me.ui_loaded = true;
|
||||
me.ui = new rcube_calendar_ui(me.settings);
|
||||
me.create_from_mail(uid); // 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);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -91,7 +90,7 @@ function rcube_calendar(settings)
|
|||
rcmail.http_post('calendar/mailimportattach', {
|
||||
_uid: rcmail.env.uid,
|
||||
_mbox: rcmail.env.mailbox,
|
||||
_part: this.selected_attachment,
|
||||
_part: this.selected_attachment
|
||||
// _calendar: $('#calendar-attachment-saveto').val(),
|
||||
}, rcmail.set_busy(true, 'itip.savingdata'));
|
||||
}
|
||||
|
@ -106,11 +105,11 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
|
|||
|
||||
// register create-from-mail command to message_commands array
|
||||
if (rcmail.env.task == 'mail') {
|
||||
rcmail.register_command('calendar-create-from-mail', function() { cal.create_from_mail() });
|
||||
rcmail.register_command('attachment-save-calendar', function() { cal.save_to_calendar() });
|
||||
rcmail.addEventListener('plugin.mail2event_dialog', function(p){ cal.mail2event_dialog(p) });
|
||||
rcmail.addEventListener('plugin.unlock_saving', function(p){ cal.ui && cal.ui.unlock_saving(); });
|
||||
|
||||
rcmail.register_command('calendar-create-from-mail', function() { cal.create_from_mail(); });
|
||||
rcmail.register_command('attachment-save-calendar', function() { cal.save_to_calendar(); });
|
||||
rcmail.addEventListener('plugin.mail2event_dialog', function(p) { cal.mail2event_dialog(p); });
|
||||
rcmail.addEventListener('plugin.unlock_saving', function(p) { cal.ui && cal.ui.unlock_saving(); });
|
||||
|
||||
if (rcmail.env.action != 'show') {
|
||||
rcmail.env.message_commands.push('calendar-create-from-mail');
|
||||
rcmail.add_element($('<a>'));
|
||||
|
@ -130,8 +129,8 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
|
|||
}
|
||||
|
||||
rcmail.register_command('plugin.calendar', function() { rcmail.switch_task('calendar'); }, true);
|
||||
|
||||
rcmail.addEventListener('plugin.ping_url', function(p){
|
||||
|
||||
rcmail.addEventListener('plugin.ping_url', function(p) {
|
||||
var action = p.action;
|
||||
p.action = p.event = null;
|
||||
new Image().src = rcmail.url(action, p);
|
||||
|
|
430
calendar_ui.js
430
calendar_ui.js
|
@ -38,7 +38,7 @@ function rcube_calendar_ui(settings)
|
|||
this.selected_event = null;
|
||||
this.selected_calendar = null;
|
||||
this.search_request = null;
|
||||
this.saving_lock;
|
||||
this.saving_lock = null;
|
||||
this.calendars = {};
|
||||
this.quickview_sources = [];
|
||||
|
||||
|
@ -197,18 +197,18 @@ function rcube_calendar_ui(settings)
|
|||
{
|
||||
var result = [],
|
||||
strlen = str.length,
|
||||
q, p, i, char, last;
|
||||
q, p, i, chr, last;
|
||||
|
||||
for (q = p = i = 0; i < strlen; i++) {
|
||||
char = str.charAt(i);
|
||||
if (char == '"' && last != '\\') {
|
||||
chr = str.charAt(i);
|
||||
if (chr == '"' && last != '\\') {
|
||||
q = !q;
|
||||
}
|
||||
else if (!q && char == delimiter) {
|
||||
else if (!q && chr == delimiter) {
|
||||
result.push(str.substring(p, i));
|
||||
p = i + 1;
|
||||
}
|
||||
last = char;
|
||||
last = chr;
|
||||
}
|
||||
|
||||
result.push(str.substr(p));
|
||||
|
@ -335,6 +335,9 @@ function rcube_calendar_ui(settings)
|
|||
if (event.rev)
|
||||
query._rev = event.rev;
|
||||
|
||||
if (event.calendar == "--invitation--itip")
|
||||
$.extend(query, {_uid: event._uid, _part: event._part, _mbox: event._mbox});
|
||||
|
||||
// open attachment in frame if it's of a supported mimetype
|
||||
if (id && att.mimetype && $.inArray(att.mimetype, settings.mimetypes)>=0) {
|
||||
if (rcmail.open_window(rcmail.url('get-attachment', query), true, true)) {
|
||||
|
@ -420,7 +423,7 @@ function rcube_calendar_ui(settings)
|
|||
if ($dialog.is(':ui-dialog'))
|
||||
$dialog.dialog('close');
|
||||
|
||||
// remove status-* classes
|
||||
// remove status-* and sensitivity-* classes
|
||||
$dialog.removeClass(function(i, oldclass) {
|
||||
var oldies = String(oldclass).split(' ');
|
||||
return $.grep(oldies, function(cls) { return cls.indexOf('status-') === 0 || cls.indexOf('sensitivity-') === 0 }).join(' ');
|
||||
|
@ -468,11 +471,13 @@ function rcube_calendar_ui(settings)
|
|||
|
||||
if (event.status) {
|
||||
var status_lc = String(event.status).toLowerCase();
|
||||
$('#event-status').show().children('.event-text').html(Q(rcmail.gettext('status-'+status_lc,'calendar')));
|
||||
$('#event-status').show().children('.event-text').text(rcmail.gettext('status-'+status_lc,'calendar'));
|
||||
$('#event-status-badge > span').text(rcmail.gettext('status-'+status_lc,'calendar'));
|
||||
$dialog.addClass('status-'+status_lc);
|
||||
}
|
||||
if (event.sensitivity && event.sensitivity != 'public') {
|
||||
$('#event-sensitivity').show().children('.event-text').html(Q(sensitivitylabels[event.sensitivity]));
|
||||
$('#event-sensitivity').show().children('.event-text').text(sensitivitylabels[event.sensitivity]);
|
||||
$('#event-status-badge > span').text(sensitivitylabels[event.sensitivity]);
|
||||
$dialog.addClass('sensitivity-'+event.sensitivity);
|
||||
}
|
||||
if (event.created || event.changed) {
|
||||
|
@ -510,7 +515,7 @@ function rcube_calendar_ui(settings)
|
|||
return (j - k);
|
||||
});
|
||||
|
||||
var data, mystatus = null, rsvp, line, morelink, html = '', overflow = '';
|
||||
var data, organizer, mystatus = null, rsvp, line, morelink, html = '', overflow = '';
|
||||
for (var j=0; j < event.attendees.length; j++) {
|
||||
data = event.attendees[j];
|
||||
if (data.email) {
|
||||
|
@ -523,7 +528,7 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
}
|
||||
|
||||
line = event_attendee_html(data);
|
||||
line = rcube_libcalendaring.attendee_html(data);
|
||||
|
||||
if (morelink)
|
||||
overflow += line;
|
||||
|
@ -562,7 +567,7 @@ function rcube_calendar_ui(settings)
|
|||
.removeClass('accepted tentative declined delegated needs-action')
|
||||
.addClass(mystatus)
|
||||
.children('.event-text')
|
||||
.html(Q(rcmail.gettext('itip' + mystatus, 'libcalendaring')));
|
||||
.text(rcmail.gettext('status' + mystatus, 'libcalendaring'));
|
||||
}
|
||||
|
||||
var show_rsvp = rsvp && !is_organizer(event) && event.status != 'CANCELLED' && has_permission(calendar, 'v');
|
||||
|
@ -666,24 +671,8 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
|
||||
rcmail.enable_command('event-history', calendar.history)
|
||||
};
|
||||
|
||||
// render HTML code for displaying an attendee record
|
||||
var event_attendee_html = function(data)
|
||||
{
|
||||
var dispname = Q(data.name || data.email), tooltip = '';
|
||||
|
||||
if (data.email) {
|
||||
tooltip = data.email + '; ' + data.status;
|
||||
dispname = '<a href="mailto:' + data.email + '" class="mailtolink" data-cutype="' + data.cutype + '">' + dispname + '</a>';
|
||||
}
|
||||
|
||||
if (data['delegated-to'])
|
||||
tooltip = rcmail.gettext('delegatedto', 'calendar') + data['delegated-to'];
|
||||
else if (data['delegated-from'])
|
||||
tooltip = rcmail.gettext('delegatedfrom', 'calendar') + data['delegated-from'];
|
||||
|
||||
return '<span class="attendee ' + String(data.role == 'ORGANIZER' ? 'organizer' : data.status).toLowerCase() + '" title="' + Q(tooltip) + '">' + dispname + '</span> ';
|
||||
rcmail.triggerEvent('calendar-event-dialog', {dialog: $dialog});
|
||||
};
|
||||
|
||||
// event handler for clicks on an attendee link
|
||||
|
@ -797,8 +786,8 @@ function rcube_calendar_ui(settings)
|
|||
event_attendees = [];
|
||||
attendees_list = $('#edit-attendees-table > tbody').html('');
|
||||
resources_list = $('#edit-resources-table > tbody').html('');
|
||||
$('#edit-attendees-notify')[(allow_invitations && has_attendees(event) && (settings.itip_notify & 2) ? 'show' : 'hide')]();
|
||||
$('#edit-localchanges-warning')[(has_attendees(event) && !(allow_invitations || (calendar.owner && is_organizer(event, calendar.owner))) ? 'show' : 'hide')]();
|
||||
$('#edit-attendees-notify')[(action != 'new' && allow_invitations && has_attendees(event) && (settings.itip_notify & 2) ? 'show' : 'hide')]();
|
||||
$('#edit-localchanges-warning')[(action != 'new' && has_attendees(event) && !(allow_invitations || (calendar.owner && is_organizer(event, calendar.owner))) ? 'show' : 'hide')]();
|
||||
|
||||
var load_attendees_tab = function()
|
||||
{
|
||||
|
@ -902,13 +891,9 @@ function rcube_calendar_ui(settings)
|
|||
if (data.attendees[i])
|
||||
data.attendees[i].role = $(elem).val();
|
||||
});
|
||||
|
||||
|
||||
if (organizer)
|
||||
data._identity = $('#edit-identities-list option:selected').val();
|
||||
|
||||
// don't submit attendees if only myself is added as organizer
|
||||
if (data.attendees.length == 1 && data.attendees[0].role == 'ORGANIZER' && String(data.attendees[0].email).toLowerCase() == settings.identity.email)
|
||||
data.attendees = [];
|
||||
|
||||
// per-attendee notification suppression
|
||||
var need_invitation = false;
|
||||
|
@ -1013,6 +998,8 @@ function rcube_calendar_ui(settings)
|
|||
window.setTimeout(load_attendees_tab, exec_deferred);
|
||||
if (calendar.attachments)
|
||||
window.setTimeout(load_attachments_tab, exec_deferred);
|
||||
|
||||
rcmail.triggerEvent('calendar-event-dialog', {dialog: $dialog});
|
||||
};
|
||||
|
||||
// show event changelog in a dialog
|
||||
|
@ -1116,8 +1103,8 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
// format attendees struct
|
||||
else if (prop == 'attendees') {
|
||||
if (change['old']) change.old_ = event_attendee_html(change['old']);
|
||||
if (change['new']) change.new_ = event_attendee_html($.extend({}, change['old'] || {}, change['new']));
|
||||
if (change['old']) change.old_ = rcube_libcalendaring.attendee_html(change['old']);
|
||||
if (change['new']) change.new_ = rcube_libcalendaring.attendee_html($.extend({}, change['old'] || {}, change['new']));
|
||||
html = true;
|
||||
}
|
||||
// localize priority values
|
||||
|
@ -1255,7 +1242,7 @@ function rcube_calendar_ui(settings)
|
|||
freebusy_data = { required:{}, all:{} };
|
||||
freebusy_ui.loading = 1; // prevent render_freebusy_grid() to load data yet
|
||||
freebusy_ui.numdays = Math.max(allday.checked ? 14 : 1, Math.ceil(duration * 2 / 86400));
|
||||
freebusy_ui.interval = allday.checked ? 1440 : 60;
|
||||
freebusy_ui.interval = allday.checked ? 1440 : (60 / (settings.timeslots || 1));
|
||||
freebusy_ui.start = fb_start;
|
||||
freebusy_ui.end = new Date(freebusy_ui.start.getTime() + DAY_MS * freebusy_ui.numdays);
|
||||
render_freebusy_grid(0);
|
||||
|
@ -1339,6 +1326,7 @@ function rcube_calendar_ui(settings)
|
|||
closeOnEscape: (!bw.ie6 && !bw.ie7),
|
||||
title: rcmail.gettext('scheduletime', 'calendar'),
|
||||
open: function() {
|
||||
rcmail.ksearch_blur();
|
||||
$dialog.attr('aria-hidden', 'false').find('#shedule-find-next, #shedule-find-prev').not(':disabled').first().focus();
|
||||
},
|
||||
close: function() {
|
||||
|
@ -1361,7 +1349,7 @@ function rcube_calendar_ui(settings)
|
|||
|
||||
// adjust dialog size to fit grid without scrolling
|
||||
var gridw = $('#schedule-freebusy-times').width();
|
||||
var overflow = gridw - $('#attendees-freebusy-table td.times').width() + 1;
|
||||
var overflow = gridw - $('#attendees-freebusy-table td.times').width();
|
||||
me.dialog_resize($dialog.get(0), $dialog.height() + (bw.ie ? 20 : 0), 800 + Math.max(0, overflow));
|
||||
|
||||
// fetch data from server
|
||||
|
@ -1391,10 +1379,12 @@ function rcube_calendar_ui(settings)
|
|||
var lastdate, datestr, css,
|
||||
curdate = new Date(),
|
||||
allday = (freebusy_ui.interval == 1440),
|
||||
interval = allday ? 1440 : (freebusy_ui.interval * (settings.timeslots || 1));
|
||||
times_css = (allday ? 'allday ' : ''),
|
||||
dates_row = '<tr class="dates">',
|
||||
times_row = '<tr class="times">',
|
||||
slots_row = '';
|
||||
|
||||
for (var s = 0, t = freebusy_ui.start.getTime(); t < freebusy_ui.end.getTime(); s++) {
|
||||
curdate.setTime(t);
|
||||
datestr = fc.fullCalendar('formatDate', curdate, date_format);
|
||||
|
@ -1407,9 +1397,9 @@ function rcube_calendar_ui(settings)
|
|||
// set css class according to working hours
|
||||
css = is_weekend(curdate) || (freebusy_ui.interval <= 60 && !is_workinghour(curdate)) ? 'offhours' : 'workinghours';
|
||||
times_row += '<td class="' + times_css + css + '" id="t-' + Math.floor(t/1000) + '">' + Q(allday ? rcmail.gettext('all-day','calendar') : $.fullCalendar.formatDate(curdate, settings['time_format'])) + '</td>';
|
||||
slots_row += '<td class="' + css + ' unknown"> </td>';
|
||||
slots_row += '<td class="' + css + '"> </td>';
|
||||
|
||||
t += freebusy_ui.interval * 60000;
|
||||
t += interval * 60000;
|
||||
}
|
||||
dates_row += '</tr>';
|
||||
times_row += '</tr>';
|
||||
|
@ -1423,7 +1413,7 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
|
||||
// add line for all/required attendees
|
||||
times_html += '<tr class="spacer"><td colspan="' + (dayslots * freebusy_ui.numdays) + '"> </td>';
|
||||
times_html += '<tr class="spacer"><td colspan="' + (dayslots * freebusy_ui.numdays) + '"></td>';
|
||||
times_html += '<tr id="fbrowall">' + slots_row + '</tr>';
|
||||
|
||||
var table = $('#schedule-freebusy-times');
|
||||
|
@ -1445,7 +1435,7 @@ function rcube_calendar_ui(settings)
|
|||
update_freebusy_dates(newstart, new Date(newstart.getTime() + freebusy_ui.startdate.data('duration') * 1000));
|
||||
render_freebusy_overlay();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// if we have loaded free-busy data, show it
|
||||
|
@ -1476,38 +1466,40 @@ function rcube_calendar_ui(settings)
|
|||
overlay.draggable('disable');
|
||||
}
|
||||
else {
|
||||
var table = $('#schedule-freebusy-times'),
|
||||
var i, n, table = $('#schedule-freebusy-times'),
|
||||
width = 0,
|
||||
pos = { top:table.children('thead').height(), left:0 },
|
||||
eventstart = date2unixtime(clone_date(me.selected_event.start, me.selected_event.allDay?1:0)),
|
||||
eventend = date2unixtime(clone_date(me.selected_event.end, me.selected_event.allDay?2:0)) - 60,
|
||||
slotstart = date2unixtime(freebusy_ui.start),
|
||||
slotsize = freebusy_ui.interval * 60,
|
||||
slotend, fraction, $cell;
|
||||
|
||||
// iterate through slots to determine position and size of the overlay
|
||||
table.children('thead').find('td').each(function(i, cell){
|
||||
slotend = slotstart + slotsize - 1;
|
||||
// event starts in this slot: compute left
|
||||
if (eventstart >= slotstart && eventstart <= slotend) {
|
||||
fraction = 1 - (slotend - eventstart) / slotsize;
|
||||
pos.left = Math.round(cell.offsetLeft + cell.offsetWidth * fraction);
|
||||
}
|
||||
// event ends in this slot: compute width
|
||||
if (eventend >= slotstart && eventend <= slotend) {
|
||||
fraction = 1 - (slotend - eventend) / slotsize;
|
||||
width = Math.round(cell.offsetLeft + cell.offsetWidth * fraction) - pos.left;
|
||||
}
|
||||
slotnum = freebusy_ui.interval > 60 ? 1 : (60 / freebusy_ui.interval),
|
||||
cells = table.children('thead').find('td'),
|
||||
cell_width = cells.first().get(0).offsetWidth,
|
||||
slotend;
|
||||
|
||||
slotstart = slotstart + slotsize;
|
||||
});
|
||||
// iterate through slots to determine position and size of the overlay
|
||||
for (i=0; i < cells.length; i++) {
|
||||
for (n=0; n < slotnum; n++) {
|
||||
slotend = slotstart + slotsize - 1;
|
||||
// event starts in this slot: compute left
|
||||
if (eventstart >= slotstart && eventstart <= slotend) {
|
||||
pos.left = Math.round(i * cell_width + (cell_width / slotnum) * n);
|
||||
}
|
||||
// event ends in this slot: compute width
|
||||
if (eventend >= slotstart && eventend <= slotend) {
|
||||
width = Math.round(i * cell_width + (cell_width / slotnum) * (n + 1)) - pos.left;
|
||||
}
|
||||
slotstart += slotsize;
|
||||
}
|
||||
}
|
||||
|
||||
if (!width)
|
||||
width = table.width() - pos.left;
|
||||
|
||||
// overlay is visible
|
||||
if (width > 0) {
|
||||
overlay.css({ width: (width-5)+'px', height:(table.children('tbody').height() - 4)+'px', left:pos.left+'px', top:pos.top+'px' }).show();
|
||||
overlay.css({ width: (width-4)+'px', height:(table.children('tbody').height() - 4)+'px', left:pos.left+'px', top:pos.top+'px' }).show();
|
||||
|
||||
// configure draggable
|
||||
if (!overlay.data('isdraggable')) {
|
||||
|
@ -1530,6 +1522,7 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
else {
|
||||
// round to 5 minutes
|
||||
// @TODO: round to timeslots?
|
||||
var round = newstart.getMinutes() % 5;
|
||||
if (round > 2.5) newstart.setTime(newstart.getTime() + (5 - round) * 60000);
|
||||
else if (round > 0) newstart.setTime(newstart.getTime() - round * 60000);
|
||||
|
@ -1547,10 +1540,8 @@ function rcube_calendar_ui(settings)
|
|||
else
|
||||
overlay.draggable('disable').hide();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// fetch free-busy information for each attendee from server
|
||||
var load_freebusy_data = function(from, interval)
|
||||
{
|
||||
|
@ -1577,9 +1568,9 @@ function rcube_calendar_ui(settings)
|
|||
success: function(data) {
|
||||
freebusy_ui.loading--;
|
||||
|
||||
// find attendee
|
||||
var attendee = null;
|
||||
for (var i=0; i < event_attendees.length; i++) {
|
||||
// find attendee
|
||||
var i, attendee = null;
|
||||
for (i=0; i < event_attendees.length; i++) {
|
||||
if (freebusy_ui.attendees[i].email == data.email) {
|
||||
attendee = freebusy_ui.attendees[i];
|
||||
break;
|
||||
|
@ -1587,25 +1578,31 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
|
||||
// copy data to member var
|
||||
var ts, req = attendee.role != 'OPT-PARTICIPANT';
|
||||
freebusy_data.start = parseISO8601(data.start);
|
||||
var ts, status,
|
||||
req = attendee.role != 'OPT-PARTICIPANT',
|
||||
start = parseISO8601(data.start);
|
||||
|
||||
freebusy_data.start = new Date(start);
|
||||
freebusy_data.end = parseISO8601(data.end);
|
||||
freebusy_data.interval = data.interval;
|
||||
freebusy_data[data.email] = {};
|
||||
for (var i=0; i < data.slots.length; i++) {
|
||||
ts = data.times[i] + '';
|
||||
freebusy_data[data.email][ts] = data.slots[i];
|
||||
|
||||
for (i=0; i < data.slots.length; i++) {
|
||||
ts = date2timestring(start, data.interval > 60);
|
||||
status = data.slots.charAt(i);
|
||||
freebusy_data[data.email][ts] = status
|
||||
start = new Date(start.getTime() + data.interval * 60000);
|
||||
|
||||
// set totals
|
||||
if (!freebusy_data.required[ts])
|
||||
freebusy_data.required[ts] = [0,0,0,0];
|
||||
if (req)
|
||||
freebusy_data.required[ts][data.slots[i]]++;
|
||||
freebusy_data.required[ts][status]++;
|
||||
|
||||
if (!freebusy_data.all[ts])
|
||||
freebusy_data.all[ts] = [0,0,0,0];
|
||||
freebusy_data.all[ts][data.slots[i]]++;
|
||||
freebusy_data.all[ts][status]++;
|
||||
}
|
||||
freebusy_data.end = parseISO8601(data.end);
|
||||
freebusy_data.interval = data.interval;
|
||||
|
||||
// hide loading indicator
|
||||
var domid = String(data.email).replace(rcmail.identifier_expr, '');
|
||||
|
@ -1668,27 +1665,51 @@ function rcube_calendar_ui(settings)
|
|||
|
||||
if (fbdata && fbdata[ts] !== undefined && row.length) {
|
||||
t = freebusy_ui.start.getTime();
|
||||
row.children().each(function(i, cell){
|
||||
curdate.setTime(t);
|
||||
ts = date2timestring(curdate, dateonly);
|
||||
cell.className = cell.className.replace('unknown', fbdata[ts] ? status_classes[fbdata[ts]] : 'unknown');
|
||||
row.children().each(function(i, cell) {
|
||||
var j, n, attr, last, all_slots = [], slots = [],
|
||||
all_cell = rowall.get(i),
|
||||
cnt = dateonly ? 1 : (60 / freebusy_ui.interval),
|
||||
percent = (100 / cnt);
|
||||
|
||||
// also update total row if all data was loaded
|
||||
if (freebusy_ui.loading == 0 && freebusy_data.all[ts] && (cell = rowall.get(i))) {
|
||||
var workinghours = cell.className.indexOf('workinghours') >= 0;
|
||||
var all_status = freebusy_data.all[ts][2] ? 'busy' : 'unknown';
|
||||
req_status = freebusy_data.required[ts][2] ? 'busy' : 'free';
|
||||
for (var j=1; j < status_classes.length; j++) {
|
||||
if (freebusy_ui.numrequired && freebusy_data.required[ts][j] >= freebusy_ui.numrequired)
|
||||
req_status = status_classes[j];
|
||||
if (freebusy_data.all[ts][j] == event_attendees.length)
|
||||
all_status = status_classes[j];
|
||||
for (n=0; n < cnt; n++) {
|
||||
curdate.setTime(t);
|
||||
ts = date2timestring(curdate, dateonly);
|
||||
attr = {
|
||||
'style': 'float:left; width:' + percent.toFixed(2) + '%',
|
||||
'class': fbdata[ts] ? status_classes[fbdata[ts]] : 'unknown'
|
||||
};
|
||||
|
||||
slots.push($('<div>').attr(attr));
|
||||
|
||||
// also update total row if all data was loaded
|
||||
if (!freebusy_ui.loading && freebusy_data.all[ts] && all_cell) {
|
||||
var all_status = freebusy_data.all[ts][2] ? 'busy' : 'unknown',
|
||||
req_status = freebusy_data.required[ts][2] ? 'busy' : 'free';
|
||||
|
||||
for (j=1; j < status_classes.length; j++) {
|
||||
if (freebusy_ui.numrequired && freebusy_data.required[ts][j] >= freebusy_ui.numrequired)
|
||||
req_status = status_classes[j];
|
||||
if (freebusy_data.all[ts][j] == event_attendees.length)
|
||||
all_status = status_classes[j];
|
||||
}
|
||||
|
||||
attr['class'] = req_status + ' all-' + all_status;
|
||||
|
||||
// these elements use some specific styling, so we want to minimize their number
|
||||
if (last && last.attr('class') == attr['class'])
|
||||
last.css('width', (percent + parseFloat(last.css('width').replace('%', ''))).toFixed(2) + '%');
|
||||
else {
|
||||
last = $('<div>').attr(attr);
|
||||
all_slots.push(last);
|
||||
}
|
||||
}
|
||||
|
||||
cell.className = (workinghours ? 'workinghours ' : 'offhours ') + req_status + ' all-' + all_status;
|
||||
|
||||
t += freebusy_ui.interval * 60000;
|
||||
}
|
||||
|
||||
t += freebusy_ui.interval * 60000;
|
||||
|
||||
$(cell).html('').append(slots);
|
||||
if (all_slots.length)
|
||||
$(all_cell).html('').append(all_slots);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -1728,17 +1749,20 @@ function rcube_calendar_ui(settings)
|
|||
sinterval = freebusy_data.interval * 60000,
|
||||
intvlslots = 1,
|
||||
numslots = Math.ceil(duration / sinterval),
|
||||
checkdate, slotend, email, ts, slot, slotdate = new Date();
|
||||
fb_start = freebusy_data.start.getTime(),
|
||||
fb_end = freebusy_data.end.getTime(),
|
||||
checkdate, slotend, email, ts, slot, slotdate = new Date(),
|
||||
candidatecount = 0, candidatestart = false, success = false;
|
||||
|
||||
// shift event times to next possible slot
|
||||
eventstart += sinterval * intvlslots * dir;
|
||||
eventend += sinterval * intvlslots * dir;
|
||||
|
||||
// iterate through free-busy slots and find candidates
|
||||
var candidatecount = 0, candidatestart = candidateend = success = false;
|
||||
for (slot = dir > 0 ? freebusy_data.start.getTime() : freebusy_data.end.getTime() - sinterval;
|
||||
(dir > 0 && slot < freebusy_data.end.getTime()) || (dir < 0 && slot >= freebusy_data.start.getTime());
|
||||
slot += sinterval * dir) {
|
||||
for (slot = dir > 0 ? fb_start : fb_end - sinterval;
|
||||
(dir > 0 && slot < fb_end) || (dir < 0 && slot >= fb_start);
|
||||
slot += sinterval * dir
|
||||
) {
|
||||
slotdate.setTime(slot);
|
||||
// fix slot if just crossed a DST change
|
||||
if (event.allDay) {
|
||||
|
@ -1750,10 +1774,10 @@ function rcube_calendar_ui(settings)
|
|||
if ((dir > 0 && slotend <= eventstart) || (dir < 0 && slot >= eventend)) // skip
|
||||
continue;
|
||||
|
||||
// respect workingours setting
|
||||
// respect workinghours setting
|
||||
if (freebusy_ui.workinhoursonly) {
|
||||
if (is_weekend(slotdate) || (freebusy_data.interval <= 60 && !is_workinghour(slotdate))) { // skip off-hours
|
||||
candidatestart = candidateend = false;
|
||||
candidatestart = false;
|
||||
candidatecount = 0;
|
||||
continue;
|
||||
}
|
||||
|
@ -1762,11 +1786,12 @@ function rcube_calendar_ui(settings)
|
|||
if (!candidatestart)
|
||||
candidatestart = slot;
|
||||
|
||||
// check freebusy data for all attendees
|
||||
ts = date2timestring(slotdate, freebusy_data.interval > 60);
|
||||
|
||||
// check freebusy data for all attendees
|
||||
for (var i=0; i < event_attendees.length; i++) {
|
||||
if (freebusy_ui.attendees[i].role != 'OPT-PARTICIPANT' && (email = freebusy_ui.attendees[i].email) && freebusy_data[email] && freebusy_data[email][ts] > 1) {
|
||||
candidatestart = candidateend = false;
|
||||
candidatestart = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1777,22 +1802,15 @@ function rcube_calendar_ui(settings)
|
|||
candidatecount = 0;
|
||||
continue;
|
||||
}
|
||||
else if (dir < 0)
|
||||
candidatestart = slot;
|
||||
|
||||
// set candidate end to slot end time
|
||||
candidatecount++;
|
||||
if (dir < 0 && !candidateend)
|
||||
candidateend = slotend;
|
||||
|
||||
// if candidate is big enough, this is it!
|
||||
if (candidatecount == numslots) {
|
||||
if (dir > 0) {
|
||||
event.start.setTime(candidatestart);
|
||||
event.end.setTime(candidatestart + duration);
|
||||
}
|
||||
else {
|
||||
event.end.setTime(candidateend);
|
||||
event.start.setTime(candidateend - duration);
|
||||
}
|
||||
event.start.setTime(candidatestart);
|
||||
event.end.setTime(candidatestart + duration);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1822,7 +1840,6 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
// update event properties and attendees availability if event times have changed
|
||||
var event_times_changed = function()
|
||||
{
|
||||
|
@ -1837,7 +1854,6 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
// add the given list of participants
|
||||
var add_attendees = function(names, params)
|
||||
{
|
||||
|
@ -1918,7 +1934,8 @@ function rcube_calendar_ui(settings)
|
|||
// delete icon
|
||||
var icon = rcmail.env.deleteicon ? '<img src="' + rcmail.env.deleteicon + '" alt="" />' : rcmail.gettext('delete');
|
||||
var dellink = '<a href="#delete" class="iconlink delete deletelink" title="' + Q(rcmail.gettext('delete')) + '">' + icon + '</a>';
|
||||
var tooltip = data.status || '';
|
||||
var tooltip = '', status = (data.status || '').toLowerCase(),
|
||||
status_label = rcmail.gettext('status' + status, 'libcalendaring');
|
||||
|
||||
// send invitation checkbox
|
||||
var invbox = '<input type="checkbox" class="edit-attendee-reply" value="' + Q(data.email) +'" title="' + Q(rcmail.gettext('calendar.sendinvitations')) + '" '
|
||||
|
@ -1928,6 +1945,8 @@ function rcube_calendar_ui(settings)
|
|||
tooltip = rcmail.gettext('delegatedto', 'calendar') + data['delegated-to'];
|
||||
else if (data['delegated-from'])
|
||||
tooltip = rcmail.gettext('delegatedfrom', 'calendar') + data['delegated-from'];
|
||||
else if (status)
|
||||
tooltip = status_label;
|
||||
|
||||
// add expand button for groups
|
||||
if (data.cutype == 'GROUP') {
|
||||
|
@ -1939,7 +1958,7 @@ function rcube_calendar_ui(settings)
|
|||
var html = '<td class="role">' + select + '</td>' +
|
||||
'<td class="name"><span class="attendee-name">' + dispname + '</span></td>' +
|
||||
'<td class="availability"><img src="' + img_src + '" class="availabilityicon ' + avail + '" data-email="' + data.email + '" alt="" /></td>' +
|
||||
'<td class="confirmstate"><span class="' + String(data.status).toLowerCase() + '" title="' + Q(tooltip) + '">' + Q(data.status || '') + '</span></td>' +
|
||||
'<td class="confirmstate"><span class="' + status + '" title="' + Q(tooltip) + '">' + Q(status ? status_label : '') + '</span></td>' +
|
||||
(data.cutype != 'RESOURCE' ? '<td class="invite">' + (organizer || readonly || !invbox ? '' : invbox) + '</td>' : '') +
|
||||
'<td class="options">' + (organizer || readonly ? '' : dellink) + '</td>';
|
||||
|
||||
|
@ -2045,6 +2064,7 @@ function rcube_calendar_ui(settings)
|
|||
closeOnEscape: true,
|
||||
title: rcmail.gettext('findresources', 'calendar'),
|
||||
open: function() {
|
||||
rcmail.ksearch_blur();
|
||||
$dialog.attr('aria-hidden', 'false');
|
||||
},
|
||||
close: function() {
|
||||
|
@ -2512,13 +2532,20 @@ function rcube_calendar_ui(settings)
|
|||
// display confirm dialog when modifying/deleting an event
|
||||
var update_event_confirm = function(action, event, data)
|
||||
{
|
||||
// Allow other plugins to do actions here
|
||||
// E.g. when you move/resize the event init wasn't called
|
||||
// but we need it as some plugins may modify user identities
|
||||
// we depend on here (kolab_delegation)
|
||||
rcmail.triggerEvent('calendar-event-init', {o: event});
|
||||
|
||||
if (!data) data = event;
|
||||
var decline = false, notify = false, html = '', cal = me.calendars[event.calendar],
|
||||
_has_attendees = has_attendees(event), _is_organizer = is_organizer(event);
|
||||
|
||||
|
||||
// event has attendees, ask whether to notify them
|
||||
if (_has_attendees) {
|
||||
var checked = (settings.itip_notify & 1 ? ' checked="checked"' : '');
|
||||
|
||||
if (_is_organizer) {
|
||||
notify = true;
|
||||
if (settings.itip_notify & 2) {
|
||||
|
@ -2543,7 +2570,7 @@ function rcube_calendar_ui(settings)
|
|||
html += '<div class="message">' + rcmail.gettext('localchangeswarning', 'calendar') + '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// recurring event: user needs to select the savemode
|
||||
if (event.recurrence) {
|
||||
var future_disabled = '', message_label = (action == 'remove' ? 'removerecurringeventwarning' : 'changerecurringeventwarning');
|
||||
|
@ -2958,6 +2985,15 @@ function rcube_calendar_ui(settings)
|
|||
return false;
|
||||
};
|
||||
|
||||
this.calendar_refresh_source = function(id)
|
||||
{
|
||||
// got race-conditions fc.currentFetchID when using refetchEvents,
|
||||
// so we remove and add the source instead
|
||||
// fc.fullCalendar('refetchEvents', me.calendars[id]);
|
||||
fc.fullCalendar('removeEventSource', me.calendars[id]);
|
||||
fc.fullCalendar('addEventSource', me.calendars[id]);
|
||||
};
|
||||
|
||||
this.calendar_destroy_source = function(id)
|
||||
{
|
||||
var delete_ids = [];
|
||||
|
@ -3021,11 +3057,11 @@ function rcube_calendar_ui(settings)
|
|||
rcmail.env.request_timeout = timeout;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
|
||||
$dialog.dialog("close");
|
||||
};
|
||||
|
||||
|
||||
// open jquery UI dialog
|
||||
$dialog.dialog({
|
||||
modal: true,
|
||||
|
@ -3042,7 +3078,6 @@ function rcube_calendar_ui(settings)
|
|||
buttons: buttons,
|
||||
width: 520
|
||||
}).show();
|
||||
|
||||
};
|
||||
|
||||
// callback from server if import succeeded
|
||||
|
@ -3085,7 +3120,7 @@ function rcube_calendar_ui(settings)
|
|||
if (custom)
|
||||
input.select();
|
||||
})
|
||||
|
||||
|
||||
var buttons = {};
|
||||
buttons[rcmail.gettext('export', 'calendar')] = function() {
|
||||
if (form) {
|
||||
|
@ -3100,8 +3135,9 @@ function rcube_calendar_ui(settings)
|
|||
|
||||
rcmail.goto_url('export_events', { source:source, start:start, attachments:attachmt?1:0 });
|
||||
}
|
||||
$dialog.dialog("close");
|
||||
};
|
||||
|
||||
|
||||
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
|
||||
$dialog.dialog("close");
|
||||
};
|
||||
|
@ -3122,7 +3158,6 @@ function rcube_calendar_ui(settings)
|
|||
buttons: buttons,
|
||||
width: 520
|
||||
}).show();
|
||||
|
||||
};
|
||||
|
||||
// download the selected event as iCal
|
||||
|
@ -3142,6 +3177,28 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
};
|
||||
|
||||
// display the edit dialog, request 'new' action and pass the selected event
|
||||
this.event_copy = function(event) {
|
||||
if (event && event.id) {
|
||||
var copy = $.extend(true, {}, event);
|
||||
|
||||
delete copy.id;
|
||||
delete copy._id;
|
||||
delete copy.created;
|
||||
delete copy.changed;
|
||||
delete copy.recurrence_id;
|
||||
delete copy.attachments; // @TODO
|
||||
|
||||
$.each(copy.attendees, function (k, v) {
|
||||
if (v.role != 'ORGANIZER') {
|
||||
v.status = 'NEEDS-ACTION';
|
||||
}
|
||||
})
|
||||
|
||||
event_edit_dialog('new', copy);
|
||||
}
|
||||
};
|
||||
|
||||
// show URL of the given calendar in a dialog box
|
||||
this.showurl = function(calendar)
|
||||
{
|
||||
|
@ -3465,8 +3522,7 @@ function rcube_calendar_ui(settings)
|
|||
this.dialog_resize = function(id, height, width)
|
||||
{
|
||||
var win = $(window), w = win.width(), h = win.height();
|
||||
$(id).dialog('option', { height: Math.min(h-20, height+130), width: Math.min(w-20, width+50) })
|
||||
.dialog('option', 'position', ['center', 'center']); // only works in a separate call (!?)
|
||||
$(id).dialog('option', { height: Math.min(h-20, height+130), width: Math.min(w-20, width+50) });
|
||||
};
|
||||
|
||||
// adjust calendar view size
|
||||
|
@ -3832,77 +3888,6 @@ function rcube_calendar_ui(settings)
|
|||
}
|
||||
}));
|
||||
|
||||
// format time string
|
||||
var formattime = function(hour, minutes, start) {
|
||||
var time, diff, unit, duration = '', d = new Date();
|
||||
d.setHours(hour);
|
||||
d.setMinutes(minutes);
|
||||
time = $.fullCalendar.formatDate(d, settings['time_format']);
|
||||
if (start) {
|
||||
diff = Math.floor((d.getTime() - start.getTime()) / 60000);
|
||||
if (diff > 0) {
|
||||
unit = 'm';
|
||||
if (diff >= 60) {
|
||||
unit = 'h';
|
||||
diff = Math.round(diff / 3) / 20;
|
||||
}
|
||||
duration = ' (' + diff + unit + ')';
|
||||
}
|
||||
}
|
||||
return [time, duration];
|
||||
};
|
||||
|
||||
var autocomplete_times = function(p, callback) {
|
||||
/* Time completions */
|
||||
var result = [];
|
||||
var now = new Date();
|
||||
var st, start = (String(this.element.attr('id')).indexOf('endtime') > 0
|
||||
&& (st = $('#edit-starttime').val())
|
||||
&& $('#edit-startdate').val() == $('#edit-enddate').val())
|
||||
? parse_datetime(st, '') : null;
|
||||
var full = p.term - 1 > 0 || p.term.length > 1;
|
||||
var hours = start ? start.getHours() :
|
||||
(full ? parse_datetime(p.term, '') : now).getHours();
|
||||
var step = 15;
|
||||
var minutes = hours * 60 + (full ? 0 : now.getMinutes());
|
||||
var min = Math.ceil(minutes / step) * step % 60;
|
||||
var hour = Math.floor(Math.ceil(minutes / step) * step / 60);
|
||||
// list hours from 0:00 till now
|
||||
for (var h = start ? start.getHours() : 0; h < hours; h++)
|
||||
result.push(formattime(h, 0, start));
|
||||
// list 15min steps for the next two hours
|
||||
for (; h < hour + 2 && h < 24; h++) {
|
||||
while (min < 60) {
|
||||
result.push(formattime(h, min, start));
|
||||
min += step;
|
||||
}
|
||||
min = 0;
|
||||
}
|
||||
// list the remaining hours till 23:00
|
||||
while (h < 24)
|
||||
result.push(formattime((h++), 0, start));
|
||||
|
||||
return callback(result);
|
||||
};
|
||||
|
||||
var autocomplete_open = function(event, ui) {
|
||||
// scroll to current time
|
||||
var $this = $(this);
|
||||
var widget = $this.autocomplete('widget');
|
||||
var menu = $this.data('ui-autocomplete').menu;
|
||||
var amregex = /^(.+)(a[.m]*)/i;
|
||||
var pmregex = /^(.+)(a[.m]*)/i;
|
||||
var val = $(this).val().replace(amregex, '0:$1').replace(pmregex, '1:$1');
|
||||
var li, html;
|
||||
widget.css('width', '10em');
|
||||
widget.children().each(function(){
|
||||
li = $(this);
|
||||
html = li.children().first().html().replace(/\s+\(.+\)$/, '').replace(amregex, '0:$1').replace(pmregex, '1:$1');
|
||||
if (html.indexOf(val) == 0)
|
||||
menu._scrollIntoView(li);
|
||||
});
|
||||
};
|
||||
|
||||
// if start date is changed, shift end date according to initial duration
|
||||
var shift_enddate = function(dateText) {
|
||||
var newstart = parse_datetime('0', dateText);
|
||||
|
@ -3978,23 +3963,24 @@ function rcube_calendar_ui(settings)
|
|||
// init event dialog
|
||||
$('#eventtabs').tabs({
|
||||
activate: function(event, ui) {
|
||||
if (ui.newPanel.selector == '#event-panel-attendees' || ui.newPanel.selector == '#event-panel-resources') {
|
||||
var tab = ui.newPanel.selector == '#event-panel-resources' ? 'resource' : 'attendee';
|
||||
// newPanel.selector for jQuery-UI 1.10, newPanel.attr('id') for jQuery-UI 1.12
|
||||
var tab = String(ui.newPanel.selector || ui.newPanel.attr('id'))
|
||||
.replace(/^#?event-panel-/, '').replace(/s$/, '');
|
||||
|
||||
if (tab == 'attendee' || tab == 'resource') {
|
||||
if (!rcube_event.is_keyboard(event))
|
||||
$('#edit-'+tab+'-name').select();
|
||||
// update free-busy status if needed
|
||||
if (freebusy_ui.needsupdate && me.selected_event)
|
||||
update_freebusy_status(me.selected_event);
|
||||
// add current user as organizer if non added yet
|
||||
if (!event_attendees.length) {
|
||||
if (tab == 'attendee' && !event_attendees.length) {
|
||||
add_attendee($.extend({ role:'ORGANIZER' }, settings.identity));
|
||||
$('#edit-attendees-form .attendees-invitebox').show();
|
||||
}
|
||||
}
|
||||
// reset autocompletion on tab change (#3389)
|
||||
if (ui.oldPanel.selector == '#event-panel-attendees' || ui.oldPanel.selector == '#event-panel-resources') {
|
||||
rcmail.ksearch_blur();
|
||||
}
|
||||
rcmail.ksearch_blur();
|
||||
}
|
||||
});
|
||||
$('#edit-enddate').datepicker(datepicker_settings);
|
||||
|
@ -4003,30 +3989,12 @@ function rcube_calendar_ui(settings)
|
|||
$('#edit-allday').click(function(){ $('#edit-starttime, #edit-endtime')[(this.checked?'hide':'show')](); event_times_changed(); });
|
||||
|
||||
// configure drop-down menu on time input fields based on jquery UI autocomplete
|
||||
$('#edit-starttime, #edit-endtime, #eventedit input.edit-alarm-time')
|
||||
.attr('autocomplete', "off")
|
||||
.autocomplete({
|
||||
delay: 100,
|
||||
minLength: 1,
|
||||
appendTo: '#eventedit',
|
||||
source: autocomplete_times,
|
||||
open: autocomplete_open,
|
||||
change: event_times_changed,
|
||||
select: function(event, ui) {
|
||||
$(this).val(ui.item[0]).change();
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.click(function() { // show drop-down upon clicks
|
||||
$(this).autocomplete('search', $(this).val() ? $(this).val().replace(/\D.*/, "") : " ");
|
||||
}).each(function(){
|
||||
$(this).data('ui-autocomplete')._renderItem = function(ul, item) {
|
||||
return $('<li>')
|
||||
.data('ui-autocomplete-item', item)
|
||||
.append('<a>' + item[0] + item[1] + '</a>')
|
||||
.appendTo(ul);
|
||||
};
|
||||
$('#edit-starttime, #edit-endtime, #eventedit input.edit-alarm-time').each(function() {
|
||||
me.init_time_autocomplete(this, {
|
||||
container: '#eventedit',
|
||||
change: event_times_changed
|
||||
});
|
||||
});
|
||||
|
||||
// adjust end time when changing start
|
||||
$('#edit-starttime').change(function(e) {
|
||||
|
@ -4222,6 +4190,7 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
|
|||
rcmail.register_command('calendar-showurl', function(){ cal.showurl(cal.calendars[cal.selected_calendar]); }, false);
|
||||
rcmail.register_command('event-download', function(){ cal.event_download(cal.selected_event); }, true);
|
||||
rcmail.register_command('event-sendbymail', function(p, obj, e){ cal.event_sendbymail(cal.selected_event, e); }, true);
|
||||
rcmail.register_command('event-copy', function(){ cal.event_copy(cal.selected_event); }, true);
|
||||
rcmail.register_command('event-history', function(p, obj, e){ cal.event_history_dialog(cal.selected_event); }, false);
|
||||
|
||||
// search and export events
|
||||
|
@ -4235,6 +4204,7 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
|
|||
rcmail.register_command('add-resource', function(){ cal.add_resource2event(); }, false);
|
||||
|
||||
// register callback commands
|
||||
rcmail.addEventListener('plugin.refresh_source', function(data) { cal.calendar_refresh_source(data); });
|
||||
rcmail.addEventListener('plugin.destroy_source', function(p){ cal.calendar_destroy_source(p.id); });
|
||||
rcmail.addEventListener('plugin.unlock_saving', function(p){ cal.unlock_saving(); });
|
||||
rcmail.addEventListener('plugin.refresh_calendar', function(p){ cal.refresh(p); });
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"roundcube/plugin-installer": ">=0.1.3",
|
||||
"kolab/libcalendaring": ">=3.2.9"
|
||||
"kolab/libcalendaring": ">=3.2.16"
|
||||
},
|
||||
"extra": {
|
||||
"roundcube": {
|
||||
|
|
|
@ -149,7 +149,7 @@ $config['calendar_itip_smtp_user'] = 'smtpauth';
|
|||
$config['calendar_itip_smtp_pass'] = '123456';
|
||||
|
||||
// show virtual invitation calendars (Kolab driver only)
|
||||
$config['kolab_invitation_calendars'] = true;
|
||||
$config['kolab_invitation_calendars'] = false;
|
||||
|
||||
// Base URL to build fully qualified URIs to access calendars via CALDAV
|
||||
// The following replacement variables are supported:
|
||||
|
|
|
@ -101,6 +101,7 @@ abstract class calendar_driver
|
|||
const FILTER_PERSONAL = 8;
|
||||
const FILTER_PRIVATE = 16;
|
||||
const FILTER_CONFIDENTIAL = 32;
|
||||
const FILTER_SHARED = 64;
|
||||
const BIRTHDAY_CALENDAR_ID = '__bdays__';
|
||||
|
||||
// features supported by backend
|
||||
|
@ -632,9 +633,9 @@ abstract class calendar_driver
|
|||
$cache = $rcmail->get_cache('calendar.birthdays', 'db', 3600);
|
||||
$cache->expunge();
|
||||
|
||||
$alarm_type = $rcmail->config->get('calendar_birthdays_alarm_type', '');
|
||||
$alarm_type = $rcmail->config->get('calendar_birthdays_alarm_type', '');
|
||||
$alarm_offset = $rcmail->config->get('calendar_birthdays_alarm_offset', '-1D');
|
||||
$alarms = $alarm_type ? $alarm_offset . ':' . $alarm_type : null;
|
||||
$alarms = $alarm_type ? $alarm_offset . ':' . $alarm_type : null;
|
||||
|
||||
// let the user select the address books to consider in prefs
|
||||
$selected_sources = $rcmail->config->get('calendar_birthday_adressbooks');
|
||||
|
@ -655,70 +656,56 @@ abstract class calendar_driver
|
|||
|
||||
// iterate over (cached) contacts
|
||||
foreach (($cached ?: $abook->search('*', '', 2, true, true, array('birthday'))) as $contact) {
|
||||
if (is_array($contact) && !empty($contact['birthday'])) {
|
||||
try {
|
||||
if (is_array($contact['birthday']))
|
||||
$contact['birthday'] = reset($contact['birthday']);
|
||||
$event = self::parse_contact($contact, $source);
|
||||
|
||||
$bday = $contact['birthday'] instanceof DateTime ? $contact['birthday'] :
|
||||
new DateTime($contact['birthday'], new DateTimezone('UTC'));
|
||||
$birthyear = $bday->format('Y');
|
||||
}
|
||||
catch (Exception $e) {
|
||||
rcube::raise_error(array(
|
||||
'code' => 600, 'type' => 'php',
|
||||
'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => 'BIRTHDAY PARSE ERROR: ' . $e),
|
||||
true, false);
|
||||
continue;
|
||||
if (empty($event)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// add stripped record to cache
|
||||
if (empty($cached)) {
|
||||
$cache_records[] = array(
|
||||
'ID' => $contact['ID'],
|
||||
'name' => $event['_displayname'],
|
||||
'birthday' => $event['start']->format('Y-m-d'),
|
||||
);
|
||||
}
|
||||
|
||||
// filter by search term (only name is involved here)
|
||||
if (!empty($search) && strpos(mb_strtolower($event['title']), $search) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$bday = clone $event['start'];
|
||||
$byear = $bday->format('Y');
|
||||
|
||||
// quick-and-dirty recurrence computation: just replace the year
|
||||
$bday->setDate($year, $bday->format('n'), $bday->format('j'));
|
||||
$bday->setTime(12, 0, 0);
|
||||
$this_year = $year;
|
||||
|
||||
// date range reaches over multiple years: use end year if not in range
|
||||
if (($bday > $end || $bday < $start) && $year2 != $year) {
|
||||
$bday->setDate($year2, $bday->format('n'), $bday->format('j'));
|
||||
$this_year = $year2;
|
||||
}
|
||||
|
||||
// birthday is within requested range
|
||||
if ($bday <= $end && $bday >= $start) {
|
||||
unset($event['_displayname']);
|
||||
$event['alarms'] = $alarms;
|
||||
|
||||
// if this is not the first occurence modify event details
|
||||
// but not when this is "all birthdays feed" request
|
||||
if ($year2 - $year < 10 && ($age = ($this_year - $byear))) {
|
||||
$event['description'] = $rcmail->gettext(array('name' => 'birthdayage', 'vars' => array('age' => $age)), 'calendar');
|
||||
$event['start'] = $bday;
|
||||
$event['end'] = clone $bday;
|
||||
unset($event['recurrence']);
|
||||
}
|
||||
|
||||
$display_name = rcube_addressbook::compose_display_name($contact);
|
||||
$event_title = $rcmail->gettext(array('name' => 'birthdayeventtitle', 'vars' => array('name' => $display_name)), 'calendar');
|
||||
|
||||
// add stripped record to cache
|
||||
if (empty($cached)) {
|
||||
$cache_records[] = array(
|
||||
'ID' => $contact['ID'],
|
||||
'name' => $display_name,
|
||||
'birthday' => $bday->format('Y-m-d'),
|
||||
);
|
||||
}
|
||||
|
||||
// filter by search term (only name is involved here)
|
||||
if (!empty($search) && strpos(mb_strtolower($event_title), $search) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// quick-and-dirty recurrence computation: just replace the year
|
||||
$bday->setDate($year, $bday->format('n'), $bday->format('j'));
|
||||
$bday->setTime(12, 0, 0);
|
||||
$this_year = $year;
|
||||
|
||||
// date range reaches over multiple years: use end year if not in range
|
||||
if (($bday > $end || $bday < $start) && $year2 != $year) {
|
||||
$bday->setDate($year2, $bday->format('n'), $bday->format('j'));
|
||||
$this_year = $year2;
|
||||
}
|
||||
|
||||
// birthday is within requested range
|
||||
if ($bday <= $end && $bday >= $start) {
|
||||
$age = $this_year - $birthyear;
|
||||
$event = array(
|
||||
'id' => rcube_ldap::dn_encode('bday:' . $source . ':' . $contact['ID'] . ':' . $this_year),
|
||||
'calendar' => self::BIRTHDAY_CALENDAR_ID,
|
||||
'title' => $event_title,
|
||||
'description' => $rcmail->gettext(array('name' => 'birthdayage', 'vars' => array('age' => $age)), 'calendar'),
|
||||
// Add more contact information to description block?
|
||||
'allday' => true,
|
||||
'start' => $bday,
|
||||
'alarms' => $alarms,
|
||||
);
|
||||
$event['end'] = clone $bday;
|
||||
$event['end']->add(new DateInterval('PT1H'));
|
||||
|
||||
$events[] = $event;
|
||||
}
|
||||
// add the main instance
|
||||
$events[] = $event;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -742,49 +729,72 @@ abstract class calendar_driver
|
|||
$rcmail = rcmail::get_instance();
|
||||
|
||||
if ($source && $contact_id && ($abook = $rcmail->get_address_book($source))) {
|
||||
$contact = $abook->get_record($contact_id, true);
|
||||
|
||||
if (is_array($contact) && !empty($contact['birthday'])) {
|
||||
try {
|
||||
if (is_array($contact['birthday']))
|
||||
$contact['birthday'] = reset($contact['birthday']);
|
||||
|
||||
$bday = $contact['birthday'] instanceof DateTime ? $contact['birthday'] :
|
||||
new DateTime($contact['birthday'], new DateTimezone('UTC'));
|
||||
$birthyear = $bday->format('Y');
|
||||
}
|
||||
catch (Exception $e) {
|
||||
rcube::raise_error(array(
|
||||
'code' => 600, 'type' => 'php',
|
||||
'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => 'BIRTHDAY PARSE ERROR: ' . $e),
|
||||
true, false);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$display_name = rcube_addressbook::compose_display_name($contact);
|
||||
$event_title = $rcmail->gettext(array('name' => 'birthdayeventtitle', 'vars' => array('name' => $display_name)), 'calendar');
|
||||
|
||||
$event = array(
|
||||
'id' => rcube_ldap::dn_encode('bday:' . $source . ':' . $contact['ID'] . ':' . $year),
|
||||
'uid' => rcube_ldap::dn_encode('bday:' . $source . ':' . $contact['ID'] . ':' . $birthyear),
|
||||
'calendar' => self::BIRTHDAY_CALENDAR_ID,
|
||||
'title' => $event_title,
|
||||
'description' => '',
|
||||
'allday' => true,
|
||||
'start' => $bday,
|
||||
'recurrence' => array('FREQ' => 'YEARLY', 'INTERVAL' => 1),
|
||||
'free_busy' => 'free',
|
||||
);
|
||||
$event['end'] = clone $bday;
|
||||
$event['end']->add(new DateInterval('PT1H'));
|
||||
|
||||
return $event;
|
||||
if ($contact = $abook->get_record($contact_id, true)) {
|
||||
return self::parse_contact($contact, $source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
/**
|
||||
* Parse contact and create an event for its birthday
|
||||
*
|
||||
* @param array $contact Contact data
|
||||
* @param string $source Addressbook source ID
|
||||
*
|
||||
* @return array Birthday event data
|
||||
*/
|
||||
public static function parse_contact($contact, $source)
|
||||
{
|
||||
if (!is_array($contact)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($contact['birthday'])) {
|
||||
$contact['birthday'] = reset($contact['birthday']);
|
||||
}
|
||||
|
||||
if (empty($contact['birthday'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$bday = $contact['birthday'];
|
||||
if (!$bday instanceof DateTime) {
|
||||
$bday = new DateTime($bday, new DateTimezone('UTC'));
|
||||
}
|
||||
$bday->_dateonly = true;
|
||||
}
|
||||
catch (Exception $e) {
|
||||
rcube::raise_error(array(
|
||||
'code' => 600, 'type' => 'php',
|
||||
'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => 'BIRTHDAY PARSE ERROR: ' . $e->getMessage()),
|
||||
true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
$rcmail = rcmail::get_instance();
|
||||
$birthyear = $bday->format('Y');
|
||||
$display_name = rcube_addressbook::compose_display_name($contact);
|
||||
$label = array('name' => 'birthdayeventtitle', 'vars' => array('name' => $display_name));
|
||||
$event_title = $rcmail->gettext($label, 'calendar');
|
||||
$uid = rcube_ldap::dn_encode('bday:' . $source . ':' . $contact['ID'] . ':' . $birthyear);
|
||||
|
||||
$event = array(
|
||||
'id' => $uid,
|
||||
'uid' => $uid,
|
||||
'calendar' => self::BIRTHDAY_CALENDAR_ID,
|
||||
'title' => $event_title,
|
||||
'description' => '',
|
||||
'allday' => true,
|
||||
'start' => $bday,
|
||||
'end' => clone $bday,
|
||||
'recurrence' => array('FREQ' => 'YEARLY', 'INTERVAL' => 1),
|
||||
'free_busy' => 'free',
|
||||
'_displayname' => $display_name,
|
||||
);
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -188,29 +188,34 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
*/
|
||||
public function get_event($id)
|
||||
{
|
||||
// directly access storage object
|
||||
if (!$this->events[$id] && ($record = $this->storage->get_object($id)))
|
||||
$this->events[$id] = $this->_to_driver_event($record, true);
|
||||
// remove our occurrence identifier if it's there
|
||||
$master_id = preg_replace('/-\d{8}(T\d{6})?$/', '', $id);
|
||||
|
||||
// event not found, maybe a recurring instance is requested
|
||||
if (!$this->events[$id]) {
|
||||
$master_id = preg_replace('/-\d+(T\d{6})?$/', '', $id);
|
||||
// directly access storage object
|
||||
if (!$this->events[$id] && $master_id == $id && ($record = $this->storage->get_object($id))) {
|
||||
$this->events[$id] = $this->_to_driver_event($record, true);
|
||||
}
|
||||
|
||||
// maybe a recurring instance is requested
|
||||
if (!$this->events[$id] && $master_id != $id) {
|
||||
$instance_id = substr($id, strlen($master_id) + 1);
|
||||
|
||||
if ($master_id != $id && ($record = $this->storage->get_object($master_id))) {
|
||||
if ($record = $this->storage->get_object($master_id)) {
|
||||
$master = $this->_to_driver_event($record);
|
||||
}
|
||||
|
||||
// check for match in top-level exceptions (aka loose single occurrences)
|
||||
if ($master && $master['_formatobj'] && ($instance = $master['_formatobj']->get_instance($instance_id))) {
|
||||
$this->events[$id] = $this->_to_driver_event($instance);
|
||||
}
|
||||
// check for match on the first instance already
|
||||
else if ($master['_instance'] && $master['_instance'] == $instance_id) {
|
||||
$this->events[$id] = $master;
|
||||
}
|
||||
else if ($master && is_array($master['recurrence'])) {
|
||||
$this->get_recurring_events($record, $master['start'], null, $id);
|
||||
if ($master) {
|
||||
// check for match in top-level exceptions (aka loose single occurrences)
|
||||
if ($master['_formatobj'] && ($instance = $master['_formatobj']->get_instance($instance_id))) {
|
||||
$this->events[$id] = $this->_to_driver_event($instance);
|
||||
}
|
||||
// check for match on the first instance already
|
||||
else if ($master['_instance'] && $master['_instance'] == $instance_id) {
|
||||
$this->events[$id] = $master;
|
||||
}
|
||||
else if (is_array($master['recurrence'])) {
|
||||
$this->get_recurring_events($record, $master['start'], null, $id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,7 +294,9 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
}
|
||||
|
||||
// set partstat filter to skip pending and declined invitations
|
||||
if (empty($filter_query) && $this->get_namespace() != 'other') {
|
||||
if (empty($filter_query) && $this->cal->rc->config->get('kolab_invitation_calendars')
|
||||
&& $this->get_namespace() != 'other'
|
||||
) {
|
||||
$partstat_exclude = array('NEEDS-ACTION','DECLINED');
|
||||
}
|
||||
else {
|
||||
|
@ -298,13 +305,13 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
|
||||
$events = array();
|
||||
foreach ($this->storage->select($query) as $record) {
|
||||
$event = $this->_to_driver_event($record, !$virtual);
|
||||
$event = $this->_to_driver_event($record, !$virtual, false);
|
||||
|
||||
// remember seen categories
|
||||
if ($event['categories']) {
|
||||
$cat = is_array($event['categories']) ? $event['categories'][0] : $event['categories'];
|
||||
$this->categories[$cat]++;
|
||||
}
|
||||
}
|
||||
|
||||
// list events in requested time window
|
||||
if ($event['start'] <= $end && $event['end'] >= $start) {
|
||||
|
@ -347,7 +354,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
// add top-level exceptions (aka loose single occurrences)
|
||||
else if (is_array($record['exceptions'])) {
|
||||
foreach ($record['exceptions'] as $ex) {
|
||||
$component = $this->_to_driver_event($ex);
|
||||
$component = $this->_to_driver_event($ex, false, false);
|
||||
if ($component['start'] <= $end && $component['end'] >= $start) {
|
||||
$events[] = $component;
|
||||
}
|
||||
|
@ -381,6 +388,10 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
return true;
|
||||
});
|
||||
|
||||
// Apply event-to-mail relations
|
||||
$config = kolab_storage_config::get_instance();
|
||||
$config->apply_links($events);
|
||||
|
||||
// avoid session race conditions that will loose temporary subscriptions
|
||||
$this->cal->rc->session->nowrite = true;
|
||||
|
||||
|
@ -451,8 +462,8 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
|
||||
//generate new event from RC input
|
||||
$object = $this->_from_driver_event($event);
|
||||
$saved = $this->storage->save($object, 'event');
|
||||
|
||||
$saved = $this->storage->save($object, 'event');
|
||||
|
||||
if (!$saved) {
|
||||
rcube::raise_error(array(
|
||||
'code' => 600, 'type' => 'php',
|
||||
|
@ -463,11 +474,13 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
}
|
||||
else {
|
||||
// save links in configuration.relation object
|
||||
$this->save_links($event['uid'], $links);
|
||||
if ($this->save_links($event['uid'], $links)) {
|
||||
$object['links'] = $links;
|
||||
}
|
||||
|
||||
$this->events = array($event['uid'] => $this->_to_driver_event($object, true));
|
||||
}
|
||||
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
|
@ -490,7 +503,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
unset($event['links']);
|
||||
|
||||
$object = $this->_from_driver_event($event, $old);
|
||||
$saved = $this->storage->save($object, 'event', $old['uid']);
|
||||
$saved = $this->storage->save($object, 'event', $old['uid']);
|
||||
|
||||
if (!$saved) {
|
||||
rcube::raise_error(array(
|
||||
|
@ -501,7 +514,9 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
}
|
||||
else {
|
||||
// save links in configuration.relation object
|
||||
$this->save_links($event['uid'], $links);
|
||||
if ($this->save_links($event['uid'], $links)) {
|
||||
$object['links'] = $links;
|
||||
}
|
||||
|
||||
$updated = true;
|
||||
$this->events = array($event['uid'] => $this->_to_driver_event($object, true));
|
||||
|
@ -572,14 +587,8 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
*/
|
||||
protected function save_links($uid, $links)
|
||||
{
|
||||
// make sure we have a valid array
|
||||
if (empty($links)) {
|
||||
$links = array();
|
||||
}
|
||||
|
||||
$storage = kolab_storage_config::get_instance();
|
||||
$remove = array_diff($storage->get_object_links($uid), $links);
|
||||
return $storage->save_object_links($uid, $links, $remove);
|
||||
return $storage->save_object_links($uid, (array) $links);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -603,14 +612,8 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
|
||||
// determine a reasonable end date if none given
|
||||
if (!$end) {
|
||||
switch ($event['recurrence']['FREQ']) {
|
||||
case 'YEARLY': $intvl = 'P100Y'; break;
|
||||
case 'MONTHLY': $intvl = 'P20Y'; break;
|
||||
default: $intvl = 'P10Y'; break;
|
||||
}
|
||||
|
||||
$end = clone $event['start'];
|
||||
$end->add(new DateInterval($intvl));
|
||||
$end->add(new DateInterval('P100Y'));
|
||||
}
|
||||
|
||||
// copy the recurrence rule from the master event (to be used in the UI)
|
||||
|
@ -628,7 +631,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
if (!$exception['_instance'])
|
||||
$exception['_instance'] = libcalendaring::recurrence_instance_identifier($exception);
|
||||
|
||||
$rec_event = $this->_to_driver_event($exception);
|
||||
$rec_event = $this->_to_driver_event($exception, false, false);
|
||||
$rec_event['id'] = $event['uid'] . '-' . $exception['_instance'];
|
||||
$rec_event['isexception'] = 1;
|
||||
|
||||
|
@ -667,22 +670,34 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
|
||||
$i = 0;
|
||||
while ($next_event = $recurrence->next_instance()) {
|
||||
$datestr = $next_event['start']->format('Ymd');
|
||||
$datestr = $next_event['start']->format('Ymd');
|
||||
$instance_id = $next_event['start']->format($recurrence_id_format);
|
||||
|
||||
// use this event data for future recurring instances
|
||||
if ($futuredata[$datestr])
|
||||
$overlay_data = $futuredata[$datestr];
|
||||
|
||||
$rec_id = $event['uid'] . '-' . $instance_id;
|
||||
$exception = $exdata[$datestr] ?: $overlay_data;
|
||||
$event_start = $next_event['start'];
|
||||
$event_end = $next_event['end'];
|
||||
|
||||
// copy some event from exception to get proper start/end dates
|
||||
if ($exception) {
|
||||
$event_copy = $next_event;
|
||||
kolab_driver::merge_exception_dates($event_copy, $exception);
|
||||
$event_start = $event_copy['start'];
|
||||
$event_end = $event_copy['end'];
|
||||
}
|
||||
|
||||
// add to output if in range
|
||||
$rec_id = $event['uid'] . '-' . $instance_id;
|
||||
if (($next_event['start'] <= $end && $next_event['end'] >= $start) || ($event_id && $rec_id == $event_id)) {
|
||||
$rec_event = $this->_to_driver_event($next_event);
|
||||
if (($event_start <= $end && $event_end >= $start) || ($event_id && $rec_id == $event_id)) {
|
||||
$rec_event = $this->_to_driver_event($next_event, false, false);
|
||||
$rec_event['_instance'] = $instance_id;
|
||||
$rec_event['_count'] = $i + 1;
|
||||
|
||||
if ($overlay_data || $exdata[$datestr]) // copy data from exception
|
||||
kolab_driver::merge_exception_data($rec_event, $exdata[$datestr] ?: $overlay_data);
|
||||
if ($exception) // copy data from exception
|
||||
kolab_driver::merge_exception_data($rec_event, $exception);
|
||||
|
||||
$rec_event['id'] = $rec_id;
|
||||
$rec_event['recurrence_id'] = $event['uid'];
|
||||
|
@ -699,7 +714,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
break;
|
||||
|
||||
// avoid endless recursion loops
|
||||
if (++$i > 1000)
|
||||
if (++$i > 100000)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -709,10 +724,13 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
/**
|
||||
* Convert from Kolab_Format to internal representation
|
||||
*/
|
||||
private function _to_driver_event($record, $noinst = false)
|
||||
private function _to_driver_event($record, $noinst = false, $links = true)
|
||||
{
|
||||
$record['calendar'] = $this->id;
|
||||
$record['links'] = $this->get_links($record['uid']);
|
||||
|
||||
if ($links && !array_key_exists('links', $record)) {
|
||||
$record['links'] = $this->get_links($record['uid']);
|
||||
}
|
||||
|
||||
if ($this->get_namespace() == 'other') {
|
||||
$record['className'] = 'fc-event-ns-other';
|
||||
|
@ -745,11 +763,25 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
private function _from_driver_event($event, $old = array())
|
||||
{
|
||||
// set current user as ORGANIZER
|
||||
$identity = $this->cal->rc->user->list_emails(true);
|
||||
if (empty($event['attendees']) && $identity['email'])
|
||||
$event['attendees'] = array(array('role' => 'ORGANIZER', 'name' => $identity['name'], 'email' => $identity['email']));
|
||||
if ($identity = $this->cal->rc->user->list_emails(true)) {
|
||||
$event['attendees'] = (array) $event['attendees'];
|
||||
$found = false;
|
||||
|
||||
$event['_owner'] = $identity['email'];
|
||||
// there can be only resources on attendees list (T1484)
|
||||
// let's check the existence of an organizer
|
||||
foreach ($event['attendees'] as $attendee) {
|
||||
if ($attendee['role'] == 'ORGANIZER') {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found) {
|
||||
$event['attendees'][] = array('role' => 'ORGANIZER', 'name' => $identity['name'], 'email' => $identity['email']);
|
||||
}
|
||||
|
||||
$event['_owner'] = $identity['email'];
|
||||
}
|
||||
|
||||
// remove EXDATE values if RDATE is given
|
||||
if (!empty($event['recurrence']['RDATE'])) {
|
||||
|
@ -774,7 +806,6 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
// remove some internal properties which should not be saved
|
||||
unset($event['_savemode'], $event['_fromcalendar'], $event['_identity'], $event['_folder_id'],
|
||||
$event['recurrence_id'], $event['attachments'], $event['deleted_attachments'], $event['className']);
|
||||
|
|
|
@ -57,12 +57,11 @@ class kolab_driver extends calendar_driver
|
|||
require_once(dirname(__FILE__) . '/kolab_invitation_calendar.php');
|
||||
|
||||
$this->cal = $cal;
|
||||
$this->rc = $cal->rc;
|
||||
$this->_read_calendars();
|
||||
|
||||
$this->rc = $cal->rc;
|
||||
|
||||
$this->cal->register_action('push-freebusy', array($this, 'push_freebusy'));
|
||||
$this->cal->register_action('calendar-acl', array($this, 'calendar_acl'));
|
||||
|
||||
|
||||
$this->freebusy_trigger = $this->rc->config->get('calendar_freebusy_trigger', false);
|
||||
|
||||
if (kolab_storage::$version == '2.0') {
|
||||
|
@ -89,11 +88,11 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
// get all folders that have "event" type, sorted by namespace/name
|
||||
$folders = kolab_storage::sort_folders(kolab_storage::get_folders('event') + kolab_storage::get_user_folders('event', true));
|
||||
$this->calendars = array();
|
||||
|
||||
$this->calendars = array();
|
||||
foreach ($folders as $folder) {
|
||||
if ($folder instanceof kolab_storage_folder_user) {
|
||||
$calendar = new kolab_user_calendar($folder->name, $this->cal);
|
||||
$calendar = new kolab_user_calendar($folder, $this->cal);
|
||||
$calendar->subscriptions = count($folder->children) > 0;
|
||||
}
|
||||
else {
|
||||
|
@ -120,10 +119,12 @@ class kolab_driver extends calendar_driver
|
|||
*/
|
||||
public function list_calendars($filter = 0, &$tree = null)
|
||||
{
|
||||
$this->_read_calendars();
|
||||
|
||||
// attempt to create a default calendar for this user
|
||||
if (!$this->has_writeable) {
|
||||
if ($this->create_calendar(array('name' => 'Calendar', 'color' => 'cc0000'))) {
|
||||
unset($this->calendars);
|
||||
unset($this->calendars);
|
||||
$this->_read_calendars();
|
||||
}
|
||||
}
|
||||
|
@ -162,8 +163,8 @@ class kolab_driver extends calendar_driver
|
|||
// special handling for user or virtual folders
|
||||
if ($cal instanceof kolab_storage_folder_user) {
|
||||
$calendars[$cal->id] = array(
|
||||
'id' => $cal->id,
|
||||
'name' => kolab_storage::object_name($fullname),
|
||||
'id' => $cal->id,
|
||||
'name' => $fullname,
|
||||
'listname' => $listname,
|
||||
'editname' => $cal->get_foldername(),
|
||||
'color' => $cal->get_color(),
|
||||
|
@ -287,22 +288,23 @@ class kolab_driver extends calendar_driver
|
|||
*/
|
||||
protected function filter_calendars($filter)
|
||||
{
|
||||
$this->_read_calendars();
|
||||
|
||||
$calendars = array();
|
||||
|
||||
$plugin = $this->rc->plugins->exec_hook('calendar_list_filter', array(
|
||||
'list' => $this->calendars,
|
||||
'calendars' => $calendars,
|
||||
'filter' => $filter,
|
||||
'editable' => ($filter & self::FILTER_WRITEABLE),
|
||||
'insert' => ($filter & self::FILTER_INSERTABLE),
|
||||
'active' => ($filter & self::FILTER_ACTIVE),
|
||||
'personal' => ($filter & self::FILTER_PERSONAL)
|
||||
));
|
||||
|
||||
if ($plugin['abort']) {
|
||||
return $plugin['calendars'];
|
||||
}
|
||||
|
||||
$personal = $filter & self::FILTER_PERSONAL;
|
||||
$shared = $filter & self::FILTER_SHARED;
|
||||
|
||||
foreach ($this->calendars as $cal) {
|
||||
if (!$cal->ready) {
|
||||
continue;
|
||||
|
@ -322,9 +324,13 @@ class kolab_driver extends calendar_driver
|
|||
if (($filter & self::FILTER_CONFIDENTIAL) && $cal->subtype != 'confidential') {
|
||||
continue;
|
||||
}
|
||||
if (($filter & self::FILTER_PERSONAL) && $cal->get_namespace() != 'personal') {
|
||||
continue;
|
||||
if ($personal || $shared) {
|
||||
$ns = $cal->get_namespace();
|
||||
if (!(($personal && $ns == 'personal') || ($shared && $ns == 'shared'))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$calendars[$cal->id] = $cal;
|
||||
}
|
||||
|
||||
|
@ -340,14 +346,19 @@ class kolab_driver extends calendar_driver
|
|||
*/
|
||||
public function get_calendar($id)
|
||||
{
|
||||
$this->_read_calendars();
|
||||
|
||||
// create calendar object if necesary
|
||||
if (!$this->calendars[$id] && in_array($id, array(self::INVITATIONS_CALENDAR_PENDING, self::INVITATIONS_CALENDAR_DECLINED))) {
|
||||
$this->calendars[$id] = new kolab_invitation_calendar($id, $this->cal);
|
||||
}
|
||||
else if (!$this->calendars[$id] && $id !== self::BIRTHDAY_CALENDAR_ID) {
|
||||
$calendar = kolab_calendar::factory($id, $this->cal);
|
||||
if ($calendar->ready)
|
||||
$this->calendars[$calendar->id] = $calendar;
|
||||
if (!$this->calendars[$id]) {
|
||||
if (in_array($id, array(self::INVITATIONS_CALENDAR_PENDING, self::INVITATIONS_CALENDAR_DECLINED))) {
|
||||
$this->calendars[$id] = new kolab_invitation_calendar($id, $this->cal);
|
||||
}
|
||||
else if ($id !== self::BIRTHDAY_CALENDAR_ID) {
|
||||
$calendar = kolab_calendar::factory($id, $this->cal);
|
||||
if ($calendar->ready) {
|
||||
$this->calendars[$calendar->id] = $calendar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->calendars[$id];
|
||||
|
@ -592,8 +603,12 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
$event = self::from_rcube_event($event);
|
||||
|
||||
$cid = $event['calendar'] ? $event['calendar'] : reset(array_keys($this->calendars));
|
||||
if ($storage = $this->get_calendar($cid)) {
|
||||
if (!$event['calendar']) {
|
||||
$this->_read_calendars();
|
||||
$event['calendar'] = reset(array_keys($this->calendars));
|
||||
}
|
||||
|
||||
if ($storage = $this->get_calendar($event['calendar'])) {
|
||||
// if this is a recurrence instance, append as exception to an already existing object for this UID
|
||||
if (!empty($event['recurrence_date']) && ($master = $storage->get_event($event['uid']))) {
|
||||
self::add_exception($master, $event);
|
||||
|
@ -885,7 +900,7 @@ class kolab_driver extends calendar_driver
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($success && $this->freebusy_trigger)
|
||||
$this->rc->output->command('plugin.ping_url', array('action' => 'calendar/push-freebusy', 'source' => $storage->id));
|
||||
|
||||
|
@ -1012,7 +1027,7 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
// copy attachment metadata to new event
|
||||
$event = self::from_rcube_event($event, $master);
|
||||
|
||||
|
||||
// remove recurrence exceptions on re-scheduling
|
||||
if ($reschedule) {
|
||||
unset($event['recurrence']['EXCEPTIONS'], $event['exceptions'], $master['recurrence']['EXDATE']);
|
||||
|
@ -1378,7 +1393,6 @@ class kolab_driver extends calendar_driver
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge certain properties from the overlay event to the base event object
|
||||
*
|
||||
|
@ -1393,25 +1407,9 @@ class kolab_driver extends calendar_driver
|
|||
if (is_array($blacklist))
|
||||
$forbidden = array_merge($forbidden, $blacklist);
|
||||
|
||||
// compute date offset from the exception
|
||||
if ($overlay['start'] instanceof DateTime && $overlay['recurrence_date'] instanceof DateTime) {
|
||||
$date_offset = $overlay['recurrence_date']->diff($overlay['start']);
|
||||
}
|
||||
|
||||
foreach ($overlay as $prop => $value) {
|
||||
if ($prop == 'start' || $prop == 'end') {
|
||||
if (is_object($event[$prop]) && $event[$prop] instanceof DateTime) {
|
||||
// set date value if overlay is an exception of the current instance
|
||||
if (substr($overlay['_instance'], 0, 8) == substr($event['_instance'], 0, 8)) {
|
||||
$event[$prop]->setDate(intval($value->format('Y')), intval($value->format('n')), intval($value->format('j')));
|
||||
}
|
||||
// apply date offset
|
||||
else if ($date_offset) {
|
||||
$event[$prop]->add($date_offset);
|
||||
}
|
||||
// adjust time of the recurring event instance
|
||||
$event[$prop]->setTime($value->format('G'), intval($value->format('i')), intval($value->format('s')));
|
||||
}
|
||||
// handled by merge_exception_dates() below
|
||||
}
|
||||
else if ($prop == 'thisandfuture' && $overlay['_instance'] == $event['_instance']) {
|
||||
$event[$prop] = $value;
|
||||
|
@ -1419,6 +1417,38 @@ class kolab_driver extends calendar_driver
|
|||
else if ($prop[0] != '_' && !in_array($prop, $forbidden))
|
||||
$event[$prop] = $value;
|
||||
}
|
||||
|
||||
self::merge_exception_dates($event, $overlay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge start/end date from the overlay event to the base event object
|
||||
*
|
||||
* @param array The event object to be altered
|
||||
* @param array The overlay event object to be merged over $event
|
||||
*/
|
||||
public static function merge_exception_dates(&$event, $overlay)
|
||||
{
|
||||
// compute date offset from the exception
|
||||
if ($overlay['start'] instanceof DateTime && $overlay['recurrence_date'] instanceof DateTime) {
|
||||
$date_offset = $overlay['recurrence_date']->diff($overlay['start']);
|
||||
}
|
||||
|
||||
foreach (array('start', 'end') as $prop) {
|
||||
$value = $overlay[$prop];
|
||||
if (is_object($event[$prop]) && $event[$prop] instanceof DateTime) {
|
||||
// set date value if overlay is an exception of the current instance
|
||||
if (substr($overlay['_instance'], 0, 8) == substr($event['_instance'], 0, 8)) {
|
||||
$event[$prop]->setDate(intval($value->format('Y')), intval($value->format('n')), intval($value->format('j')));
|
||||
}
|
||||
// apply date offset
|
||||
else if ($date_offset) {
|
||||
$event[$prop]->add($date_offset);
|
||||
}
|
||||
// adjust time of the recurring event instance
|
||||
$event[$prop]->setTime($value->format('G'), intval($value->format('i')), intval($value->format('s')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1436,8 +1466,10 @@ class kolab_driver extends calendar_driver
|
|||
{
|
||||
if ($calendars && is_string($calendars))
|
||||
$calendars = explode(',', $calendars);
|
||||
else if (!$calendars)
|
||||
else if (!$calendars) {
|
||||
$this->_read_calendars();
|
||||
$calendars = array_keys($this->calendars);
|
||||
}
|
||||
|
||||
$query = array();
|
||||
if ($modifiedsince)
|
||||
|
@ -1482,8 +1514,10 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
if ($calendars && is_string($calendars))
|
||||
$calendars = explode(',', $calendars);
|
||||
else if (!$calendars)
|
||||
else if (!$calendars) {
|
||||
$this->_read_calendars();
|
||||
$calendars = array_keys($this->calendars);
|
||||
}
|
||||
|
||||
foreach ($calendars as $cid) {
|
||||
if ($storage = $this->get_calendar($cid)) {
|
||||
|
@ -1521,6 +1555,9 @@ class kolab_driver extends calendar_driver
|
|||
|
||||
$candidates = array();
|
||||
$query = array(array('tags', '=', 'x-has-alarms'));
|
||||
|
||||
$this->_read_calendars();
|
||||
|
||||
foreach ($this->calendars as $cid => $calendar) {
|
||||
// skip calendars with alarms disabled
|
||||
if (!$calendar->alarms || ($calendars && !in_array($cid, $calendars)))
|
||||
|
@ -1633,15 +1670,14 @@ class kolab_driver extends calendar_driver
|
|||
$event = $storage->get_event($event['id']);
|
||||
}
|
||||
|
||||
if ($event && !empty($event['_attachments'])) {
|
||||
foreach ($event['_attachments'] as $att) {
|
||||
if ($event) {
|
||||
$attachments = isset($event['_attachments']) ? $event['_attachments'] : $event['attachments'];
|
||||
foreach ((array) $attachments as $att) {
|
||||
if ($att['id'] == $id) {
|
||||
return $att;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1953,46 +1989,7 @@ class kolab_driver extends calendar_driver
|
|||
*/
|
||||
public static function from_rcube_event($event, $old = array())
|
||||
{
|
||||
// in kolab_storage attachments are indexed by content-id
|
||||
if (is_array($event['attachments']) || !empty($event['deleted_attachments'])) {
|
||||
$event['_attachments'] = array();
|
||||
|
||||
foreach ($event['attachments'] as $attachment) {
|
||||
$key = null;
|
||||
// Roundcube ID has nothing to do with the storage ID, remove it
|
||||
if ($attachment['content'] || $attachment['path']) {
|
||||
unset($attachment['id']);
|
||||
}
|
||||
else {
|
||||
foreach ((array)$old['_attachments'] as $cid => $oldatt) {
|
||||
if ($attachment['id'] == $oldatt['id'])
|
||||
$key = $cid;
|
||||
}
|
||||
}
|
||||
|
||||
// flagged for deletion => set to false
|
||||
if ($attachment['_deleted'] || in_array($attachment['id'], (array)$event['deleted_attachments'])) {
|
||||
$event['_attachments'][$key] = false;
|
||||
}
|
||||
// replace existing entry
|
||||
else if ($key) {
|
||||
$event['_attachments'][$key] = $attachment;
|
||||
}
|
||||
// append as new attachment
|
||||
else {
|
||||
$event['_attachments'][] = $attachment;
|
||||
}
|
||||
}
|
||||
|
||||
$event['_attachments'] = array_merge((array)$old['_attachments'], $event['_attachments']);
|
||||
|
||||
// attachments flagged for deletion => set to false
|
||||
foreach ($event['_attachments'] as $key => $attachment) {
|
||||
if ($attachment['_deleted'] || in_array($attachment['id'], (array)$event['deleted_attachments'])) {
|
||||
$event['_attachments'][$key] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
kolab_format::merge_attachments($event, $old);
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
@ -2317,6 +2314,8 @@ class kolab_driver extends calendar_driver
|
|||
return parent::calendar_form($action, $calendar, $formfields);
|
||||
}
|
||||
|
||||
$this->_read_calendars();
|
||||
|
||||
if ($calendar['id'] && ($cal = $this->calendars[$calendar['id']])) {
|
||||
$folder = $cal->get_realname(); // UTF7
|
||||
$color = $cal->get_color();
|
||||
|
@ -2450,7 +2449,7 @@ class kolab_driver extends calendar_driver
|
|||
if (is_array($form['content']) && !empty($form['content'])) {
|
||||
$table = new html_table(array('cols' => 2));
|
||||
foreach ($form['content'] as $col => $colprop) {
|
||||
$label = !empty($colprop['label']) ? $colprop['label'] : $this->rc->gettext($col);
|
||||
$label = !empty($colprop['label']) ? $colprop['label'] : $this->cal->gettext($col);
|
||||
|
||||
$table->add('title', html::label($colprop['id'], rcube::Q($label)));
|
||||
$table->add(null, $colprop['value']);
|
||||
|
|
|
@ -34,6 +34,7 @@ class kolab_invitation_calendar
|
|||
public $categories = array();
|
||||
public $name = 'Invitations';
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
|
@ -62,7 +63,6 @@ class kolab_invitation_calendar
|
|||
$this->alarms = $prefs[$this->id]['showalarms'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for a nice and human readable name for this calendar
|
||||
*
|
||||
|
@ -73,7 +73,6 @@ class kolab_invitation_calendar
|
|||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the IMAP folder owner
|
||||
*
|
||||
|
@ -84,7 +83,6 @@ class kolab_invitation_calendar
|
|||
return $this->cal->rc->get_user_name();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -93,7 +91,6 @@ class kolab_invitation_calendar
|
|||
return $this->get_name();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the name of the namespace to which the IMAP folder belongs
|
||||
*
|
||||
|
@ -104,7 +101,6 @@ class kolab_invitation_calendar
|
|||
return 'x-special';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the top-end calendar folder name (not the entire path)
|
||||
*
|
||||
|
@ -171,7 +167,6 @@ class kolab_invitation_calendar
|
|||
return $prop['id'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for a single event object
|
||||
*/
|
||||
|
@ -202,7 +197,7 @@ class kolab_invitation_calendar
|
|||
else {
|
||||
$cal = null;
|
||||
foreach (kolab_storage::list_folders('', '*', 'event', null) as $foldername) {
|
||||
$cal = new kolab_calendar($foldername, $this->cal);
|
||||
$cal = $this->_get_calendar($foldername);
|
||||
if ($cal->ready && $cal->storage && $cal->get_event($event['id'])) {
|
||||
break;
|
||||
}
|
||||
|
@ -216,7 +211,6 @@ class kolab_invitation_calendar
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param integer Event's new start (unix timestamp)
|
||||
* @param integer Event's new end (unix timestamp)
|
||||
|
@ -239,7 +233,7 @@ class kolab_invitation_calendar
|
|||
// aggregate events from all calendar folders
|
||||
$events = array();
|
||||
foreach (kolab_storage::list_folders('', '*', 'event', null) as $foldername) {
|
||||
$cal = new kolab_calendar($foldername, $this->cal);
|
||||
$cal = $this->_get_calendar($foldername);
|
||||
if ($cal->get_namespace() == 'other')
|
||||
continue;
|
||||
|
||||
|
@ -257,7 +251,7 @@ class kolab_invitation_calendar
|
|||
}
|
||||
|
||||
if ($match) {
|
||||
$events[$event['id']] = $this->_mod_event($event);
|
||||
$events[$event['id'] ?: $event['uid']] = $this->_mod_event($event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,7 +287,7 @@ class kolab_invitation_calendar
|
|||
// aggregate counts from all calendar folders
|
||||
$count = 0;
|
||||
foreach (kolab_storage::list_folders('', '*', 'event', null) as $foldername) {
|
||||
$cal = new kolab_calendar($foldername, $this->cal);
|
||||
$cal = $this->_get_calendar($foldername);
|
||||
if ($cal->get_namespace() == 'other')
|
||||
continue;
|
||||
|
||||
|
@ -303,6 +297,15 @@ class kolab_invitation_calendar
|
|||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get calendar object instance (that maybe already initialized)
|
||||
*/
|
||||
private function _get_calendar($folder_name)
|
||||
{
|
||||
$id = kolab_storage::folder_id($folder_name, true);
|
||||
return $this->cal->driver->get_calendar($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to modify some event properties
|
||||
*/
|
||||
|
@ -318,7 +321,6 @@ class kolab_invitation_calendar
|
|||
return $event;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new event record
|
||||
*
|
||||
|
@ -337,7 +339,6 @@ class kolab_invitation_calendar
|
|||
* @see calendar_driver::new_event()
|
||||
* @return boolean True on success, False on error
|
||||
*/
|
||||
|
||||
public function update_event($event, $exception_id = null)
|
||||
{
|
||||
// forward call to the actual storage folder
|
||||
|
@ -372,6 +373,4 @@ class kolab_invitation_calendar
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* @author Thomas Bruederli <bruederli@kolabsys.com>
|
||||
*
|
||||
* Copyright (C) 2014-2015, Kolab Systems AG <contact@kolabsys.com>
|
||||
* Copyright (C) 2014-2016, Kolab Systems AG <contact@kolabsys.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
|
@ -45,8 +45,12 @@ class kolab_user_calendar extends kolab_calendar
|
|||
$this->userdata = $user_or_folder;
|
||||
$this->storage = new kolab_storage_folder_user($this->userdata['kolabtargetfolder'], '', $this->userdata);
|
||||
}
|
||||
else if ($user_or_folder instanceof kolab_storage_folder_user) {
|
||||
$this->storage = $user_or_folder;
|
||||
$this->userdata = $this->storage->ldaprec;
|
||||
}
|
||||
else { // get user record from LDAP
|
||||
$this->storage = new kolab_storage_folder_user($user_or_folder);
|
||||
$this->storage = new kolab_storage_folder_user($user_or_folder);
|
||||
$this->userdata = $this->storage->ldaprec;
|
||||
}
|
||||
|
||||
|
@ -57,7 +61,7 @@ class kolab_user_calendar extends kolab_calendar
|
|||
// ID is derrived from the user's kolabtargetfolder attribute
|
||||
$this->id = kolab_storage::folder_id($this->userdata['kolabtargetfolder'], true);
|
||||
$this->imap_folder = $this->userdata['kolabtargetfolder'];
|
||||
$this->name = $this->storage->get_name();
|
||||
$this->name = $this->storage->name;
|
||||
$this->parent = ''; // user calendars are top level
|
||||
|
||||
// user-specific alarms settings win
|
||||
|
@ -67,7 +71,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for a nice and human readable name for this calendar
|
||||
*
|
||||
|
@ -78,7 +81,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return $this->userdata['displayname'] ?: ($this->userdata['name'] ?: $this->userdata['mail']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the IMAP folder owner
|
||||
*
|
||||
|
@ -89,7 +91,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return $this->userdata['mail'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -98,7 +99,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return trim($this->userdata['displayname'] . '; ' . $this->userdata['mail'], '; ');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the name of the namespace to which the IMAP folder belongs
|
||||
*
|
||||
|
@ -109,7 +109,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return 'other user';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the top-end calendar folder name (not the entire path)
|
||||
*
|
||||
|
@ -164,7 +163,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
return $prop['id'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for a single event object
|
||||
*/
|
||||
|
@ -225,12 +223,13 @@ class kolab_user_calendar extends kolab_calendar
|
|||
}
|
||||
}
|
||||
|
||||
// aggregate all calendar folders the user shares (but are not subscribed)
|
||||
foreach (kolab_storage::list_user_folders($this->userdata, 'event', false) as $foldername) {
|
||||
// aggregate all calendar folders the user shares (but are not activated)
|
||||
foreach (kolab_storage::list_user_folders($this->userdata, 'event', 2) as $foldername) {
|
||||
$cal = new kolab_calendar($foldername, $this->cal);
|
||||
foreach ($cal->list_events($start, $end, $search, 1) as $event) {
|
||||
$this->events[$event['id']] = $event;
|
||||
$this->timeindex[$this->time_key($event)] = $event['id'];
|
||||
$uid = $event['id'] ?: $event['uid'];
|
||||
$this->events[$uid] = $event;
|
||||
$this->timeindex[$this->time_key($event)] = $uid;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,7 +317,7 @@ class kolab_user_calendar extends kolab_calendar
|
|||
'X-OUT-OF-OFFICE' => $this->cal->gettext('availoutofoffice'),
|
||||
);
|
||||
|
||||
// rcmail::console('_fetch_freebusy', kolab_storage::get_freebusy_url($this->userdata['mail']), $fbdata);
|
||||
// rcube::console('_fetch_freebusy', kolab_storage::get_freebusy_url($this->userdata['mail']), $fbdata);
|
||||
|
||||
// parse free-busy information
|
||||
$count = 0;
|
||||
|
@ -334,7 +333,7 @@ class kolab_user_calendar extends kolab_calendar
|
|||
foreach ($fb['periods'] as $tuple) {
|
||||
list($from, $to, $type) = $tuple;
|
||||
$event = array(
|
||||
'id' => md5($this->id . $from->format('U') . '/' . $to->format('U')),
|
||||
'uid' => md5($this->id . $from->format('U') . '/' . $to->format('U')),
|
||||
'calendar' => $this->id,
|
||||
'changed' => $fb['created'] ?: new DateTime(),
|
||||
'title' => $this->get_name() . ' ' . ($titlemap[$type] ?: $type),
|
||||
|
@ -351,8 +350,8 @@ class kolab_user_calendar extends kolab_calendar
|
|||
// avoid duplicate entries
|
||||
$key = $this->time_key($event);
|
||||
if (!$this->timeindex[$key]) {
|
||||
$this->events[$event['id']] = $event;
|
||||
$this->timeindex[$key] = $event['id'];
|
||||
$this->events[$event['uid']] = $event;
|
||||
$this->timeindex[$key] = $event['uid'];
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
@ -367,10 +366,9 @@ class kolab_user_calendar extends kolab_calendar
|
|||
*/
|
||||
private function time_key($event)
|
||||
{
|
||||
return sprintf('%s/%s', $event['start']->format('U'), is_object($event['end']->format('U')) ?: '0');
|
||||
return sprintf('%s/%s', $event['start']->format('U'), is_object($event['end']) ? $event['end']->format('U') : '0');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new event record
|
||||
*
|
||||
|
@ -389,7 +387,6 @@ class kolab_user_calendar extends kolab_calendar
|
|||
* @see calendar_driver::new_event()
|
||||
* @return boolean True on success, False on error
|
||||
*/
|
||||
|
||||
public function update_event($event, $exception_id = null)
|
||||
{
|
||||
return false;
|
||||
|
@ -416,17 +413,4 @@ class kolab_user_calendar extends kolab_calendar
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert from Kolab_Format to internal representation
|
||||
*/
|
||||
private function _to_rcube_event($record)
|
||||
{
|
||||
$record['id'] = $record['uid'];
|
||||
$record['calendar'] = $this->id;
|
||||
|
||||
return kolab_driver::to_rcube_event($record);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -177,7 +177,7 @@ class calendar_ui
|
|||
{
|
||||
$color = $prop['color'];
|
||||
$class = 'cal-' . asciiwords($id, true);
|
||||
$css .= "li .$class, #eventshow .$class { color: #$color }\n";
|
||||
$css .= "li .$class, #eventshow .$class { color: #$color; }\n";
|
||||
|
||||
if ($mode != 1) {
|
||||
if ($mode == 3) {
|
||||
|
@ -189,7 +189,7 @@ class calendar_ui
|
|||
$css .= ".fc-event-$class, ";
|
||||
$css .= ".fc-event-$class .fc-event-inner {";
|
||||
}
|
||||
if (!$attrib['printmode'])
|
||||
if (!$prop['printmode'])
|
||||
$css .= " background-color: #$color;";
|
||||
if ($mode % 2 == 0)
|
||||
$css .= " border-color: #$color;";
|
||||
|
@ -585,7 +585,7 @@ class calendar_ui
|
|||
|
||||
$checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'event-export-attachments', 'value' => 1));
|
||||
$html .= html::div('form-section',
|
||||
html::label('event-export-range', $this->cal->gettext('exportattachments')) .
|
||||
html::label('event-export-attachments', $this->cal->gettext('exportattachments')) .
|
||||
$checkbox->show(1)
|
||||
);
|
||||
|
||||
|
@ -607,7 +607,7 @@ class calendar_ui
|
|||
$attrib['id'] = 'rcmUploadForm';
|
||||
|
||||
// Get max filesize, enable upload progress bar
|
||||
$max_filesize =$this->rc->upload_init();
|
||||
$max_filesize = $this->rc->upload_init();
|
||||
|
||||
$button = new html_inputfield(array('type' => 'button'));
|
||||
$input = new html_inputfield(array(
|
||||
|
@ -616,7 +616,7 @@ class calendar_ui
|
|||
|
||||
return html::div($attrib,
|
||||
html::div(null, $input->show()) .
|
||||
html::div('formbuttons', $button->show($this->rc->gettext('upload'), array('class' => 'button mainaction',
|
||||
html::div('buttons', $button->show($this->rc->gettext('upload'), array('class' => 'button mainaction',
|
||||
'onclick' => rcmail_output::JS_OBJECT_NAME . ".upload_file(this.form)"))) .
|
||||
html::div('hint', $this->rc->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))))
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
$labels['default_view'] = 'Изглед по подразбиране';
|
||||
$labels['time_format'] = 'Формат на часовете';
|
||||
$labels['timeslots'] = 'Деления за час';
|
||||
$labels['first_day'] = 'Първи ден от седмицата';
|
||||
$labels['first_hour'] = 'Първи час при показване';
|
||||
$labels['workinghours'] = 'Работни часове';
|
||||
|
@ -19,6 +20,12 @@ $labels['coloringmode0'] = 'Според календара';
|
|||
$labels['coloringmode1'] = 'Относно категорията';
|
||||
$labels['coloringmode2'] = 'Календар за очертание, категория за съдържание';
|
||||
$labels['coloringmode3'] = 'Категория за очертание, календар за съдържание';
|
||||
$labels['afternothing'] = 'Не предприемай нищо';
|
||||
$labels['aftertrash'] = 'Премести в Кошчето';
|
||||
$labels['afterdelete'] = 'Изтрий съобщението';
|
||||
$labels['afterflagdeleted'] = 'Маркирай като изтрито';
|
||||
$labels['aftermoveto'] = 'Премести в...';
|
||||
$labels['itipoptions'] = 'Покани за събитие';
|
||||
$labels['calendar'] = 'Календар';
|
||||
$labels['calendars'] = 'Календари';
|
||||
$labels['category'] = 'Категория';
|
||||
|
@ -36,6 +43,7 @@ $labels['new_event'] = 'Добавяне на събитие';
|
|||
$labels['edit_event'] = 'Промяна на събитие';
|
||||
$labels['edit'] = 'Промяна';
|
||||
$labels['save'] = 'Запис';
|
||||
$labels['removelist'] = 'Премахни от списъка';
|
||||
$labels['cancel'] = 'Отказ';
|
||||
$labels['select'] = 'Избиране';
|
||||
$labels['print'] = 'Печат';
|
||||
|
@ -46,30 +54,47 @@ $labels['all-day'] = 'цял ден';
|
|||
$labels['export'] = 'Извличане';
|
||||
$labels['exporttitle'] = 'Извличане към iCalendar';
|
||||
$labels['exportrange'] = 'Събития от';
|
||||
$labels['exportattachments'] = 'С прикачени файлове';
|
||||
$labels['customdate'] = 'Дата по избор';
|
||||
$labels['location'] = 'Местоположение';
|
||||
$labels['url'] = 'URL адрес';
|
||||
$labels['date'] = 'Дата';
|
||||
$labels['start'] = 'Начало';
|
||||
$labels['starttime'] = 'Време за начало';
|
||||
$labels['end'] = 'Край';
|
||||
$labels['endtime'] = 'Време за край';
|
||||
$labels['repeat'] = 'Повтори';
|
||||
$labels['selectdate'] = 'Избор на дата';
|
||||
$labels['freebusy'] = 'Показване като';
|
||||
$labels['free'] = 'Свободно';
|
||||
$labels['busy'] = 'Заето';
|
||||
$labels['outofoffice'] = 'Извън офиса';
|
||||
$labels['tentative'] = 'Предварително';
|
||||
$labels['mystatus'] = 'Моят статус';
|
||||
$labels['status'] = 'Статус';
|
||||
$labels['status-confirmed'] = 'Потвърдено';
|
||||
$labels['status-cancelled'] = 'Отхвърлено';
|
||||
$labels['priority'] = 'Приоритет';
|
||||
$labels['sensitivity'] = 'Частност';
|
||||
$labels['sensitivity'] = 'Поверителност';
|
||||
$labels['public'] = 'публично';
|
||||
$labels['private'] = 'частно';
|
||||
$labels['confidential'] = 'конфиденциално';
|
||||
$labels['links'] = 'Цикличност';
|
||||
$labels['alarms'] = 'Напомняне';
|
||||
$labels['comment'] = 'Коментар';
|
||||
$labels['created'] = 'Създаден';
|
||||
$labels['changed'] = 'Последна промяна';
|
||||
$labels['unknown'] = 'Неизвестно';
|
||||
$labels['eventoptions'] = 'Опции';
|
||||
$labels['generated'] = 'генерирано в';
|
||||
$labels['eventhistory'] = 'История';
|
||||
$labels['removelink'] = 'Премахни е-мейл препратките';
|
||||
$labels['printdescriptions'] = 'Печат на описанията';
|
||||
$labels['parentcalendar'] = 'Внасяне вътре';
|
||||
$labels['searchearlierdates'] = '« Търсене за по- стари събития';
|
||||
$labels['searchlaterdates'] = 'Търсене за по- нови събития »';
|
||||
$labels['andnmore'] = '$nr повече...';
|
||||
$labels['togglerole'] = 'Натиснете за превключване на роля';
|
||||
$labels['createfrommail'] = 'Запазване като събитие';
|
||||
$labels['importevents'] = 'Внасяне на събития';
|
||||
$labels['importrange'] = 'Събития от';
|
||||
|
@ -77,6 +102,15 @@ $labels['onemonthback'] = '1 месец назад';
|
|||
$labels['nmonthsback'] = '$nr месеца назад';
|
||||
$labels['showurl'] = 'Показване на URL на календара';
|
||||
$labels['showurldescription'] = 'Използвайте следния адрес, за да достъпвате (само за четене) вашия календар от други приложения. Можете да копирате и поставяте това във всеки календарен софтуер, поддържащ форматът iCal';
|
||||
$labels['searchterms'] = 'Търсене за';
|
||||
$labels['calendarsubscribe'] = 'Постоянен списък';
|
||||
$labels['nocalendarsfound'] = 'Не бяха намерени календари';
|
||||
$labels['nrcalendarsfound'] = 'Бяха намерени $nr календара';
|
||||
$labels['quickview'] = 'Покажи само този календар';
|
||||
$labels['invitationspending'] = 'Чакащи покани';
|
||||
$labels['invitationsdeclined'] = 'Отхвърлени покани';
|
||||
$labels['changepartstat'] = 'Промени състоянието на участник';
|
||||
$labels['rsvpcomment'] = 'Текст на поканата';
|
||||
$labels['listrange'] = 'Оразмеряване към екран:';
|
||||
$labels['listsections'] = 'Разделяне на:';
|
||||
$labels['smartsections'] = 'Интелигентни секции';
|
||||
|
@ -85,38 +119,79 @@ $labels['today'] = 'Днес';
|
|||
$labels['tomorrow'] = 'Утре';
|
||||
$labels['thisweek'] = 'Тази седмица';
|
||||
$labels['nextweek'] = 'Следващата седмица';
|
||||
$labels['prevweek'] = 'Миналата седмица';
|
||||
$labels['thismonth'] = 'Този месец';
|
||||
$labels['nextmonth'] = 'Следващия месец';
|
||||
$labels['weekofyear'] = 'Седмица';
|
||||
$labels['pastevents'] = 'Минали';
|
||||
$labels['futureevents'] = 'Бъдещи';
|
||||
$labels['showalarms'] = 'Покажи напомняния';
|
||||
$labels['defaultalarmtype'] = 'Настройка за напомняне по подразбиране';
|
||||
$labels['defaultalarmoffset'] = 'Време за напомняне по подразбиране';
|
||||
$labels['attendee'] = 'Участник';
|
||||
$labels['role'] = 'Роля';
|
||||
$labels['availability'] = 'Налич.';
|
||||
$labels['confirmstate'] = 'Статус';
|
||||
$labels['addattendee'] = 'Добавяне на участник';
|
||||
$labels['roleorganizer'] = 'Организатор';
|
||||
$labels['rolerequired'] = 'Задължителен';
|
||||
$labels['roleoptional'] = 'По избор';
|
||||
$labels['availfree'] = 'Свободно';
|
||||
$labels['availbusy'] = 'Заето';
|
||||
$labels['availunknown'] = 'Неизвестно';
|
||||
$labels['rolechair'] = 'Председател';
|
||||
$labels['rolenonparticipant'] = 'Липсващ';
|
||||
$labels['cutypeindividual'] = 'Индивидуален';
|
||||
$labels['cutypegroup'] = 'Група';
|
||||
$labels['cutyperesource'] = 'Ресурс';
|
||||
$labels['cutyperoom'] = 'Стая';
|
||||
$labels['availfree'] = 'Свободен';
|
||||
$labels['availbusy'] = 'Зает';
|
||||
$labels['availunknown'] = 'Няма информация';
|
||||
$labels['availtentative'] = 'Предварително';
|
||||
$labels['availoutofoffice'] = 'Извън офиса';
|
||||
$labels['delegatedto'] = 'Делегирано към:';
|
||||
$labels['delegatedfrom'] = 'Делегирано от:';
|
||||
$labels['sendinvitations'] = 'Изпращане на покани';
|
||||
$labels['sendnotifications'] = 'Известяване на участниците относно промените';
|
||||
$labels['sendcancellation'] = 'Известяване на участниците относно отмяна на събития';
|
||||
$labels['invitationsubject'] = 'Бяхте поканен на "$title"';
|
||||
$labels['eventupdatesubject'] = '"$title" беше отмнено';
|
||||
$labels['itipdeclineevent'] = 'Искате ли да отхвърлите поканата за това събитие?';
|
||||
$labels['saveincalendar'] = 'запазване в';
|
||||
$labels['updatemycopy'] = 'Обнови в моя календар';
|
||||
$labels['savetocalendar'] = 'Запази в календар';
|
||||
$labels['openpreview'] = 'Провери календар';
|
||||
$labels['noearlierevents'] = 'Няма по-ранни събития';
|
||||
$labels['nolaterevents'] = 'Няма по-късни събития';
|
||||
$labels['resource'] = 'Ресурс';
|
||||
$labels['resourcedetails'] = 'Детайли';
|
||||
$labels['resourceowner'] = 'Собственик';
|
||||
$labels['tabsummary'] = 'Заглавие';
|
||||
$labels['tabrecurrence'] = 'Да се повтаря';
|
||||
$labels['tabattendees'] = 'Участници';
|
||||
$labels['tabresources'] = 'Ресурси';
|
||||
$labels['tabattachments'] = 'Прикрепени файлове';
|
||||
$labels['tabsharing'] = 'Споделяне';
|
||||
$labels['deleteobjectconfirm'] = 'Наистина ли искате да премахнете това събитие?';
|
||||
$labels['deleteventconfirm'] = 'Наистина ли искате да премахнете това събитие?';
|
||||
$labels['deletecalendarconfirm'] = 'Наистина ли искате да премахнете този календар с всичките му събития?';
|
||||
$labels['deletecalendarconfirmrecursive'] = 'Наистина ли искате да премахнете този календар с всичките му събития и допълнителни календари?';
|
||||
$labels['savingdata'] = 'Запазване на данни...';
|
||||
$labels['errorsaving'] = 'Неуспешно записването на промените.';
|
||||
$labels['successremoval'] = 'Събитието беше премахнато успешно.';
|
||||
$labels['successrestore'] = 'Събитието беше възстановено успешно.';
|
||||
$labels['importedsuccessfully'] = 'Събитието е добавено успешно към \'$calendar\'';
|
||||
$labels['updatedsuccessfully'] = 'Събитието беше обновено успешно в \'$calendar\'';
|
||||
$labels['importsuccess'] = '$nr събития бяха внесени успешно.';
|
||||
$labels['importnone'] = 'Не бяха намерени събития за внасяне';
|
||||
$labels['importerror'] = 'Възникна грешка при внасянето на събития';
|
||||
$labels['aclnorights'] = 'Не разполагате с административни права върху този календар.';
|
||||
$labels['changeeventconfirm'] = 'Промяна на събитие';
|
||||
$labels['removeeventconfirm'] = 'Изтриване на събитие';
|
||||
$labels['currentevent'] = 'Настоящи';
|
||||
$labels['futurevents'] = 'Бъдещи';
|
||||
$labels['allevents'] = 'Всички';
|
||||
$labels['saveasnew'] = 'Запази като нов';
|
||||
$labels['birthdays'] = 'Рождени дни';
|
||||
$labels['arialabelcalendarview'] = 'Преглед на календара';
|
||||
$labels['arialabeleventattendees'] = 'Списък с участниците в събитието';
|
||||
$labels['arialabelresourceselection'] = 'Налични ресурси';
|
||||
?>
|
||||
|
|
|
@ -169,7 +169,6 @@ $labels['invitationattendlinks'] = "En cas que el vostre client de correu electr
|
|||
$labels['eventupdatesubject'] = '"$title" ha estat actualitzat';
|
||||
$labels['eventupdatesubjectempty'] = 'Un esdeveniment que us afecta ha estat actualitzat';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nQuan: \$date\n\nConvidats: \$attendees\n\nSi us plau cerqueu el fitxer iCalendar adjunt dins dels detalls actualitzats de l'esdeveniment per poder-lo importar a la vostra aplicació de calendari.";
|
||||
$labels['eventcancelsubject'] = '"$title" ha estat cancel·lat';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nQuan: \$date\n\nConvidats: \$attendees\n\nL'esdeveniment ha estat cancel·lat per \$organizer.\n\nSi us plau cerqueu el fitxer iCalendar adjunt amb els detalls actualitzats de l'esdeveniment.";
|
||||
$labels['itipobjectnotfound'] = 'L\'esdeveniment que fa referència aquest missatge no s\'ha trobat al vostre calendari.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender ha acceptat la invitació al següent esdeveniment:\n\n*\$title*\n\nQuan: \$date\n\nConvidats: \$attendees";
|
||||
|
|
|
@ -236,6 +236,7 @@ $labels['changeeventconfirm'] = 'Změnit událost';
|
|||
$labels['removeeventconfirm'] = 'Smazat událost';
|
||||
$labels['changerecurringeventwarning'] = 'Toto je opakovaná událost. Chcete upravit jen toto konání, toto a všechna následující konání, úplně všechna konání nebo uložit událost jako novou?';
|
||||
$labels['removerecurringeventwarning'] = 'Toto je opakovaná událost. Chcete smazat jen toto konání, toto a všechna následující konání, nebo úplně všechna konání?';
|
||||
$labels['removerecurringallonly'] = 'Toto je opakovaná událost. Jako účastník můžete smazat pouze celou událost se všemi konáními.';
|
||||
$labels['currentevent'] = 'Nynější';
|
||||
$labels['futurevents'] = 'Budoucí';
|
||||
$labels['allevents'] = 'Vše';
|
||||
|
@ -247,10 +248,13 @@ $labels['birthdayscalendarsources'] = 'Z těchto adresářů';
|
|||
$labels['birthdayeventtitle'] = 'Narozeniny $name';
|
||||
$labels['birthdayage'] = 'Věk $age';
|
||||
$labels['objectchangelog'] = 'Historie změn';
|
||||
$labels['objectdiff'] = 'Změny od $rev1 do $rev2';
|
||||
$labels['objectnotfound'] = 'Nepodařilo se nahrát data události';
|
||||
$labels['objectchangelognotavailable'] = 'Historie změn není pro tuto událost dostupná';
|
||||
$labels['objectdiffnotavailable'] = 'Pro vybrané verze není žádné srovnání možné';
|
||||
$labels['revisionrestoreconfirm'] = 'Opravdu chcete obnovit změnu $rev této události? Tímto dojde k nahrazení nynější události starou verzí.';
|
||||
$labels['objectrestoresuccess'] = 'Pozměnění $rev úspěšně obnoveno';
|
||||
$labels['objectrestoreerror'] = 'Nepodařilo se obnovit staré pozměnění';
|
||||
$labels['arialabelminical'] = 'Výběr data v kalendáři';
|
||||
$labels['arialabelcalendarview'] = 'Pohled na kalendář';
|
||||
$labels['arialabelsearchform'] = 'Hledání události';
|
||||
|
|
|
@ -169,7 +169,6 @@ $labels['invitationattendlinks'] = "Hvis dit e-postprogram ikke understøtter iT
|
|||
$labels['eventupdatesubject'] = '"$title" er blevet opdateret';
|
||||
$labels['eventupdatesubjectempty'] = 'Et arrangement der vedrører dig er blevet opdateret';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nTidspunkt: \$date\n\nInviterede: \$attendees\n\nBemærk venligst vedhæftede iCalendar-fil med alle detaljer om arrangementet, som du kan importere til dit kalenderprogram.";
|
||||
$labels['eventcancelsubject'] = '"$title" er blevet aflyst';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nTidspunkt: \$date\n\nInviterede: \$attendees\n\nDette arrangement er blevet aflyst af \$organizer.\n\nBemærk venligst vedhæftede iCalendard-fil med de opdaterede detaljer om arrangementet.";
|
||||
$labels['itipobjectnotfound'] = 'Begivenheden som denne besked henviser til, blev ikke fundet i din kalender.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender har accepteret invitationen til det følgende arrangement:\n\n*\$title*\n\nTidspunkt: \$date\n\nInviterede: \$attendees";
|
||||
|
|
|
@ -176,10 +176,9 @@ $labels['itipmailbodyaccepted'] = "\$sender hat die Einladung zum folgenden Term
|
|||
$labels['itipmailbodytentative'] = "\$sender hat die Einladung mit Vorbehalt zum folgenden Termin angenommen:\n\n*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees";
|
||||
$labels['itipmailbodydeclined'] = "\$sender hat die Einladung zum folgenden Termin abgelehnt:\n\n*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees";
|
||||
$labels['itipmailbodycancel'] = "\$sender hat ihre Teilnahme bei der folgenden Veranstaltung zurückgewiesen:\n\n*\$title*\n\nam: \$date";
|
||||
$labels['itipmailbodydelegated'] = "\$sender hat die Teilnahme an folgendem Event delegiert:\n\n*\$title*\n\nWhen: \$date";
|
||||
$labels['itipmailbodydelegatedto'] = "\$sender hat die Teilnahme an folgendem Event an Sie delegiert:\n\n*\$title*\n\nWhen: \$date";
|
||||
$labels['itipmailbodydelegated'] = "\$sender hat die Teilnahme an folgendem Event delegiert:\n\n*\$title*\n\nWann: \$date";
|
||||
$labels['itipmailbodydelegatedto'] = "\$sender hat die Teilnahme an folgendem Event an Sie delegiert:\n\n*\$title*\n\nWann: \$date";
|
||||
$labels['itipdeclineevent'] = 'Möchten Sie die Einladung zu diesem Termin ablehnen?';
|
||||
$labels['declinedeleteconfirm'] = 'Do you also want to delete this declined event from your calendar?';
|
||||
$labels['itipcomment'] = 'Kommentar zur Einladungs/Benachrichtigung';
|
||||
$labels['itipcommenttitle'] = 'Dieser Kommentar wird an die Einladungs/Benachrichtigung angehängt, die an die Teilnehmer verschickt wird';
|
||||
$labels['notanattendee'] = 'Sie sind nicht in der Liste der Teilnehmer aufgeführt';
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
$labels['default_view'] = 'Standardansicht';
|
||||
$labels['time_format'] = 'Zeitformatierung';
|
||||
$labels['timeslots'] = 'Zeitfenster pro Stunde';
|
||||
$labels['first_day'] = 'Erster Wochentag';
|
||||
$labels['first_hour'] = 'Erste angezeigte Stunde';
|
||||
$labels['workinghours'] = 'Arbeitszeiten';
|
||||
|
@ -174,9 +175,9 @@ $labels['itipobjectnotfound'] = 'Der Termin auf den sich diese Nachricht bezieht
|
|||
$labels['itipmailbodyaccepted'] = "\$sender hat die Einladung zum folgenden Termin angenommen:\n\n*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees";
|
||||
$labels['itipmailbodytentative'] = "\$sender hat die Einladung mit Vorbehalt zum folgenden Termin angenommen:\n\n*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees";
|
||||
$labels['itipmailbodydeclined'] = "\$sender hat die Einladung zum folgenden Termin abgelehnt:\n\n*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees";
|
||||
$labels['itipmailbodycancel'] = "\$sender hat Ihre Teilnahme bei der folgenden Veranstaltung zurückgewiesen:\n\n*\$title*\n\nam: \$date";
|
||||
$labels['itipmailbodycancel'] = "\$sender hat Ihre Teilnahme bei der folgenden Veranstaltung zurückgewiesen:\n\n*\$title*\n\nWann: \$date";
|
||||
$labels['itipmailbodydelegated'] = "\$sender hat die Teilnahme an folgendem Event delegiert:\n\n*\$title*\n\nWhen: \$date";
|
||||
$labels['itipmailbodydelegatedto'] = "\$sender hat die Teilnahme an folgendem Event an Sie delegiert:\n\n*\$title*\n\nWhen: \$date";
|
||||
$labels['itipmailbodydelegatedto'] = "\$sender hat die Teilnahme an folgendem Event an Sie delegiert:\n\n*\$title*\n\nWann: \$date";
|
||||
$labels['itipdeclineevent'] = 'Möchten Sie die Einladung zu diesem Termin ablehnen?';
|
||||
$labels['declinedeleteconfirm'] = 'Soll der abgelehnte Termin zusätzlich aus dem Kalender gelöscht werden?';
|
||||
$labels['itipcomment'] = 'Kommentar zur Einladungs-/Benachrichtigungsnachricht';
|
||||
|
|
|
@ -182,7 +182,7 @@ $labels['invitationattendlinks'] = "In case your email client doesn't support iT
|
|||
$labels['eventupdatesubject'] = '"$title" has been updated';
|
||||
$labels['eventupdatesubjectempty'] = 'An event that concerns you has been updated';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nPlease find attached an iCalendar file with the updated event details which you can import to your calendar application.";
|
||||
$labels['eventcancelsubject'] = '"$title" has been canceled';
|
||||
$labels['eventcancelsubject'] = '"$title" has been cancelled';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nThe event has been cancelled by \$organizer.\n\nPlease find attached an iCalendar file with the updated event details.";
|
||||
|
||||
// invitation handling (overrides labels from libcalendaring)
|
||||
|
|
|
@ -80,6 +80,7 @@ $labels['sensitivity'] = 'Privacidad';
|
|||
$labels['public'] = 'público';
|
||||
$labels['private'] = 'privado';
|
||||
$labels['confidential'] = 'confidencial';
|
||||
$labels['links'] = 'Referencia';
|
||||
$labels['alarms'] = 'Recordatorio';
|
||||
$labels['comment'] = 'Comentario';
|
||||
$labels['created'] = 'Creado';
|
||||
|
@ -88,6 +89,7 @@ $labels['unknown'] = 'Desconocido';
|
|||
$labels['eventoptions'] = 'Opciones';
|
||||
$labels['generated'] = 'generado en';
|
||||
$labels['eventhistory'] = 'Historial';
|
||||
$labels['removelink'] = 'Eliminar referencia de correo';
|
||||
$labels['printdescriptions'] = 'Imprimir descripciones';
|
||||
$labels['parentcalendar'] = 'Insertar dentro';
|
||||
$labels['searchearlierdates'] = '« Buscar eventos anteriores';
|
||||
|
@ -167,13 +169,15 @@ $labels['invitationattendlinks'] = "En caso que su cliente de correo electrónic
|
|||
$labels['eventupdatesubject'] = '"$title" ha sido actualizado';
|
||||
$labels['eventupdatesubjectempty'] = 'Un evento que le interesa ha sido actualizado';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nCuándo: \$date\n\nInvitados: \$attendees\n\nEncontrará adjunto un archivo iCalendar con todos los detalles del evento, el cual puede importar a su aplicación de calendario.";
|
||||
$labels['eventcancelsubject'] = '"$title" has been canceled';
|
||||
$labels['eventcancelsubject'] = '"$title" ha sido cancelado';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nCuándo: \$date\n\nInvitados: \$attendees\n\nEl evento ha sido cancelado por \$organizer.\n\nEncontrará adjunto un archivo iCalendar con todos los detalles actualizados del evento.";
|
||||
$labels['itipobjectnotfound'] = 'El evento referido por este mensaje no fue encontrado en su calendario.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender ha aceptado la invitación al siguiente evento:\n\n*\$title*\n\nCuándo: \$date\n\nInvitados: \$attendees";
|
||||
$labels['itipmailbodytentative'] = "\$sender ha tentativamente aceptado la invitación al siguiente evento:\n\n*\$title*\n\nCuándo: \$date\n\nInvitados: \$attendees";
|
||||
$labels['itipmailbodydeclined'] = "\$sender ha rechazado la invitación al siguiente evento:\n\n*\$title*\n\nCuándo: \$date\n\nInvitados: \$attendees";
|
||||
$labels['itipmailbodycancel'] = "\$sender ha rechazado tu participación en el siguiente evento:\n\n*\$title*\n\nCuándo:\$date";
|
||||
$labels['itipmailbodydelegated'] = "\$sender ha delegado la invitación en el siguiente evento:\n\n*\$title*\n\nCuándo: \$date";
|
||||
$labels['itipmailbodydelegatedto'] = "\$sender ha delegado la participación en el siguiente evento a usted:\n\n*\$title*\n\nCuándo: \$date";
|
||||
$labels['itipdeclineevent'] = '¿Quiere rechazar la invitación a este evento?';
|
||||
$labels['declinedeleteconfirm'] = '¿Quiere también eliminar este evento rechazado de su calendario?';
|
||||
$labels['itipcomment'] = 'Comentario de la invitación/notificación';
|
||||
|
@ -232,6 +236,7 @@ $labels['changeeventconfirm'] = 'Cambiar evento';
|
|||
$labels['removeeventconfirm'] = 'Eliminar evento';
|
||||
$labels['changerecurringeventwarning'] = 'Este es un evento recurrente. ¿Desea editar solo el evento actual, este y las ocurrencias futuras, todas las ocurrencias o guardarlo como un evento nuevo?';
|
||||
$labels['removerecurringeventwarning'] = 'Este es un evento recurrente. ¿Desea eliminar solo el evento actual, este y las ocurrencias futuras o todas las ocurrencias del evento?';
|
||||
$labels['removerecurringallonly'] = 'Este es un evento recurrente. Como participante, usted solamente puede eliminar el evento completo con todas las ocurrencias.';
|
||||
$labels['currentevent'] = 'Actual';
|
||||
$labels['futurevents'] = 'Futuro';
|
||||
$labels['allevents'] = 'Todos';
|
||||
|
@ -243,10 +248,13 @@ $labels['birthdayscalendarsources'] = 'De estas libretas de direcciones';
|
|||
$labels['birthdayeventtitle'] = 'Cumpleaños de $name';
|
||||
$labels['birthdayage'] = 'Edad $age';
|
||||
$labels['objectchangelog'] = 'Cambiar Historial';
|
||||
$labels['objectdiff'] = 'Cambios de $rev1 a $rev2';
|
||||
$labels['objectnotfound'] = 'Fallo al cargar datos del evento';
|
||||
$labels['objectchangelognotavailable'] = 'Cambiar historial no esta disponible para este evento';
|
||||
$labels['objectdiffnotavailable'] = 'No es posible comparar las revisiones seleccionadas';
|
||||
$labels['revisionrestoreconfirm'] = 'Confirme que quiere recuperar la revisión $rev de este evento. Esta acción reemplazará el evento actual con la versión anterior.';
|
||||
$labels['objectrestoresuccess'] = 'Revisión $rev recuperada exitosamente';
|
||||
$labels['objectrestoreerror'] = 'Fallo al restaurar el evento anterior';
|
||||
$labels['arialabelminical'] = 'Selección de fecha del calendario';
|
||||
$labels['arialabelcalendarview'] = 'Vista del calendario';
|
||||
$labels['arialabelsearchform'] = 'Formulario de búsqueda de evento';
|
||||
|
|
|
@ -6,19 +6,198 @@
|
|||
*
|
||||
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
|
||||
*/
|
||||
$labels['default_view'] = 'Vista predeterminada';
|
||||
$labels['time_format'] = 'Formato de tiempo';
|
||||
$labels['timeslots'] = 'Los intervalos de tiempo por hora';
|
||||
$labels['first_day'] = 'Primer día de la semana';
|
||||
$labels['first_hour'] = 'Primera hora para mostrar';
|
||||
$labels['workinghours'] = 'Horas laborales';
|
||||
$labels['add_category'] = 'Añadir categoría';
|
||||
$labels['remove_category'] = 'Borrar la categoría';
|
||||
$labels['defaultcalendar'] = 'Crear nuevos eventos en';
|
||||
$labels['eventcoloring'] = 'Evento para colorear';
|
||||
$labels['coloringmode0'] = 'De acuerdo con el calendario';
|
||||
$labels['coloringmode1'] = 'De acuerdo con la categoría';
|
||||
$labels['coloringmode2'] = 'Calendario para el esquema, la categoría de contenido';
|
||||
$labels['coloringmode3'] = 'Calendario para el esquema, la categoría de contenido';
|
||||
$labels['afternothing'] = 'No hacer nada';
|
||||
$labels['aftertrash'] = 'Mover a la papelera';
|
||||
$labels['afterdelete'] = 'Eliminar el mensaje';
|
||||
$labels['afterflagdeleted'] = 'Marcar como eliminado';
|
||||
$labels['aftermoveto'] = 'Mover a...';
|
||||
$labels['itipoptions'] = 'Invitaciones para el evento';
|
||||
$labels['afteraction'] = 'Se procesa después de un mensaje de invitación o actualización';
|
||||
$labels['calendar'] = 'Calendario';
|
||||
$labels['calendars'] = 'Calendarios';
|
||||
$labels['category'] = 'Categoría';
|
||||
$labels['categories'] = 'Categorías';
|
||||
$labels['createcalendar'] = 'Crear nuevo calendario';
|
||||
$labels['editcalendar'] = 'Editar propiedades del calendario';
|
||||
$labels['name'] = 'Nombre';
|
||||
$labels['color'] = 'Color';
|
||||
$labels['day'] = 'Día';
|
||||
$labels['week'] = 'Semana';
|
||||
$labels['month'] = 'Mes';
|
||||
$labels['agenda'] = 'Agenda';
|
||||
$labels['new'] = 'Nuevo';
|
||||
$labels['new_event'] = 'Nuevo evento';
|
||||
$labels['edit_event'] = 'Editar evento';
|
||||
$labels['edit'] = 'Editar';
|
||||
$labels['save'] = 'Guardar';
|
||||
$labels['removelist'] = 'Borrar de la lista';
|
||||
$labels['cancel'] = 'Cancelar';
|
||||
$labels['select'] = 'Seleccionar';
|
||||
$labels['print'] = 'Imprimir';
|
||||
$labels['printtitle'] = 'Imprimir calendarios';
|
||||
$labels['title'] = 'Resumen';
|
||||
$labels['description'] = 'Descripción';
|
||||
$labels['all-day'] = 'Todo el día';
|
||||
$labels['export'] = 'Exportar';
|
||||
$labels['exporttitle'] = 'Exportar a iCalendar';
|
||||
$labels['exportrange'] = 'Eventos de';
|
||||
$labels['exportattachments'] = 'con los adjuntos';
|
||||
$labels['customdate'] = 'Fecha personalizada';
|
||||
$labels['location'] = 'Ubicación';
|
||||
$labels['url'] = 'URL';
|
||||
$labels['date'] = 'Fecha';
|
||||
$labels['start'] = 'Inicio';
|
||||
$labels['starttime'] = 'Tiempo de inicio';
|
||||
$labels['end'] = 'Fin';
|
||||
$labels['endtime'] = 'Hora de finalización';
|
||||
$labels['repeat'] = 'Repetir';
|
||||
$labels['selectdate'] = 'Seleccione la fecha';
|
||||
$labels['freebusy'] = 'Mostrarme como';
|
||||
$labels['free'] = 'Disponible';
|
||||
$labels['busy'] = 'Ocupado';
|
||||
$labels['outofoffice'] = 'Fuera de la oficina';
|
||||
$labels['tentative'] = 'Provisional';
|
||||
$labels['mystatus'] = 'Mi estado';
|
||||
$labels['status'] = 'Estado';
|
||||
$labels['status-confirmed'] = 'Confirmado';
|
||||
$labels['status-cancelled'] = 'Cancelado';
|
||||
$labels['priority'] = 'Prioridad';
|
||||
$labels['sensitivity'] = 'Privacidad';
|
||||
$labels['public'] = 'Pública';
|
||||
$labels['private'] = 'Privada';
|
||||
$labels['confidential'] = 'Confidencial';
|
||||
$labels['links'] = 'Referencia';
|
||||
$labels['alarms'] = 'Recordatorio';
|
||||
$labels['comment'] = 'Comentario';
|
||||
$labels['created'] = 'Creado';
|
||||
$labels['changed'] = 'Última modificación';
|
||||
$labels['unknown'] = 'Desconocido';
|
||||
$labels['eventoptions'] = 'Opciones';
|
||||
$labels['generated'] = 'Creado a las';
|
||||
$labels['eventhistory'] = 'Historial';
|
||||
$labels['removelink'] = 'Eliminar la referencia de correo electrónico';
|
||||
$labels['printdescriptions'] = 'Imprimir descripción ';
|
||||
$labels['parentcalendar'] = 'Inserte en el interior';
|
||||
$labels['searchearlierdates'] = '« Búsqueda de eventos anteriores';
|
||||
$labels['searchlaterdates'] = 'Búsqueda de eventos posteriores »';
|
||||
$labels['andnmore'] = '$nr más...';
|
||||
$labels['togglerole'] = 'Haga clic para cambiar el rol';
|
||||
$labels['createfrommail'] = 'Guardar como evento';
|
||||
$labels['importevents'] = 'Importar eventos';
|
||||
$labels['importrange'] = 'Eventos de';
|
||||
$labels['onemonthback'] = '1 mes atrás';
|
||||
$labels['nmonthsback'] = '$nr meses atrás';
|
||||
$labels['showurl'] = 'Mostrar URL del calendario';
|
||||
$labels['showurldescription'] = 'Usar la siguiente dirección para acceder (sólo lectura) en su calendario desde otras aplicaciones. Puede copiar y pegar esto en cualquier software de calendario que admita el formato iCal.';
|
||||
$labels['caldavurldescription'] = 'Copie esta dirección en un <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> cliente (Evolution o Mozilla Thunderbird) para sincronizar esta tarea con su ordenador o celular.';
|
||||
$labels['findcalendars'] = 'Buscar calendarios ...';
|
||||
$labels['searchterms'] = 'Buscar términos';
|
||||
$labels['calsearchresults'] = 'Calendarios disponibles';
|
||||
$labels['calendarsubscribe'] = 'Lista Permanente';
|
||||
$labels['nocalendarsfound'] = 'No se han encontrado calendarios';
|
||||
$labels['nrcalendarsfound'] = '$nr calendarios encontrados';
|
||||
$labels['quickview'] = 'Ver solo este calendario';
|
||||
$labels['invitationspending'] = 'Invitaciones pendientes';
|
||||
$labels['invitationsdeclined'] = 'Invitaciones rechazada';
|
||||
$labels['changepartstat'] = 'Cambiar el estado del participante';
|
||||
$labels['rsvpcomment'] = 'Texto de la invitación';
|
||||
$labels['listrange'] = 'Rango de visualización:';
|
||||
$labels['listsections'] = 'Dividir en:';
|
||||
$labels['smartsections'] = 'Secciones inteligentes';
|
||||
$labels['until'] = 'hasta';
|
||||
$labels['today'] = 'Hoy';
|
||||
$labels['tomorrow'] = 'Mañana';
|
||||
$labels['thisweek'] = 'Esta semana';
|
||||
$labels['nextweek'] = 'Próxima semana';
|
||||
$labels['prevweek'] = 'Semana pasada';
|
||||
$labels['thismonth'] = 'Este mes';
|
||||
$labels['nextmonth'] = 'Próximo mes';
|
||||
$labels['weekofyear'] = 'Semana';
|
||||
$labels['pastevents'] = 'Pasado';
|
||||
$labels['futureevents'] = 'Futuro';
|
||||
$labels['showalarms'] = 'Mostrar recordatorios';
|
||||
$labels['defaultalarmtype'] = 'Configuración predeterminada del recordatorio';
|
||||
$labels['defaultalarmoffset'] = 'Tiempo de aviso predeterminado';
|
||||
$labels['attendee'] = 'Participante';
|
||||
$labels['role'] = 'Rol';
|
||||
$labels['availability'] = 'Disponible';
|
||||
$labels['confirmstate'] = 'Estado';
|
||||
$labels['addattendee'] = 'Añada participante';
|
||||
$labels['roleorganizer'] = 'Organizador';
|
||||
$labels['rolerequired'] = 'Requerido';
|
||||
$labels['roleoptional'] = 'Opcional';
|
||||
$labels['rolechair'] = 'Silla';
|
||||
$labels['rolenonparticipant'] = 'Ausente';
|
||||
$labels['cutypeindividual'] = 'Individual';
|
||||
$labels['cutypegroup'] = 'Grupo';
|
||||
$labels['cutyperesource'] = 'Recurso';
|
||||
$labels['cutyperoom'] = 'Habitación';
|
||||
$labels['availfree'] = 'Disponible';
|
||||
$labels['availbusy'] = 'Ocupado';
|
||||
$labels['availunknown'] = 'Desconocido';
|
||||
$labels['availtentative'] = 'Provisional';
|
||||
$labels['availoutofoffice'] = 'Fuera de la oficina';
|
||||
$labels['delegatedto'] = 'Delegar a: ';
|
||||
$labels['delegatedfrom'] = 'Delegado de:';
|
||||
$labels['scheduletime'] = 'Buscar disponibilidad';
|
||||
$labels['sendinvitations'] = 'Enviar invitaciones';
|
||||
$labels['sendnotifications'] = 'Notificar a los participantes acerca de las modificaciones';
|
||||
$labels['sendcancellation'] = 'Notificar a los participantes sobre la cancelación de eventos';
|
||||
$labels['onlyworkinghours'] = 'Encuentra disponibilidad dentro de mis horas de trabajo';
|
||||
$labels['reqallattendees'] = 'Requeridos/todos los participantes';
|
||||
$labels['prevslot'] = 'Ranura anterior';
|
||||
$labels['nextslot'] = 'Siguiente ranura';
|
||||
$labels['suggestedslot'] = 'Ranura sugerida';
|
||||
$labels['noslotfound'] = 'Incapaz de encontrar un intervalo de tiempo libre';
|
||||
$labels['invitationsubject'] = 'Usted sido invitado a "$title"';
|
||||
$labels['invitationmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nSe adjunta un archivo iCalendar con todos los detalles del evento que se puede importar a la aplicación de calendario.";
|
||||
$labels['invitationattendlinks'] = "En caso de que su cliente de correo electrónico no admite solicitudes iTIP que puede utilizar el siguiente enlace para aceptar o rechazar esta invitación:\n\$url";
|
||||
$labels['eventupdatesubject'] = '"$title" Ha sido actualizado';
|
||||
$labels['eventupdatesubjectempty'] = 'Un evento que le concierne ha sido actualizado';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nSe adjunta un archivo iCalendar con los detalles del evento actualizados que se puede importar a la aplicación de calendario.";
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nEl evento ha sido cancelado por\$organizer.\n\nSe adjunta un archivo iCalendar con los detalles del evento actualizados.";
|
||||
$labels['itipobjectnotfound'] = 'El evento referido por este mensaje no se encontró en su calendario.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender ha aceptado la invitación al evento siguiente:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
|
||||
$labels['itipmailbodytentative'] = "\$sender ha aceptado provisionalmente la invitación al evento siguiente:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
|
||||
$labels['itipmailbodydeclined'] = "\$sender ha declinado la invitación al evento siguiente:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
|
||||
$labels['itipmailbodycancel'] = "\$sender ha rechazado su participación en el evento siguiente:\n\n*\$title*\n\nWhen: \$date";
|
||||
$labels['itipmailbodydelegated'] = "\$sender ha delegado la participación en el evento siguiente:\n\n*\$title*\n\nWhen: \$date";
|
||||
$labels['itipmailbodydelegatedto'] = "\$sender ha delegado la participación en el siguiente evento a usted:\n\n*\$title*\n\nWhen: \$date";
|
||||
$labels['itipdeclineevent'] = '¿Quieres rechazar la invitación a este evento?';
|
||||
$labels['declinedeleteconfirm'] = '¿Usted también desea eliminar este declinado evento del calendario?';
|
||||
$labels['itipcomment'] = 'Añadir comentarios a la Invitación/notificación';
|
||||
$labels['itipcommenttitle'] = 'Este comentario se adjunta al mensaje de invitación/notificación enviada a los participantes';
|
||||
$labels['notanattendee'] = 'Usted no está en la lista como un asistente de este evento';
|
||||
$labels['eventcancelled'] = 'El evento ha sido cancelado';
|
||||
$labels['resource'] = 'Recurso';
|
||||
$labels['resourcedetails'] = 'Detalles';
|
||||
$labels['tabsummary'] = 'Sumario';
|
||||
$labels['tabrecurrence'] = 'Recurrencia ';
|
||||
$labels['tabresources'] = 'Recursos';
|
||||
$labels['tabattachments'] = 'Adjuntos';
|
||||
$labels['tabsharing'] = 'Compartir';
|
||||
$labels['savingdata'] = 'Guardando datos...';
|
||||
$labels['attendeupdateesuccess'] = 'Se ha actualizado correctamente el estado del participante';
|
||||
$labels['itipinvalidrequest'] = 'Esta invitación ya no es válida';
|
||||
$labels['futurevents'] = 'Futuro';
|
||||
$labels['allevents'] = 'Todo';
|
||||
$labels['objectchangelog'] = 'Cambiar historial';
|
||||
$labels['objectdiff'] = 'Cambiar de $rev1 a $rev2';
|
||||
$labels['objectdiffnotavailable'] = 'No hay comparación posible que las revisiones seleccionadas';
|
||||
$labels['objectrestoresuccess'] = 'Revisión $rev restaurado correctamente';
|
||||
$labels['objectrestoreerror'] = 'No se pudo restaurar la revisión antigua';
|
||||
?>
|
||||
|
|
|
@ -169,13 +169,14 @@ $labels['invitationattendlinks'] = "Dans le cas où votre application de message
|
|||
$labels['eventupdatesubject'] = '"$title" a été modifié';
|
||||
$labels['eventupdatesubjectempty'] = 'Un évènement vous concernant a été modifié';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nQuand: \$date\n\nParticipants: \$attendees\n\nVous trouverez ci-joint un fichier iCalendar avec tous les modifications de l'évènement que vous pourrez importer dans votre agenda électronique.";
|
||||
$labels['eventcancelsubject'] = '"$title" a été annulé';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nQuand: \$date\n\nParticipants: \$attendees\n\nL'évènement a été annulé par \$organizer.\n\nVous trouverez en pièce jointe un fichier iCalendar avec les modifications de l'évènement que vous pourrez importer dans votre agenda électronique.";
|
||||
$labels['itipobjectnotfound'] = 'L\'évènement lié à ce message n\'a pas été trouvé dans votre calendrier.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender a accepté l'invitation à l'évènement suivant :\n\n*\$title*\n\nQuand: \$date\n\nParticipants: \$attendees";
|
||||
$labels['itipmailbodytentative'] = "\$sender a accepté provisoirement l'invitation à l'évènement suivant :\n\n*\$title*\n\nQuand: \$date\n\nParticipants: \$attendees";
|
||||
$labels['itipmailbodydeclined'] = "\$sender a refusé l'invitation à l'évènement suivant :\n\n*\$title*\n\nQuand: \$date\n\nParticipants: \$attendees";
|
||||
$labels['itipmailbodycancel'] = "\$sender a rejeté votre participation à l’évènement suivant :\n\n*\$title*\n\nLe: \$date";
|
||||
$labels['itipmailbodydelegated'] = "\$sender a délégué la participation à l'événement suivant : \n\n*\$title*\n\nQuand: \$date";
|
||||
$labels['itipmailbodydelegatedto'] = "\$sender vous a délégué la participation à l'événement suivant : \n\n*\$title*\n\nQuand : \$date";
|
||||
$labels['itipdeclineevent'] = 'Voulez-vous refuser l\'invitation à cet évènement?';
|
||||
$labels['declinedeleteconfirm'] = 'Voulez-vous aussi supprimer cet évènement annulé, de votre calendrier ?';
|
||||
$labels['itipcomment'] = 'Commentaire d’invitation ou de notification';
|
||||
|
@ -233,7 +234,8 @@ $labels['aclnorights'] = 'Vous n\'avez pas les droits d\'administration sur cet
|
|||
$labels['changeeventconfirm'] = 'Modifier l\'évènement';
|
||||
$labels['removeeventconfirm'] = 'Supprimer l\'évènement';
|
||||
$labels['changerecurringeventwarning'] = 'Ceci est un évènement récurant. Voulez vous éditer seulement cette occurrence, celle-ci et toutes les suivantes, toutes les occurrences ou l\'enregistrer comme un nouvel évènement? ';
|
||||
$labels['removerecurringeventwarning'] = 'Ceci est un évènement recrurent. Voulez-vous supprimer uniquement l\'évènement courent, l’évènement courent et toutes ces occurrences futures ou toutes les occurrences ?';
|
||||
$labels['removerecurringeventwarning'] = 'Ceci est un évènement récurent. Voulez-vous supprimer l\'évènement courant uniquement, l’évènement courant et toutes les occurrences futures, ou toutes les occurrences ?';
|
||||
$labels['removerecurringallonly'] = 'Ceci est un évènement récurent. En tant que participant vous pouvez seulement supprimer l\'évènement entier avec toutes les occurrences.';
|
||||
$labels['currentevent'] = 'Cette occurrence';
|
||||
$labels['futurevents'] = 'Cette occurrence et toutes les suivantes';
|
||||
$labels['allevents'] = 'Toutes les occurrences';
|
||||
|
@ -245,10 +247,13 @@ $labels['birthdayscalendarsources'] = 'Depuis ces carnets d\'adresses';
|
|||
$labels['birthdayeventtitle'] = 'Anniversaire de $name';
|
||||
$labels['birthdayage'] = 'Age $age';
|
||||
$labels['objectchangelog'] = 'Historique des modifications';
|
||||
$labels['objectdiff'] = 'Modifications depuis $rev1 jusqu\'à $rev2';
|
||||
$labels['objectnotfound'] = 'Impossible de charger les données de l’évènement';
|
||||
$labels['objectchangelognotavailable'] = 'Il n\'y a pas d\'historique des modifications pour cet évènement';
|
||||
$labels['objectdiffnotavailable'] = 'La comparaison des versions sélectionnées est impossible';
|
||||
$labels['revisionrestoreconfirm'] = 'Voulez-vous vraiment restaurer le version $rev de cet évènement ? Cette action va remplacer l\'évènement courent par l\'ancienne version.';
|
||||
$labels['revisionrestoreconfirm'] = 'Voulez-vous vraiment restaurer le version $rev de cet évènement ? Cette action va remplacer l\'évènement courant par l\'ancienne version.';
|
||||
$labels['objectrestoresuccess'] = 'La révision $rev a été restaurée avec succès';
|
||||
$labels['objectrestoreerror'] = 'Échec lors de la restauration de la précédente révision';
|
||||
$labels['arialabelminical'] = 'Sélection de la date du calendrier';
|
||||
$labels['arialabelcalendarview'] = 'Vue du calendrier';
|
||||
$labels['arialabelsearchform'] = 'Recherche d\'évènements depuis';
|
||||
|
|
|
@ -147,7 +147,6 @@ $labels['invitationattendlinks'] = "Amennyiben a levelezőben nem lát elfogadó
|
|||
$labels['eventupdatesubject'] = '$title - módosítva';
|
||||
$labels['eventupdatesubjectempty'] = 'Egy Önt érintő esemény módosítva lett';
|
||||
$labels['eventupdatemailbody'] = "Módosítás érkezett '\$title' eseményre vonatkozóan.\n\nIdőpont: \$date\nSzervező: \$organizer\nRésztvevők: \$attendees\n\n\nMellékletben egy frissített iCalendar naptárbejegyzés, mely tetszőleges naptárprogramba importálható.";
|
||||
$labels['eventcancelsubject'] = '$title - lemondva';
|
||||
$labels['eventcancelmailbody'] = "'\$title' eseményre \$organizer szervező visszavonta a meghívást.\n\nIdőpont: \$date\nRésztvevők: \$attendees\n\n\nMellékletben egy frissített iCalendar naptárbejegyzés, mely tetszőleges naptárprogramba importálható.";
|
||||
$labels['itipobjectnotfound'] = 'Az üzenetben hivatkozott esemény nem található a naptárban.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender elfogadta a meghívást '\$title' eseményre.\n\nIdőpont: \$date\nRésztvevők: \$attendees";
|
||||
|
|
|
@ -169,7 +169,6 @@ $labels['invitationattendlinks'] = "Se il tuo client di posta elettronica non su
|
|||
$labels['eventupdatesubject'] = '"$title" è stato aggiornato';
|
||||
$labels['eventupdatesubjectempty'] = 'Un evento che ti riguarda è stato aggiornato';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nQuando: \$date\n\nInvitati: \$attendees\n\nIn allegato un file iCalendar con i dettagli aggiornati dell'evento che puoi importare nella tua applicazione calendario.";
|
||||
$labels['eventcancelsubject'] = '"$title" è stato annullato';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nQuando: \$date\n\nInvitati: \$attendees\n\nL'evento è stato cancellato da \$organizer.\n\nIn allegato un file iCalendar con i dettagli aggiornati dell'evento .";
|
||||
$labels['itipobjectnotfound'] = 'L\'evento al quale questo messaggio fa riferimento non è stato trovato nel tuo calendario.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender ha accettato l'invito al seguente evento:\n\n*\$title*\n\nQuando: \$date\n\nInvitati: \$attendees";
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
$labels['default_view'] = 'デフォルトビュー';
|
||||
$labels['time_format'] = '時刻表示形式';
|
||||
$labels['timeslots'] = '一時間毎のタイムスロット';
|
||||
$labels['first_day'] = '最初の平日';
|
||||
$labels['first_hour'] = '最初の時間を表示';
|
||||
$labels['workinghours'] = '労働時間';
|
||||
|
@ -19,6 +20,13 @@ $labels['coloringmode0'] = 'カレンダーの説明';
|
|||
$labels['coloringmode1'] = 'カテゴリの説明';
|
||||
$labels['coloringmode2'] = 'アウトライン用カレンダー、コンテンツ用カテゴリ';
|
||||
$labels['coloringmode3'] = 'アウトライン用カレンダー、コンテンツ用カテゴリ';
|
||||
$labels['afternothing'] = '何もしない';
|
||||
$labels['aftertrash'] = 'ゴミ箱へ移動';
|
||||
$labels['afterdelete'] = 'メッセージを削除';
|
||||
$labels['afterflagdeleted'] = '削除フラグ';
|
||||
$labels['aftermoveto'] = '移動...';
|
||||
$labels['itipoptions'] = 'イベント招待';
|
||||
$labels['afteraction'] = '招待もしくは更新の後にメッセージは送達されます';
|
||||
$labels['calendar'] = 'カレンダー';
|
||||
$labels['calendars'] = 'カレンダー';
|
||||
$labels['category'] = 'カテゴリ';
|
||||
|
@ -47,12 +55,15 @@ $labels['all-day'] = '全日';
|
|||
$labels['export'] = 'エクスポート';
|
||||
$labels['exporttitle'] = 'iカレンダーへエクスポート';
|
||||
$labels['exportrange'] = 'イベント元';
|
||||
$labels['exportattachments'] = '添付する';
|
||||
$labels['customdate'] = 'カスタム日時';
|
||||
$labels['location'] = '場所';
|
||||
$labels['url'] = 'URL';
|
||||
$labels['date'] = '期日';
|
||||
$labels['start'] = '開始';
|
||||
$labels['starttime'] = '開始時間';
|
||||
$labels['end'] = '終了';
|
||||
$labels['endtime'] = '終了日';
|
||||
$labels['repeat'] = '繰返し';
|
||||
$labels['selectdate'] = '日付選択';
|
||||
$labels['freebusy'] = '表示する';
|
||||
|
@ -60,7 +71,9 @@ $labels['free'] = '空';
|
|||
$labels['busy'] = 'ビジー';
|
||||
$labels['outofoffice'] = '外出';
|
||||
$labels['tentative'] = '仮';
|
||||
$labels['mystatus'] = 'マイ ステータス';
|
||||
$labels['status'] = '状態';
|
||||
$labels['status-confirmed'] = '確認済';
|
||||
$labels['status-cancelled'] = 'キャンセル済';
|
||||
$labels['priority'] = '優先度';
|
||||
$labels['sensitivity'] = 'プライバシー';
|
||||
|
@ -69,6 +82,7 @@ $labels['private'] = 'プライベート';
|
|||
$labels['confidential'] = '親展';
|
||||
$labels['links'] = '参照';
|
||||
$labels['alarms'] = '通知';
|
||||
$labels['comment'] = 'コメント';
|
||||
$labels['created'] = '作成済';
|
||||
$labels['changed'] = '最終変更';
|
||||
$labels['unknown'] = '不明';
|
||||
|
@ -89,8 +103,18 @@ $labels['onemonthback'] = '1 ヶ月戻る';
|
|||
$labels['nmonthsback'] = '$nr ヶ月戻る';
|
||||
$labels['showurl'] = 'カレンダーURL表示';
|
||||
$labels['showurldescription'] = '以下のアドレスを使用して他のアプリケーションからカレンダーにアクセス(読込のみ)できます。iCal形式をサポートしたカレンダーソフトウェアへコピーアンドペーストができます。';
|
||||
$labels['caldavurldescription'] = 'この指定したカレンダーをコンピュータもしくはモバイルデバイスと全同期するためにはこのアドレスを <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> クライアントアプリケーション(たとえばエボリューションやMozilla サンダーバード)へコピーしてください。';
|
||||
$labels['findcalendars'] = 'カレンダーの検索';
|
||||
$labels['searchterms'] = '用語検索';
|
||||
$labels['calsearchresults'] = '有効なカレンダー';
|
||||
$labels['calendarsubscribe'] = '持続的なもののリスト';
|
||||
$labels['nocalendarsfound'] = 'カレンダーが見つかりませんでした';
|
||||
$labels['nrcalendarsfound'] = '$nr カレンダーが見つかりました';
|
||||
$labels['quickview'] = 'このカレンダーは閲覧のみ';
|
||||
$labels['invitationspending'] = '保留中の招待';
|
||||
$labels['invitationsdeclined'] = '断った招待';
|
||||
$labels['changepartstat'] = '参加者のステータス変更';
|
||||
$labels['rsvpcomment'] = '招待テキスト';
|
||||
$labels['listrange'] = '表示範囲:';
|
||||
$labels['listsections'] = '分割:';
|
||||
$labels['smartsections'] = 'スマートセクション';
|
||||
|
@ -99,6 +123,7 @@ $labels['today'] = '今日';
|
|||
$labels['tomorrow'] = '明日';
|
||||
$labels['thisweek'] = '今週';
|
||||
$labels['nextweek'] = '来週';
|
||||
$labels['prevweek'] = '前週';
|
||||
$labels['thismonth'] = '今月';
|
||||
$labels['nextmonth'] = '来月';
|
||||
$labels['weekofyear'] = '週';
|
||||
|
@ -116,13 +141,18 @@ $labels['roleorganizer'] = '編成者';
|
|||
$labels['rolerequired'] = '要件';
|
||||
$labels['roleoptional'] = 'オプション';
|
||||
$labels['rolechair'] = '議長';
|
||||
$labels['rolenonparticipant'] = '欠席';
|
||||
$labels['cutypeindividual'] = '個人';
|
||||
$labels['cutypegroup'] = 'グループ';
|
||||
$labels['cutyperesource'] = 'リソース';
|
||||
$labels['cutyperoom'] = 'ルーム';
|
||||
$labels['availfree'] = '空';
|
||||
$labels['availbusy'] = 'ビジー';
|
||||
$labels['availunknown'] = '不明';
|
||||
$labels['availtentative'] = '仮';
|
||||
$labels['availoutofoffice'] = '外出';
|
||||
$labels['delegatedto'] = '委任先:';
|
||||
$labels['delegatedfrom'] = '委任元:';
|
||||
$labels['scheduletime'] = '利用可検索';
|
||||
$labels['sendinvitations'] = '招待を送る';
|
||||
$labels['sendnotifications'] = '変更を参加者へ通知する';
|
||||
|
@ -131,6 +161,7 @@ $labels['onlyworkinghours'] = '労働時間内の利用可検索';
|
|||
$labels['reqallattendees'] = '要件/全参加者';
|
||||
$labels['prevslot'] = '前のスロット';
|
||||
$labels['nextslot'] = '次のスロット';
|
||||
$labels['suggestedslot'] = '指示されたスロット';
|
||||
$labels['noslotfound'] = '空スロットを見つけられません';
|
||||
$labels['invitationsubject'] = '"$title" に招待されました';
|
||||
$labels['invitationmailbody'] = "*\$title*\n\nいつ: \$date\n\n招待者: \$attendees\n\nあなたのカレンダーアプリケーションにインポートできる全イベントの詳細がインポートできる添付されたiカレンダーファイルを見つけてください。";
|
||||
|
@ -138,17 +169,33 @@ $labels['invitationattendlinks'] = "この場合あなたのメールクライ
|
|||
$labels['eventupdatesubject'] = '"$title" はアップデートされました';
|
||||
$labels['eventupdatesubjectempty'] = 'あなたに関連するイベントが更新されました';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nいつ: \$date\n\n招待者: \$attendees\n\nあなたのカレンダーアプリケーションにインポートできるアップデートされた全イベントの詳細が添付されたiカレンダーファイルを見つけてください。";
|
||||
$labels['eventcancelsubject'] = '"$title" は変更されました';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nいつ: \$date\n\n招待者: \$attendees\n\nイベントが \$organizer によってキャンセルされました。\n\n更新されたイベントの詳細とともに添付されたiカレンダーファイルを見つけてください。";
|
||||
$labels['itipobjectnotfound'] = 'このメッセージから参照されるイベントはカレンダーには見つかりません。';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender は以下のイベントへの招待を承諾しました:\n\n*\$title*\n\nいつ: \$date\n\n招待者: \$attendees";
|
||||
$labels['itipmailbodytentative'] = "\$sender は以下のイベントへの招待を仮承諾しました:\n\n*\$title*\n\nいつ: \$date\n\n招待者: \$attendees";
|
||||
$labels['itipmailbodydeclined'] = "\$sender は以下のイベントへの招待を辞退しました:\n\n*\$title*\n\nいつ: \$date\n\n招待者: \$attendees";
|
||||
$labels['itipmailbodycancel'] = "\$sender は以下のイベントへの参加を断りました:\n\n*\$title*\n\nいつ: \$date";
|
||||
$labels['itipmailbodydelegated'] = "\$sender は以下のイベントへの参加を委任しました:\n\n*\$title*\n\nいつ: \$date";
|
||||
$labels['itipmailbodydelegatedto'] = "\$sender は以下のイベントへの参加をあなたへ委任しました:\n\n*\$title*\n\nいつ: \$date";
|
||||
$labels['itipdeclineevent'] = 'このイベントへの招待を辞退しますか?';
|
||||
$labels['declinedeleteconfirm'] = 'この断ったイベントもカレンダーから削除しますか?';
|
||||
$labels['itipcomment'] = '招待/通知コメント';
|
||||
$labels['itipcommenttitle'] = 'このコメントは参加者へ送られた招待/通知メッセージへ添付されます';
|
||||
$labels['notanattendee'] = 'このイベントの出席者として一覧にありません';
|
||||
$labels['eventcancelled'] = 'このイベントはキャンセルされました';
|
||||
$labels['saveincalendar'] = '保存';
|
||||
$labels['updatemycopy'] = 'マイカレンダーの更新';
|
||||
$labels['savetocalendar'] = 'カレンダーへ保存';
|
||||
$labels['openpreview'] = 'カレンダーにチェック';
|
||||
$labels['noearlierevents'] = '以前のイベントはありません';
|
||||
$labels['nolaterevents'] = '以降のイベントはありません';
|
||||
$labels['resource'] = 'リソース';
|
||||
$labels['addresource'] = 'リソースの記帳';
|
||||
$labels['findresources'] = 'リソースの検索';
|
||||
$labels['resourcedetails'] = '詳細';
|
||||
$labels['resourceavailability'] = '利用可';
|
||||
$labels['resourceowner'] = '所有者';
|
||||
$labels['resourceadded'] = 'リソースはイベントへ追加されました';
|
||||
$labels['tabsummary'] = '要約';
|
||||
$labels['tabrecurrence'] = '繰返し';
|
||||
$labels['tabattendees'] = '参加者';
|
||||
|
@ -158,6 +205,7 @@ $labels['tabsharing'] = '共有';
|
|||
$labels['deleteobjectconfirm'] = '本当にこのイベントを削除しますか?';
|
||||
$labels['deleteventconfirm'] = '本当にこのイベントを削除しますか?';
|
||||
$labels['deletecalendarconfirm'] = '本当にこのカレンダーを全イベントとともに削除しますか?';
|
||||
$labels['deletecalendarconfirmrecursive'] = 'このカレンダーとカレンダー内のすべてのイベントやサブカレンダーを削除しますか?';
|
||||
$labels['savingdata'] = 'データを保存中…';
|
||||
$labels['errorsaving'] = '変更が保存できませんでした。';
|
||||
$labels['operationfailed'] = '要求された操作ができませんでした。';
|
||||
|
@ -168,27 +216,52 @@ $labels['successremoval'] = 'イベントを削除しました';
|
|||
$labels['successrestore'] = 'イベントを復旧しました';
|
||||
$labels['errornotifying'] = 'イベント参加者への通知が送信できませんでした';
|
||||
$labels['errorimportingevent'] = 'イベントのインポートができませんでした';
|
||||
$labels['importwarningexists'] = 'このイベントのコピーはすでにカレンダーにあります。';
|
||||
$labels['newerversionexists'] = 'このイベントのより新しいヴァージョンがすでにあります。中断されました。';
|
||||
$labels['nowritecalendarfound'] = 'イベントを保存するカレンダーが見つかりません';
|
||||
$labels['importedsuccessfully'] = '\'$calendar\' へイベントを追加しました';
|
||||
$labels['updatedsuccessfully'] = '\'$calendar\' 内のイベントの更新に成功しました';
|
||||
$labels['attendeupdateesuccess'] = '出席者状況を更新しました';
|
||||
$labels['itipsendsuccess'] = '出席者へ招待を送信しました。';
|
||||
$labels['itipresponseerror'] = 'この招待の返信できませんでした';
|
||||
$labels['itipinvalidrequest'] = 'この招待は間もなく無効になります';
|
||||
$labels['sentresponseto'] = '$mailto への招待の返信しました';
|
||||
$labels['localchangeswarning'] = 'あなたのカレンダーにのみ反映されイベントのまとめ役に通知されない変更を行おうとしています';
|
||||
$labels['importsuccess'] = '$nr イベントをインポートしました';
|
||||
$labels['importnone'] = 'インポートされたイベントはありません';
|
||||
$labels['importerror'] = 'インポート中にエラーが発生しました。';
|
||||
$labels['aclnorights'] = 'このカレンダーの管理権限がありません。';
|
||||
$labels['changeeventconfirm'] = 'イベント変更';
|
||||
$labels['removeeventconfirm'] = 'イベントを削除';
|
||||
$labels['changerecurringeventwarning'] = 'これは繰返しイベントです。現在のイベントのみ、このイベントと今後の全イベント、全イベント、編集したい、もしくは新しいイベントとして保存したい?';
|
||||
$labels['removerecurringeventwarning'] = 'これは繰返しのイベントです。現在のイベントのみ削除しますか? これと将来のすべてのイベントを削除しますか? または全てを削除しますか?';
|
||||
$labels['removerecurringallonly'] = 'これは繰返しイベントです。参加者は全ての出来事に対して参加のみを取り消せます。';
|
||||
$labels['currentevent'] = '現在';
|
||||
$labels['futurevents'] = '今後';
|
||||
$labels['allevents'] = '全て';
|
||||
$labels['saveasnew'] = '新規保存';
|
||||
$labels['birthdays'] = '誕生日';
|
||||
$labels['birthdayscalendar'] = '誕生日カレンダー';
|
||||
$labels['displaybirthdayscalendar'] = '誕生日をカレンダーに表示';
|
||||
$labels['birthdayscalendarsources'] = 'これらのアドレス帳から';
|
||||
$labels['birthdayeventtitle'] = '$name さんの誕生日';
|
||||
$labels['birthdayage'] = '年齢 $age';
|
||||
$labels['objectchangelog'] = '変更履歴';
|
||||
$labels['objectdiff'] = '$rev1 から $rev2 への変更';
|
||||
$labels['objectnotfound'] = 'イベントデータのロードに失敗しました';
|
||||
$labels['objectchangelognotavailable'] = 'このイベントの更新履歴は利用できません';
|
||||
$labels['objectdiffnotavailable'] = '選択されたリビジョンでは比較できません';
|
||||
$labels['revisionrestoreconfirm'] = '本当にリビジョン $rev のイベントを復旧しますか? 現在のイベントは古いバージョンのイベントに置換えられます。';
|
||||
$labels['objectrestoresuccess'] = 'リビジョン $rev は復旧されました';
|
||||
$labels['objectrestoreerror'] = '古いバージョンの復旧に失敗しました';
|
||||
$labels['arialabelminical'] = 'カレンダー日付選択';
|
||||
$labels['arialabelcalendarview'] = 'カレンダー表示';
|
||||
$labels['arialabelsearchform'] = 'イベント検索元';
|
||||
$labels['arialabelquicksearchbox'] = 'イベント検索入力';
|
||||
$labels['arialabelcalsearchform'] = 'カレンダー検索元';
|
||||
$labels['calendaractions'] = '行事カレンダー';
|
||||
$labels['arialabeleventattendees'] = 'イベント参加者リスト';
|
||||
$labels['arialabeleventresources'] = 'イベントリソースリスト';
|
||||
$labels['arialabelresourcesearchform'] = 'リソース検索元';
|
||||
$labels['arialabelresourceselection'] = '利用可能なリソース';
|
||||
?>
|
||||
|
|
|
@ -152,7 +152,6 @@ $labels['invitationattendlinks'] = "In het geval dat uw email programma geen iTi
|
|||
$labels['eventupdatesubject'] = '"$title" is gewijzigd';
|
||||
$labels['eventupdatesubjectempty'] = 'Een afspraak is gewijzigd';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nWanneer: \$date\n\nGenodigden: \$attendees\n\nBijgevoegd vindt u een iCalendar bestand met de gewijzigde details omtrent de afspraak die u kunt importeren in uw kalender programma.";
|
||||
$labels['eventcancelsubject'] = '"$title" is geannuleerd';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nWanneer: \$date\n\nGenodigden: \$attendees\n\nDeze afspraak is geannuleerd door \$organizer.\n\nBijgevoegd vindt u een iCalendar bestand met de gewijzigde details omtrent de afspraak";
|
||||
$labels['itipobjectnotfound'] = 'De afspraak waaraan door dit bericht wordt gereferreerd is niet gevonden in uw kalender.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender heeft de uitnodiging geaccepteerd voor de volgende afspraak:\n\n*\$title*\n\nWanneer: \$date\n\nGenodigden: \$attendees";
|
||||
|
|
|
@ -176,6 +176,8 @@ $labels['itipmailbodyaccepted'] = "\$sender zaakceptował zaproszenie do następ
|
|||
$labels['itipmailbodytentative'] = "\$sender warunkowo zaakceptował zaproszenie do następującego zdarzenia:\n\n*\$title*\n\nKiedy: \$date\n\nZaproszeni: \$attendees";
|
||||
$labels['itipmailbodydeclined'] = "\$sender odrzucił zaproszenie na następujące zdarzenie:\n\n*\$title*\n\nKiedy: \$date\n\nZaproszeni: \$attendees";
|
||||
$labels['itipmailbodycancel'] = "\$sender odrzucił twój udział w zastępującym zdarzeniu:\n\n*\$title*\n\nKiedy: \$date";
|
||||
$labels['itipmailbodydelegated'] = "\$sender oddelegował udział w następującym wydarzeniu:\n\n*\$title*\n\nKiedy: \$date";
|
||||
$labels['itipmailbodydelegatedto'] = "\$sender oddelegował do ciebie udział w następującym wydarzeniu:\n\n*\$title*\n\nKiedy: \$date";
|
||||
$labels['itipdeclineevent'] = 'Czy chcesz odrzucić zaproszenie na to zdarzenie?';
|
||||
$labels['declinedeleteconfirm'] = 'Czy chcesz także usunąć to odrzucone zdarzenie ze swojego kalendarza?';
|
||||
$labels['itipcomment'] = 'Komentarz zaproszenia/powiadomienia';
|
||||
|
@ -246,10 +248,13 @@ $labels['birthdayscalendarsources'] = 'Z tych książek adresowych';
|
|||
$labels['birthdayeventtitle'] = 'Urodziny $name\'s';
|
||||
$labels['birthdayage'] = 'Wiek $age';
|
||||
$labels['objectchangelog'] = 'Historia zmian';
|
||||
$labels['objectdiff'] = 'Zmiany od $rev1 do $rev2';
|
||||
$labels['objectnotfound'] = 'Nie udało się wczytać zdarzenia';
|
||||
$labels['objectchangelognotavailable'] = 'Historia zmian jest niedostępna dla tego zdarzenia';
|
||||
$labels['objectdiffnotavailable'] = 'Nie można porównać wybranych wersji';
|
||||
$labels['revisionrestoreconfirm'] = 'Czy na pewno chcesz przywrócić wersję $rev tego zdarzenia? Bierzące zdarzenie zostanie zastąpione starszą wersją.';
|
||||
$labels['objectrestoresuccess'] = 'Wersja $rev została pomyślnie przywrócona';
|
||||
$labels['objectrestoreerror'] = 'Nie udało się przywrócić starej wersji';
|
||||
$labels['arialabelminical'] = 'Wybór daty kalendarza';
|
||||
$labels['arialabelcalendarview'] = 'Podgląd kalendarza';
|
||||
$labels['arialabelsearchform'] = 'Formularz wyszukiwania zdarzeń';
|
||||
|
|
|
@ -141,7 +141,6 @@ $labels['invitationattendlinks'] = "No caso do seu cliente de e-mail não suport
|
|||
$labels['eventupdatesubject'] = '"$title" foi atualizado';
|
||||
$labels['eventupdatesubjectempty'] = 'Um evento do seu interesse foi atualizado';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nQuando: \$date\n\nConvidados: \$attendees\n\nSegue em anexo um arquivo iCalendar com os detalhes atualizados do evento na qual você pode importar para sua aplicação de calendário.";
|
||||
$labels['eventcancelsubject'] = '"$title" foi cancelado';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nQuando: \$date\n\nConvidados: \$attendees\n\nO evento foi cancelado por \$organizer.\n\nSegue em anexo um arquivo iCalendar com os detalhes atualizados do evento.";
|
||||
$labels['itipobjectnotfound'] = 'O evento referenciado por esta mensagem não foi encontrado em seu calendário.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender aceitou o convite para o seguinte evento:\n\n*\$title*\n\nQuando: \$date\n\nConvidados: \$attendees";
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
|
||||
*/
|
||||
$labels['default_view'] = 'Visualização padrão';
|
||||
$labels['default_view'] = 'Visualização predefinida';
|
||||
$labels['time_format'] = 'Formato da hora';
|
||||
$labels['timeslots'] = 'Entradas por hora';
|
||||
$labels['first_day'] = 'Primeiro dia da semana';
|
||||
|
@ -130,8 +130,8 @@ $labels['weekofyear'] = 'Semana';
|
|||
$labels['pastevents'] = 'Passado';
|
||||
$labels['futureevents'] = 'Futuro';
|
||||
$labels['showalarms'] = 'Mostrar lembretes';
|
||||
$labels['defaultalarmtype'] = 'Configuração padrão de lembrete';
|
||||
$labels['defaultalarmoffset'] = 'Horário padrão de lembrete';
|
||||
$labels['defaultalarmtype'] = 'Notificação predefinida dos lembretes';
|
||||
$labels['defaultalarmoffset'] = 'Agendamento predefinido das notificações';
|
||||
$labels['attendee'] = 'Participante';
|
||||
$labels['role'] = 'Papel';
|
||||
$labels['availability'] = 'Disp.';
|
||||
|
@ -169,7 +169,7 @@ $labels['invitationattendlinks'] = "No caso do seu cliente de e-mail não suport
|
|||
$labels['eventupdatesubject'] = '"$title" foi atualizado.';
|
||||
$labels['eventupdatesubjectempty'] = 'Um evento do seu interesse foi atualizado';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nQuando: \$date\n\nConvidados: \$attendees\n\nSegue em anexo um arquivo iCalendar atualizado com os detalhes de um evento, o qual pode importar para o seu calendário.";
|
||||
$labels['eventcancelsubject'] = '"$title" foi cancelado.';
|
||||
$labels['eventcancelsubject'] = '"$title" foi cancelado';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nQuando: \$date\n\nConvidados: \$attendees\n\nO evento foi cancelado por \$organizer.\n\nSegue em anexo um arquivo iCalendar com os detalhes atualizados do evento.";
|
||||
$labels['itipobjectnotfound'] = 'O evento citado nesta mensagem não foi encontrado no seu calendário.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender aceitou o convite para o seguinte evento:\n\n*\$title*\n\nQuando: \$date\n\nConvidados: \$attendees";
|
||||
|
@ -244,23 +244,17 @@ $labels['saveasnew'] = 'Guardar como';
|
|||
$labels['birthdays'] = 'Aniversários';
|
||||
$labels['birthdayscalendar'] = 'Calendário de aniversários';
|
||||
$labels['displaybirthdayscalendar'] = 'Mostrar calendário de aniversários';
|
||||
$labels['birthdayscalendarsources'] = 'From these address books';
|
||||
$labels['birthdayscalendarsources'] = 'Agendas a incluir:';
|
||||
$labels['birthdayeventtitle'] = 'Aniversário de $name';
|
||||
$labels['birthdayage'] = 'Idade $age';
|
||||
$labels['objectchangelog'] = 'Alterar histórico';
|
||||
$labels['revision'] = 'Revisão';
|
||||
$labels['user'] = 'Utilizador';
|
||||
$labels['operation'] = 'Ação';
|
||||
$labels['actionappend'] = 'Guardado';
|
||||
$labels['actionmove'] = 'Movido';
|
||||
$labels['actiondelete'] = 'Eliminado';
|
||||
$labels['compare'] = 'Comparar';
|
||||
$labels['showrevision'] = 'Mostrar esta versão';
|
||||
$labels['restore'] = 'Restaurar esta versão';
|
||||
$labels['objectdiff'] = 'Diferenças entre $rev1 e $rev2';
|
||||
$labels['objectnotfound'] = 'Falha ao ler os dados do evento';
|
||||
$labels['objectchangelognotavailable'] = 'Não é possível alterar o histórico deste evento';
|
||||
$labels['objectdiffnotavailable'] = 'Não é possível comparar as revisões selecionadas';
|
||||
$labels['revisionrestoreconfirm'] = 'Confirma o restauro da revisão $rev deste evento? Os dados atuais serão substituídos pelos da versão anterior.';
|
||||
$labels['objectdiffnotavailable'] = 'Não é possível comparar as versões selecionadas';
|
||||
$labels['revisionrestoreconfirm'] = 'Confirma a reposição das alterações $rev deste evento? Os dados atuais serão substituídos pela versão anterior.';
|
||||
$labels['objectrestoresuccess'] = 'A versão $rev foi reposta com sucesso.';
|
||||
$labels['objectrestoreerror'] = 'Não foi possível repor a versão anterior.';
|
||||
$labels['arialabelminical'] = 'Seleção da data do calendário';
|
||||
$labels['arialabelcalendarview'] = 'Vista do calendário';
|
||||
$labels['arialabelsearchform'] = 'Quadro de pesquisa de eventos';
|
||||
|
|
|
@ -169,7 +169,6 @@ $labels['invitationattendlinks'] = "V kolikor vaš email klient ne podpira iTip
|
|||
$labels['eventupdatesubject'] = '"$title" je bil posodobljen';
|
||||
$labels['eventupdatesubjectempty'] = 'Dogodek, ki vas zadeva je bil posodobljen';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nProsim preglejte pripeto iCalendar datoteko s posodobljenimi informacijami o dogodku. Datoteko lahko uvozite v vašo koledar aplikacijo.";
|
||||
$labels['eventcancelsubject'] = '"$title" je bil preklican';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nDogodek je bil preklican s strani \$organizer.\n\nProsim preglejte pripeto iCalendar datoteko s posodobljenimi informacijami o dogodku.";
|
||||
$labels['itipobjectnotfound'] = 'Dogodek, na katerega se nanaša to sporočilo, ni bil najden v vašem koledarju.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender je sprejel vabilo na dogodek:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
|
||||
|
|
|
@ -169,7 +169,6 @@ $labels['invitationattendlinks'] = "Om din e-postklient inte stöder iTip-förfr
|
|||
$labels['eventupdatesubject'] = '"$title" har uppdaterats';
|
||||
$labels['eventupdatesubjectempty'] = 'En händelse som berör dig har uppdaterats';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nNär: \$date\n\nInbjudna: \$attendees\n\nHärmed bifogas en iCalendar-fil med uppdaterad information som du kan importera till din kalenderapplikation.";
|
||||
$labels['eventcancelsubject'] = '"$title" har ställts in';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nNär: \$date\n\nInbjudna: \$attendees\n\nHändelsen har ställts in av \$organizer.\n\nHärmed bifogas en iCalendar-fil med uppdaterad information om händelsen.";
|
||||
$labels['itipobjectnotfound'] = 'Den händelse som avses i detta meddelande hittades inte i din kalender.';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender har accepterat inbjudan till följande händelse:\n\n*\$title*\n\nNär: \$date\n\nInbjudna: \$attendees";
|
||||
|
|
|
@ -155,7 +155,6 @@ $labels['invitationsubject'] = 'คุณได้รับเชิญไปย
|
|||
$labels['invitationattendlinks'] = "ในกรณีที่โปรแกรมอีเมล์ของคุณไม่รองรับ 'การร้องขอ iTip' คุณสามารถใช้ลิงค์ต่อไปนี้ในการตอบรับหรือปฎิเสธจดหมายเชิญฉบับนี้ :\n\$url";
|
||||
$labels['eventupdatesubject'] = '"$title" ได้รับการปรับปรุงสถานะ';
|
||||
$labels['eventupdatesubjectempty'] = 'เหตุการณ์ที่คุณเป็นห่วงได้ถูกปรับปรุงสถานะแล้ว';
|
||||
$labels['eventcancelsubject'] = '"$title" ถูกยกเลิก';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nเมื่อ: \$date\n\nInvitees: \$attendees\n\n เหตุการณ์ได้ถูกยกเลิกโดย \$organizer.\n\n ไฟล์ iCalendar ที่แนบมาด้วย ได้รับการปรับปรุงรายละเอียดเรียบร้อยแล้ว";
|
||||
$labels['itipobjectnotfound'] = 'เหตุการณ์ที่อ้างถึงโดยข้อความนี้ไม่ถูกตรวจพบในปฎิทินของคุณ';
|
||||
$labels['itipmailbodyaccepted'] = "\$sender ได้ตอบรับคำเชิญสำหรับเหตุการณ์ต่อไปนี้:\n\n*\$title*\n\nเมื่อ: \$date\n\nInvitees: \$attendees";
|
||||
|
|
|
@ -164,7 +164,6 @@ $labels['invitationattendlinks'] = "У разі, якщо Ваш поштови
|
|||
$labels['eventupdatesubject'] = '"$title" була оновлена';
|
||||
$labels['eventupdatesubjectempty'] = 'Подія, яка стосується Вас, була оновленна ';
|
||||
$labels['eventupdatemailbody'] = "*\$title*\n\nКоли: \$date\n\nЗапрошені: \$attendees\n\nУ вкладенні Ви знайдете файл iCalendar з усіма змінами у події, який Ви можете імпортувати у Вашу програму-щоденник.";
|
||||
$labels['eventcancelsubject'] = '"$title" була відмінена';
|
||||
$labels['eventcancelmailbody'] = "*\$title*\n\nКоли: \$date\n\nЗапрошені: \$attendees\n\nЦя подія скасована \$organizer.\n\nУ вкладенні Ви знайдете файл iCalendar з усіма змінами у події.";
|
||||
$labels['itipobjectnotfound'] = 'Згадану в даному повідомленні подію, не знайдено у Вашому календарі.';
|
||||
$labels['itipdeclineevent'] = 'Ви хочете відхилити запрошення на дану подію?';
|
||||
|
|
|
@ -8,9 +8,15 @@
|
|||
*/
|
||||
$labels['default_view'] = '默认视图';
|
||||
$labels['time_format'] = '时间格式';
|
||||
$labels['timeslots'] = '每小时分成几段';
|
||||
$labels['first_day'] = '周几排列在前';
|
||||
$labels['first_hour'] = '几点最前显示';
|
||||
$labels['workinghours'] = '工作时间';
|
||||
$labels['add_category'] = '增加分类';
|
||||
$labels['remove_category'] = '移除分类';
|
||||
$labels['defaultcalendar'] = '创建事件于';
|
||||
$labels['eventcoloring'] = '事件标色';
|
||||
$labels['coloringmode0'] = '根据日历';
|
||||
$labels['aftertrash'] = '移到回收站';
|
||||
$labels['afterdelete'] = '删除此信息';
|
||||
$labels['afterflagdeleted'] = '被删除标签';
|
||||
|
@ -36,6 +42,8 @@ $labels['title'] = '汇总';
|
|||
$labels['description'] = '描述';
|
||||
$labels['export'] = '导出';
|
||||
$labels['exporttitle'] = '导出到ICalendar';
|
||||
$labels['location'] = '地点';
|
||||
$labels['url'] = '网址';
|
||||
$labels['date'] = '日期';
|
||||
$labels['start'] = '开始';
|
||||
$labels['starttime'] = '开始时间';
|
||||
|
@ -63,14 +71,49 @@ $labels['created'] = '已创建';
|
|||
$labels['changed'] = '最后更改';
|
||||
$labels['unknown'] = '未知';
|
||||
$labels['eventoptions'] = '选项';
|
||||
$labels['eventhistory'] = '历史';
|
||||
$labels['searchearlierdates'] = '<< 查找以前的事件';
|
||||
$labels['searchlaterdates'] = '查找以后的时间 >>';
|
||||
$labels['invitationspending'] = '未决邀请';
|
||||
$labels['invitationsdeclined'] = '已拒绝邀请';
|
||||
$labels['rsvpcomment'] = '邀请文字';
|
||||
$labels['until'] = '直到';
|
||||
$labels['today'] = '今天';
|
||||
$labels['tomorrow'] = '明天';
|
||||
$labels['thisweek'] = '本周';
|
||||
$labels['nextweek'] = '下周';
|
||||
$labels['prevweek'] = '上周';
|
||||
$labels['thismonth'] = '本月';
|
||||
$labels['nextmonth'] = '下月';
|
||||
$labels['weekofyear'] = '周';
|
||||
$labels['pastevents'] = '过去';
|
||||
$labels['futureevents'] = '未来';
|
||||
$labels['showalarms'] = '显示提醒';
|
||||
$labels['defaultalarmtype'] = '默认提醒设置';
|
||||
$labels['defaultalarmoffset'] = '默认提醒时间';
|
||||
$labels['attendee'] = '参与者';
|
||||
$labels['role'] = '身份';
|
||||
$labels['availability'] = '有空';
|
||||
$labels['confirmstate'] = '状态';
|
||||
$labels['addattendee'] = '添加参与者';
|
||||
$labels['roleorganizer'] = '组织者';
|
||||
$labels['rolerequired'] = '必须';
|
||||
$labels['roleoptional'] = '可选';
|
||||
$labels['rolenonparticipant'] = '缺席';
|
||||
$labels['cutypeindividual'] = '个人';
|
||||
$labels['cutypegroup'] = '组织';
|
||||
$labels['cutyperesource'] = '资源';
|
||||
$labels['availfree'] = '空闲';
|
||||
$labels['availbusy'] = '忙碌';
|
||||
$labels['availunknown'] = '未知';
|
||||
$labels['availtentative'] = '临时';
|
||||
$labels['availoutofoffice'] = '外出';
|
||||
$labels['scheduletime'] = '查找是否有空';
|
||||
$labels['sendinvitations'] = '发送邀请';
|
||||
$labels['sendnotifications'] = '通知参加者修改事项';
|
||||
$labels['resource'] = '资源';
|
||||
$labels['tabsummary'] = '汇总';
|
||||
$labels['tabsharing'] = '分享';
|
||||
$labels['savingdata'] = '保存数据...';
|
||||
$labels['futurevents'] = '未来';
|
||||
?>
|
||||
|
|
|
@ -373,6 +373,7 @@ pre {
|
|||
right: 4px;
|
||||
}
|
||||
|
||||
#eventedit.uidialog,
|
||||
.calendarmain div.uidialog {
|
||||
display: none;
|
||||
}
|
||||
|
@ -547,24 +548,56 @@ a.miniColors-trigger {
|
|||
margin: 0 -0.2em;
|
||||
}
|
||||
|
||||
#eventshow.status-cancelled {
|
||||
background: url(images/badge_cancelled.png) top right no-repeat;
|
||||
#event-status-badge {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#eventshow.sensitivity-private {
|
||||
background: url(images/badge_private.png) top right no-repeat;
|
||||
#event-status-badge span {
|
||||
display: none;
|
||||
text-transform: uppercase;
|
||||
width: 150px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
position: absolute;
|
||||
left: -20px;
|
||||
top: 35px;
|
||||
padding-left: 10px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
box-shadow: 1px 1px 2px #ccc, -1px -1px 2px #ccc;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
-o-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
#eventshow.sensitivity-confidential {
|
||||
background: url(images/badge_confidential.png) top right no-repeat;
|
||||
#eventshow.status-cancelled #event-status-badge span {
|
||||
background: url(images/badge.png) 26px -24px no-repeat #cc0000;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sensitivity-private #event-title {
|
||||
margin-right: 50px;
|
||||
#eventshow.sensitivity-private #event-status-badge span {
|
||||
background: url(images/badge.png) 40px -52px no-repeat #0066ff;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sensitivity-confidential #event-title {
|
||||
margin-right: 60px;
|
||||
#eventshow.sensitivity-confidential #event-status-badge span {
|
||||
background: url(images/badge.png) 20px 2px no-repeat #cc0000;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#eventshow.status-cancelled #event-title,
|
||||
#eventshow.sensitivity-private #event-title,
|
||||
#eventshow.sensitivity-confidential #event-title {
|
||||
margin-right: 80px;
|
||||
}
|
||||
|
||||
#eventshow div.event-line {
|
||||
|
|
|
@ -44,14 +44,6 @@ html #calendartoolbar a.buttonPas {
|
|||
width: 102%;
|
||||
}
|
||||
|
||||
#eventshow.sensitivity-private {
|
||||
background-image: url(images/badge_private.gif);
|
||||
}
|
||||
|
||||
#eventshow.sensitivity-confidential {
|
||||
background-image: url(images/badge_confidential.gif);
|
||||
}
|
||||
|
||||
.fc-day-content {
|
||||
cursor: default;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
<li><roundcube:button command="calendar-edit" label="calendar.edit" classAct="active" /></li>
|
||||
<li><roundcube:button command="calendar-delete" label="delete" classAct="active" /></li>
|
||||
<roundcube:if condition="env:calendar_driver == 'kolab'" />
|
||||
<li><roundcube:button command="calendar-remove" label="calendar.remove" classAct="active" /></li>
|
||||
<li><roundcube:button command="calendar-remove" label="calendar.removelist" classAct="active" /></li>
|
||||
<roundcube:endif />
|
||||
<li><roundcube:button command="calendar-showurl" label="calendar.showurl" classAct="active" /></li>
|
||||
<roundcube:if condition="env:calendar_driver == 'kolab'" />
|
||||
|
@ -62,6 +62,7 @@
|
|||
|
||||
<div id="eventshow" class="uidialog">
|
||||
<h1 id="event-title">Event Title</h1>
|
||||
<div id="event-status-badge"><span></span></div>
|
||||
<div class="event-section" id="event-location">Location</div>
|
||||
<div class="event-section" id="event-date">From-To</div>
|
||||
<div class="event-section" id="event-description">
|
||||
|
@ -122,6 +123,7 @@
|
|||
<ul>
|
||||
<li><roundcube:button command="event-download" label="download" classAct="active" /></li>
|
||||
<li><roundcube:button command="event-sendbymail" label="send" classAct="active" /></li>
|
||||
<li><roundcube:button command="event-copy" label="copy" classAct="active" /></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ body.calendarmain #mainscreen {
|
|||
width: 6px;
|
||||
top: 40px !important;
|
||||
bottom: 0;
|
||||
height: auto;
|
||||
background: url(images/toggle.gif) -1px 48% no-repeat transparent;
|
||||
}
|
||||
|
||||
|
@ -453,7 +454,8 @@ pre {
|
|||
|
||||
#calendars .searchresults .boxtitle {
|
||||
background: none;
|
||||
padding: 2px 8px 2px 8px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#calendars .searchresults .listing li {
|
||||
|
@ -538,6 +540,7 @@ body.calendarmain #searchmenulink {
|
|||
width: 15px;
|
||||
}
|
||||
|
||||
#eventedit.uidialog,
|
||||
.calendarmain div.uidialog {
|
||||
display: none;
|
||||
}
|
||||
|
@ -640,7 +643,7 @@ a.miniColors-trigger {
|
|||
border-top: 2px solid #fafafa;
|
||||
}
|
||||
|
||||
#edit-attachments-form .formbuttons {
|
||||
#edit-attachments-form .buttons {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
|
@ -681,7 +684,7 @@ a.miniColors-trigger {
|
|||
}
|
||||
|
||||
.event-attendees span.attendee {
|
||||
padding-right: 18px;
|
||||
padding: 1px 18px 1px 0;
|
||||
margin-right: 0.5em;
|
||||
background: url(images/attendee-status.png) right 0 no-repeat;
|
||||
}
|
||||
|
@ -769,24 +772,56 @@ a.miniColors-trigger {
|
|||
margin: 0 -0.2em;
|
||||
}
|
||||
|
||||
.calendarmain .eventdialog.status-cancelled {
|
||||
background: url(images/badge_cancelled.png) top right no-repeat;
|
||||
#event-status-badge {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.calendarmain .eventdialog.sensitivity-private {
|
||||
background: url(images/badge_private.png) top right no-repeat;
|
||||
#event-status-badge span {
|
||||
display: none;
|
||||
text-transform: uppercase;
|
||||
width: 150px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
position: absolute;
|
||||
left: -20px;
|
||||
top: 35px;
|
||||
padding-left: 10px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
box-shadow: 1px 1px 2px #ccc, -1px -1px 2px #ccc;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
-o-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.calendarmain .eventdialog.sensitivity-confidential {
|
||||
background: url(images/badge_confidential.png) top right no-repeat;
|
||||
.eventdialog.status-cancelled #event-status-badge span {
|
||||
background: url(images/badge.png) 26px -24px no-repeat #cc0000;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.calendarmain .sensitivity-private #event-title {
|
||||
margin-right: 50px;
|
||||
.eventdialog.sensitivity-private #event-status-badge span {
|
||||
background: url(images/badge.png) 40px -52px no-repeat #0066ff;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.eventdialog.sensitivity-confidential #event-status-badge span {
|
||||
background: url(images/badge.png) 20px 2px no-repeat #cc0000;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.calendarmain .status-cancelled #event-title,
|
||||
.calendarmain .sensitivity-private #event-title,
|
||||
.calendarmain .sensitivity-confidential #event-title {
|
||||
margin-right: 60px;
|
||||
margin-right: 80px;
|
||||
}
|
||||
|
||||
.calendarmain .eventdialog div.event-line {
|
||||
|
@ -803,11 +838,6 @@ a.miniColors-trigger {
|
|||
margin-left: 2em;
|
||||
}
|
||||
|
||||
.calendarmain .eventdialog #event-rsvp-comment,
|
||||
.calendarmain .eventdialog #event-created-changed {
|
||||
margin-top: 0.6em;
|
||||
}
|
||||
|
||||
.eventdialog .event-text-old,
|
||||
.eventdialog .event-text-new,
|
||||
.eventdialog .event-text-diff {
|
||||
|
@ -1110,7 +1140,7 @@ td.topalign {
|
|||
|
||||
#eventedit .edit-attendees-table th.invite,
|
||||
#eventedit .edit-attendees-table td.invite {
|
||||
width: 44px;
|
||||
width: 50px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
|
@ -1210,50 +1240,51 @@ td.topalign {
|
|||
height: 14px;
|
||||
border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.availability img.availabilityicon.loading {
|
||||
background: url(images/loading_blue.gif) center no-repeat;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times td.unknown,
|
||||
#schedule-freebusy-times td div.unknown,
|
||||
.availability img.availabilityicon.unknown {
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times td.free,
|
||||
#schedule-freebusy-times td div.free,
|
||||
.availability img.availabilityicon.free {
|
||||
background: #abd640;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times td.busy,
|
||||
#schedule-freebusy-times td div.busy,
|
||||
.availability img.availabilityicon.busy {
|
||||
background: #e26569;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times td.tentative,
|
||||
#schedule-freebusy-times td div.tentative,
|
||||
.availability img.availabilityicon.tentative {
|
||||
background: #8383fc;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times td.out-of-office,
|
||||
#schedule-freebusy-times td div.out-of-office,
|
||||
.availability img.availabilityicon.out-of-office {
|
||||
background: #fbaa68;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times td.all-busy,
|
||||
#schedule-freebusy-times td.all-tentative,
|
||||
#schedule-freebusy-times td.all-out-of-office {
|
||||
#schedule-freebusy-times td div.all-busy,
|
||||
#schedule-freebusy-times td div.all-tentative,
|
||||
#schedule-freebusy-times td div.all-out-of-office {
|
||||
background-image: url(images/freebusy-colors.png);
|
||||
background-position: top right;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times td.all-tentative {
|
||||
#schedule-freebusy-times td div.all-tentative {
|
||||
background-position: right -40px;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times td.all-out-of-office {
|
||||
#schedule-freebusy-times td div.all-out-of-office {
|
||||
background-position: right -80px;
|
||||
}
|
||||
|
||||
|
@ -1267,10 +1298,6 @@ td.topalign {
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#edit-attendees-legend img.availabilityicon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.edit-attendees-table tbody td.confirmstate {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
@ -1284,22 +1311,27 @@ td.topalign {
|
|||
}
|
||||
|
||||
.edit-attendees-table td.confirmstate span.needs-action {
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.edit-attendees-table td.confirmstate span.accepted {
|
||||
background-position: 5px -20px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.edit-attendees-table td.confirmstate span.declined {
|
||||
background-position: 5px -40px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.edit-attendees-table td.confirmstate span.tentative {
|
||||
background-position: 5px -60px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.edit-attendees-table td.confirmstate span.delegated {
|
||||
background-position: 5px -180px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
#attendees-freebusy-table {
|
||||
|
@ -1380,7 +1412,8 @@ td.topalign {
|
|||
.attendees-list .spacer,
|
||||
#schedule-freebusy-times tr.spacer td {
|
||||
background: 0;
|
||||
font-size: 50%;
|
||||
padding: 0;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times {
|
||||
|
@ -1393,6 +1426,15 @@ td.topalign {
|
|||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times tbody td {
|
||||
padding: 0;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times tbody td div {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#attendees-freebusy-table div.timesheader,
|
||||
#schedule-freebusy-times tr.times td {
|
||||
min-width: 30px;
|
||||
|
@ -1410,6 +1452,10 @@ td.topalign {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
#schedule-freebusy-times #fbrowall td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#schedule-event-time {
|
||||
position: absolute;
|
||||
border: 2px solid #333;
|
||||
|
|
BIN
skins/larry/images/badge.png
Normal file
BIN
skins/larry/images/badge.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 746 B |
|
@ -82,6 +82,7 @@
|
|||
|
||||
<div id="eventshow" class="uidialog eventdialog" aria-hidden="true">
|
||||
<h1 id="event-title">Event Title</h1>
|
||||
<div id="event-status-badge"><span></span></div>
|
||||
<div class="event-section" id="event-location">Location</div>
|
||||
<div class="event-section" id="event-date">From-To</div>
|
||||
<div class="event-section" id="event-description">
|
||||
|
@ -163,6 +164,7 @@
|
|||
<ul id="eventoptionsmenu-menu" class="toolbarmenu" role="menu" aria-labelledby="aria-label-eventoptions">
|
||||
<li role="menuitem"><roundcube:button command="event-download" label="download" classAct="active" /></li>
|
||||
<li role="menuitem"><roundcube:button command="event-sendbymail" label="send" classAct="active" /></li>
|
||||
<li role="menuitem"><roundcube:button command="event-copy" label="copy" classAct="active" /></li>
|
||||
<roundcube:if condition="env:calendar_driver == 'kolab' && config:kolab_bonnie_api" />
|
||||
<li role="menuitem"><roundcube:button command="event-history" type="link" label="calendar.eventhistory" classAct="active" /></li>
|
||||
<roundcube:endif />
|
||||
|
|
87
skins/larry/templates/dialog.html
Normal file
87
skins/larry/templates/dialog.html
Normal file
|
@ -0,0 +1,87 @@
|
|||
<roundcube:object name="doctype" value="html5" />
|
||||
<html>
|
||||
<head>
|
||||
<title><roundcube:object name="pagetitle" /></title>
|
||||
<roundcube:include file="/includes/links.html" />
|
||||
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="/this/iehacks.css" /><![endif]-->
|
||||
</head>
|
||||
<body class="calendarmain dialog">
|
||||
|
||||
<div id="mainscreen">
|
||||
<div id="calendarsidebar">
|
||||
<h2 id="aria-label-minical" class="voice"><roundcube:label name="calendar.arialabelminical" /></h2>
|
||||
<div id="datepicker" class="uibox" role="presentation"></div>
|
||||
|
||||
<div id="calendars" class="uibox listbox" style="visibility:hidden" role="navigation" aria-labelledby="aria-label-calendarlist">
|
||||
<h2 class="boxtitle" id="aria-label-calendarlist"><roundcube:label name="calendar.calendars" />
|
||||
<a href="#calendars" class="iconbutton search" title="<roundcube:label name='calendar.findcalendars' />" tabindex="0"><roundcube:label name='calendar.findcalendars' /></a>
|
||||
</h2>
|
||||
<div class="listsearchbox">
|
||||
<div class="searchbox" role="search" aria-labelledby="aria-label-calsearchform" aria-controls="calendarslist">
|
||||
<h3 id="aria-label-calsearchform" class="voice"><roundcube:label name="calendar.arialabelcalsearchform" /></h3>
|
||||
<label for="calendarlistsearch" class="voice"><roundcube:label name="calendar.searchterms" /></label>
|
||||
<input type="text" name="q" id="calendarlistsearch" placeholder="<roundcube:label name='calendar.findcalendars' />" />
|
||||
<a class="iconbutton searchicon"></a>
|
||||
<roundcube:button command="reset-listsearch" id="calendarlistsearch-reset" class="iconbutton reset" title="resetsearch" label="resetsearch" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="scroller">
|
||||
<roundcube:object name="plugin.calendar_list" id="calendarslist" class="treelist listing" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="aria-label-calendarview" class="voice"><roundcube:label name="calendar.arialabelcalendarview" /></h2>
|
||||
<div id="calendar" role="main" aria-labelledby="aria-label-calendarview">
|
||||
<roundcube:object name="plugin.angenda_options" class="boxfooter" id="agendaoptions" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="timezonedisplay"><roundcube:var name="env:timezone" /></div>
|
||||
|
||||
<roundcube:include file="/templates/eventshow.html" />
|
||||
<roundcube:include file="/templates/eventedit.html" />
|
||||
|
||||
<roundcube:object name="plugin.calendar_css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
// UI startup
|
||||
var UI = new rcube_mail_ui();
|
||||
|
||||
$(document).ready(function(e) {
|
||||
UI.init();
|
||||
|
||||
// animation to unfold list search box
|
||||
$('#calendars .boxtitle a.search').click(function(e){
|
||||
var title = $('#calendars .boxtitle'),
|
||||
box = $('#calendars .listsearchbox'),
|
||||
dir = box.is(':visible') ? -1 : 1;
|
||||
|
||||
box.slideToggle({
|
||||
duration: 160,
|
||||
progress: function(animation, progress) {
|
||||
if (dir < 0) progress = 1 - progress;
|
||||
$('#calendars .scroller').css('top', (title.outerHeight() + 34 * progress) + 'px');
|
||||
},
|
||||
complete: function() {
|
||||
box.toggleClass('expanded');
|
||||
if (box.is(':visible')) {
|
||||
box.find('input[type=text]').focus();
|
||||
}
|
||||
else {
|
||||
$('#calendarlistsearch-reset').click();
|
||||
}
|
||||
// TODO: save state in localStorage
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -117,10 +117,10 @@
|
|||
<!-- attachments list (with upload form) -->
|
||||
<div id="event-panel-attachments">
|
||||
<div id="edit-attachments">
|
||||
<roundcube:object name="plugin.attachments_list" id="attachment-list" class="attachmentslist" />
|
||||
<roundcube:object name="plugin.attachments_list" id="attachmentlist" class="attachmentslist" />
|
||||
</div>
|
||||
<div id="edit-attachments-form" role="region" aria-labelledby="aria-label-attachmentuploadform">
|
||||
<h3 id="aria-label-attachmentuploadform" class="voice"><roundcube:label name="arialabelattachmentuploadform" /></h2>
|
||||
<h3 id="aria-label-attachmentuploadform" class="voice"><roundcube:label name="arialabelattachmentuploadform" /></h3>
|
||||
<roundcube:object name="plugin.attachments_form" id="calendar-attachment-form" attachmentFieldSize="30" />
|
||||
</div>
|
||||
<roundcube:object name="plugin.filedroparea" id="event-panel-attachments" />
|
||||
|
|
80
skins/larry/templates/eventshow.html
Normal file
80
skins/larry/templates/eventshow.html
Normal file
|
@ -0,0 +1,80 @@
|
|||
<div id="eventshow" class="uidialog eventdialog" aria-hidden="true">
|
||||
<h1 id="event-title">Event Title</h1>
|
||||
<div class="event-section" id="event-location">Location</div>
|
||||
<div class="event-section" id="event-date">From-To</div>
|
||||
<div class="event-section" id="event-description">
|
||||
<h5 class="label"><roundcube:label name="calendar.description" /></h5>
|
||||
<div class="event-text"></div>
|
||||
</div>
|
||||
<div class="event-section" id="event-url">
|
||||
<h5 class="label"><roundcube:label name="calendar.url" /></h5>
|
||||
<div class="event-text"></div>
|
||||
</div>
|
||||
<div class="event-section" id="event-repeat">
|
||||
<h5 class="label"><roundcube:label name="calendar.repeat" /></h5>
|
||||
<div class="event-text"></div>
|
||||
</div>
|
||||
<div class="event-section" id="event-alarm">
|
||||
<h5 class="label"><roundcube:label name="calendar.alarms" /></h5>
|
||||
<div class="event-text"></div>
|
||||
</div>
|
||||
<div class="event-section event-attendees" id="event-attendees">
|
||||
<h5 class="label"><roundcube:label name="calendar.tabattendees" /></h5>
|
||||
<div class="event-text"></div>
|
||||
</div>
|
||||
<div class="event-line" id="event-partstat">
|
||||
<label><roundcube:label name="calendar.mystatus" /></label>
|
||||
<span class="changersvp" role="button" tabindex="0" title="<roundcube:label name='calendar.changepartstat' />">
|
||||
<span class="event-text"></span>
|
||||
<a class="iconbutton edit"><roundcube:label name='calendar.changepartstat' /></a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="event-line" id="event-calendar">
|
||||
<label><roundcube:label name="calendar.calendar" /></label>
|
||||
<span class="event-text">Default</span>
|
||||
</div>
|
||||
<div class="event-line" id="event-category">
|
||||
<label><roundcube:label name="calendar.category" /></label>
|
||||
<span class="event-text"></span>
|
||||
</div>
|
||||
<div class="event-line" id="event-status">
|
||||
<label><roundcube:label name="calendar.status" /></label>
|
||||
<span class="event-text"></span>
|
||||
</div>
|
||||
<div class="event-line" id="event-free-busy">
|
||||
<label><roundcube:label name="calendar.freebusy" /></label>
|
||||
<span class="event-text"></span>
|
||||
</div>
|
||||
<div class="event-line" id="event-priority">
|
||||
<label><roundcube:label name="calendar.priority" /></label>
|
||||
<span class="event-text"></span>
|
||||
</div>
|
||||
<div class="event-line" id="event-sensitivity">
|
||||
<label><roundcube:label name="calendar.sensitivity" /></label>
|
||||
<span class="event-text"></span>
|
||||
</div>
|
||||
<div class="event-section" id="event-attachments">
|
||||
<label><roundcube:label name="attachments" /></label>
|
||||
<div class="event-text"></div>
|
||||
</div>
|
||||
<div class="event-line" id="event-created-changed">
|
||||
<label><roundcube:label name="calendar.created" /></label>
|
||||
<span class="event-text event-created"></span>
|
||||
<label><roundcube:label name="calendar.changed" /></label>
|
||||
<span class="event-text event-changed"></span>
|
||||
</div>
|
||||
<div class="event-line" id="event-rsvp-comment">
|
||||
<label><roundcube:label name="calendar.rsvpcomment" /></label>
|
||||
<span class="event-text"></span>
|
||||
</div>
|
||||
|
||||
<roundcube:object name="plugin.event_rsvp_buttons" id="event-rsvp" class="event-dialog-message" style="display:none" />
|
||||
</div>
|
||||
|
||||
<div id="eventoptionsmenu" class="popupmenu" aria-hidden="true">
|
||||
<h3 id="aria-label-eventoptions" class="voice"><roundcube:label name="calendar.eventoptions" /></h3>
|
||||
<ul id="eventoptionsmenu-menu" class="toolbarmenu" role="menu" aria-labelledby="aria-label-eventoptions">
|
||||
<li role="menuitem"><roundcube:button command="event-download" label="download" classAct="active" /></li>
|
||||
<li role="menuitem"><roundcube:button command="event-sendbymail" label="send" classAct="active" /></li>
|
||||
</ul>
|
||||
</div>
|
Loading…
Add table
Reference in a new issue