Page MenuHomePhorge

No OneTemporary

Size
710 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
index 53d3f203..81ca66e6 100644
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -1,3296 +1,3296 @@
<?php
/**
* Calendar plugin for Roundcube webmail
*
* @author Lazlo Westerhof <hello@lazlo.me>
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2010, Lazlo Westerhof <hello@lazlo.me>
* Copyright (C) 2014-2015, 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
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class calendar extends rcube_plugin
{
const FREEBUSY_UNKNOWN = 0;
const FREEBUSY_FREE = 1;
const FREEBUSY_BUSY = 2;
const FREEBUSY_TENTATIVE = 3;
const FREEBUSY_OOF = 4;
const SESSION_KEY = 'calendar_temp';
public $task = '?(?!logout).*';
public $rc;
public $lib;
public $resources_dir;
public $home; // declare public to be used in other classes
public $urlbase;
public $timezone;
public $timezone_offset;
public $gmt_offset;
public $ui;
public $defaults = array(
'calendar_default_view' => "agendaWeek",
'calendar_timeslots' => 2,
'calendar_work_start' => 6,
'calendar_work_end' => 18,
'calendar_agenda_range' => 60,
'calendar_agenda_sections' => 'smart',
'calendar_event_coloring' => 0,
'calendar_time_indicator' => true,
'calendar_allow_invite_shared' => false,
'calendar_itip_send_option' => 3,
'calendar_itip_after_action' => 0,
);
private $ical;
private $itip;
private $driver;
/**
* Plugin initialization.
*/
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'));
}
else if ($this->rc->action == 'feed' && !empty($_REQUEST['_cal'])) {
$this->add_hook('startup', array($this, 'ical_feed_export'));
}
else {
// default startup routine
$this->add_hook('startup', array($this, 'startup'));
}
$this->add_hook('user_delete', array($this, 'user_delete'));
}
/**
* Startup hook
*/
public function startup($args)
{
// the calendar module can be enabled/disabled by the kolab_auth plugin
if ($this->rc->config->get('calendar_disabled', false) || !$this->rc->config->get('calendar_enabled', true))
return;
// load Calendar user interface
if (!$this->rc->output->ajax_call && (!$this->rc->output->env['framed'] || $args['action'] == 'preview')) {
$this->ui->init();
// settings are required in (almost) every GUI step
if ($args['action'] != 'attend')
$this->rc->output->set_env('calendar_settings', $this->load_settings());
}
if ($args['task'] == 'calendar' && $args['action'] != 'save-pref') {
if ($args['action'] != 'upload') {
$this->load_driver();
}
// register calendar actions
$this->register_action('index', array($this, 'calendar_view'));
$this->register_action('event', array($this, 'event_action'));
$this->register_action('calendar', array($this, 'calendar_action'));
$this->register_action('count', array($this, 'count_events'));
$this->register_action('load_events', array($this, 'load_events'));
$this->register_action('export_events', array($this, 'export_events'));
$this->register_action('import_events', array($this, 'import_events'));
$this->register_action('upload', array($this, 'attachment_upload'));
$this->register_action('get-attachment', array($this, 'attachment_get'));
$this->register_action('freebusy-status', array($this, 'freebusy_status'));
$this->register_action('freebusy-times', array($this, 'freebusy_times'));
$this->register_action('randomdata', array($this, 'generate_randomdata'));
$this->register_action('print', array($this,'print_view'));
$this->register_action('mailimportitip', array($this, 'mail_import_itip'));
$this->register_action('mailimportattach', array($this, 'mail_import_attachment'));
$this->register_action('mailtoevent', array($this, 'mail_message2event'));
$this->register_action('inlineui', array($this, 'get_inline_ui'));
$this->register_action('check-recent', array($this, 'check_recent'));
$this->register_action('itip-status', array($this, 'event_itip_status'));
$this->register_action('itip-remove', array($this, 'event_itip_remove'));
$this->register_action('itip-decline-reply', array($this, 'mail_itip_decline_reply'));
$this->register_action('itip-delegate', array($this, 'mail_itip_delegate'));
$this->register_action('resources-list', array($this, 'resources_list'));
$this->register_action('resources-owner', array($this, 'resources_owner'));
$this->register_action('resources-calendar', array($this, 'resources_calendar'));
$this->register_action('resources-autocomplete', array($this, 'resources_autocomplete'));
$this->add_hook('refresh', array($this, 'refresh'));
// remove undo information...
if ($undo = $_SESSION['calendar_event_undo']) {
// ...after timeout
$undo_time = $this->rc->config->get('undo_timeout', 0);
if ($undo['ts'] < time() - $undo_time) {
$this->rc->session->remove('calendar_event_undo');
// @TODO: do EXPUNGE on kolab objects?
}
}
}
else if ($args['task'] == 'settings') {
// add hooks for Calendar settings
$this->add_hook('preferences_sections_list', array($this, 'preferences_sections_list'));
$this->add_hook('preferences_list', array($this, 'preferences_list'));
$this->add_hook('preferences_save', array($this, 'preferences_save'));
}
else if ($args['task'] == 'mail') {
// hooks to catch event invitations on incoming mails
if ($args['action'] == 'show' || $args['action'] == 'preview') {
$this->add_hook('template_object_messagebody', array($this, 'mail_messagebody_html'));
}
// add 'Create event' item to message menu
if ($this->api->output->type == 'html') {
$this->api->add_content(html::tag('li', null,
$this->api->output->button(array(
'command' => 'calendar-create-from-mail',
'label' => 'calendar.createfrommail',
'type' => 'link',
'classact' => 'icon calendarlink active',
'class' => 'icon calendarlink',
'innerclass' => 'icon calendar',
))),
'messagemenu');
$this->api->output->add_label('calendar.createfrommail');
}
$this->add_hook('messages_list', array($this, 'mail_messages_list'));
$this->add_hook('message_compose', array($this, 'mail_message_compose'));
}
else if ($args['task'] == 'addressbook') {
if ($this->rc->config->get('calendar_contact_birthdays')) {
$this->add_hook('contact_update', array($this, 'contact_update'));
$this->add_hook('contact_create', array($this, 'contact_update'));
}
}
// add hooks to display alarms
$this->add_hook('pending_alarms', array($this, 'pending_alarms'));
$this->add_hook('dismiss_alarms', array($this, 'dismiss_alarms'));
}
/**
* Helper method to load the backend driver according to local config
*/
private function load_driver()
{
if (is_object($this->driver))
return;
$driver_name = $this->rc->config->get('calendar_driver', 'database');
$driver_class = $driver_name . '_driver';
require_once($this->home . '/drivers/calendar_driver.php');
require_once($this->home . '/drivers/' . $driver_name . '/' . $driver_class . '.php');
$this->driver = new $driver_class($this);
if ($this->driver->undelete)
$this->driver->undelete = $this->rc->config->get('undo_timeout', 0) > 0;
}
/**
* Load iTIP functions
*/
private function load_itip()
{
if (!$this->itip) {
require_once($this->home . '/lib/calendar_itip.php');
$this->itip = new calendar_itip($this);
if ($this->rc->config->get('kolab_invitation_calendars'))
$this->itip->set_rsvp_actions(array('accepted','tentative','declined','delegated','needs-action'));
}
return $this->itip;
}
/**
* Load iCalendar functions
*/
public function get_ical()
{
if (!$this->ical) {
$this->ical = libcalendaring::get_ical();
}
return $this->ical;
}
/**
* Get properties of the calendar this user has specified as default
*/
public function get_default_calendar($writeable = false, $confidential = false)
{
$default_id = $this->rc->config->get('calendar_default_calendar');
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL);
$calendar = $calendars[$default_id] ?: null;
if (!$calendar || $confidential || ($writeable && !$calendar['editable'])) {
foreach ($calendars as $cal) {
if ($confidential && $cal['subtype'] == 'confidential') {
$calendar = $cal;
break;
}
if ($cal['default']) {
$calendar = $cal;
if (!$confidential)
break;
}
if (!$writeable || $cal['editable']) {
$first = $cal;
}
}
}
return $calendar ?: $first;
}
/**
* Render the main calendar view from skin template
*/
function calendar_view()
{
$this->rc->output->set_pagetitle($this->gettext('calendar'));
// Add CSS stylesheets to the page header
$this->ui->addCSS();
// Add JS files to the page header
$this->ui->addJS();
$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
rcube_autocomplete_init();
$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);
if (in_array($view, array('agendaWeek', 'agendaDay', 'month', 'table')))
$this->rc->output->set_env('view', $view);
if ($date = rcube_utils::get_input_value('date', rcube_utils::INPUT_GPC))
$this->rc->output->set_env('date', $date);
if ($msgref = rcube_utils::get_input_value('itip', rcube_utils::INPUT_GPC))
$this->rc->output->set_env('itip_events', $this->itip_events($msgref));
$this->rc->output->send("calendar.calendar");
}
/**
* Handler for preferences_sections_list hook.
* Adds Calendar settings sections into preferences sections list.
*
* @param array Original parameters
* @return array Modified parameters
*/
function preferences_sections_list($p)
{
$p['list']['calendar'] = array(
'id' => 'calendar', 'section' => $this->gettext('calendar'),
);
return $p;
}
/**
* Handler for preferences_list hook.
* Adds options blocks into Calendar settings sections in Preferences.
*
* @param array Original parameters
* @return array Modified parameters
*/
function preferences_list($p)
{
if ($p['section'] != 'calendar') {
return $p;
}
$no_override = array_flip((array)$this->rc->config->get('dont_override'));
$p['blocks']['view']['name'] = $this->gettext('mainoptions');
if (!isset($no_override['calendar_default_view'])) {
if (!$p['current']) {
$p['blocks']['view']['content'] = true;
return $p;
}
$field_id = 'rcmfd_default_view';
$select = new html_select(array('name' => '_default_view', 'id' => $field_id));
$select->add($this->gettext('day'), "agendaDay");
$select->add($this->gettext('week'), "agendaWeek");
$select->add($this->gettext('month'), "month");
$select->add($this->gettext('agenda'), "table");
$p['blocks']['view']['options']['default_view'] = array(
'title' => html::label($field_id, Q($this->gettext('default_view'))),
'content' => $select->show($this->rc->config->get('calendar_default_view', $this->defaults['calendar_default_view'])),
);
}
if (!isset($no_override['calendar_timeslots'])) {
if (!$p['current']) {
$p['blocks']['view']['content'] = true;
return $p;
}
$field_id = 'rcmfd_timeslot';
$choices = array('1', '2', '3', '4', '6');
$select = new html_select(array('name' => '_timeslots', 'id' => $field_id));
$select->add($choices);
$p['blocks']['view']['options']['timeslots'] = array(
'title' => html::label($field_id, Q($this->gettext('timeslots'))),
'content' => $select->show(strval($this->rc->config->get('calendar_timeslots', $this->defaults['calendar_timeslots']))),
);
}
if (!isset($no_override['calendar_first_day'])) {
if (!$p['current']) {
$p['blocks']['view']['content'] = true;
return $p;
}
$field_id = 'rcmfd_firstday';
$select = new html_select(array('name' => '_first_day', 'id' => $field_id));
$select->add(rcube_label('sunday'), '0');
$select->add(rcube_label('monday'), '1');
$select->add(rcube_label('tuesday'), '2');
$select->add(rcube_label('wednesday'), '3');
$select->add(rcube_label('thursday'), '4');
$select->add(rcube_label('friday'), '5');
$select->add(rcube_label('saturday'), '6');
$p['blocks']['view']['options']['first_day'] = array(
'title' => html::label($field_id, Q($this->gettext('first_day'))),
'content' => $select->show(strval($this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']))),
);
}
if (!isset($no_override['calendar_first_hour'])) {
if (!$p['current']) {
$p['blocks']['view']['content'] = true;
return $p;
}
$time_format = $this->rc->config->get('time_format', libcalendaring::to_php_date_format($this->rc->config->get('calendar_time_format', $this->defaults['calendar_time_format'])));
$select_hours = new html_select();
for ($h = 0; $h < 24; $h++)
$select_hours->add(date($time_format, mktime($h, 0, 0)), $h);
$field_id = 'rcmfd_firsthour';
$p['blocks']['view']['options']['first_hour'] = array(
'title' => html::label($field_id, Q($this->gettext('first_hour'))),
'content' => $select_hours->show($this->rc->config->get('calendar_first_hour', $this->defaults['calendar_first_hour']), array('name' => '_first_hour', 'id' => $field_id)),
);
}
if (!isset($no_override['calendar_work_start'])) {
if (!$p['current']) {
$p['blocks']['view']['content'] = true;
return $p;
}
$field_id = 'rcmfd_workstart';
$p['blocks']['view']['options']['workinghours'] = array(
'title' => html::label($field_id, Q($this->gettext('workinghours'))),
'content' => $select_hours->show($this->rc->config->get('calendar_work_start', $this->defaults['calendar_work_start']), array('name' => '_work_start', 'id' => $field_id)) .
' &mdash; ' . $select_hours->show($this->rc->config->get('calendar_work_end', $this->defaults['calendar_work_end']), array('name' => '_work_end', 'id' => $field_id)),
);
}
if (!isset($no_override['calendar_event_coloring'])) {
if (!$p['current']) {
$p['blocks']['view']['content'] = true;
return $p;
}
$field_id = 'rcmfd_coloring';
$select_colors = new html_select(array('name' => '_event_coloring', 'id' => $field_id));
$select_colors->add($this->gettext('coloringmode0'), 0);
$select_colors->add($this->gettext('coloringmode1'), 1);
$select_colors->add($this->gettext('coloringmode2'), 2);
$select_colors->add($this->gettext('coloringmode3'), 3);
$p['blocks']['view']['options']['eventcolors'] = array(
'title' => html::label($field_id . 'value', Q($this->gettext('eventcoloring'))),
'content' => $select_colors->show($this->rc->config->get('calendar_event_coloring', $this->defaults['calendar_event_coloring'])),
);
}
// loading driver is expensive, don't do it if not needed
$this->load_driver();
if (!isset($no_override['calendar_default_alarm_type'])) {
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(rcube_label(strtolower("alarm{$type}option"), 'libcalendaring'), $type);
$p['blocks']['view']['options']['alarmtype'] = array(
'title' => html::label($field_id, 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(rcube_label('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', Q($this->gettext('defaultalarmoffset'))),
'content' => $input_value->show($preset[0]) . ' ' . $select_offset->show($preset[1]),
);
}
if (!isset($no_override['calendar_default_calendar'])) {
if (!$p['current']) {
$p['blocks']['view']['content'] = true;
return $p;
}
// 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) {
$select_cal->add($prop['name'], strval($id));
if ($prop['default'])
$default_calendar = $id;
}
$p['blocks']['view']['options']['defaultcalendar'] = array(
'title' => html::label($field_id . 'value', Q($this->gettext('defaultcalendar'))),
'content' => $select_cal->show($this->rc->config->get('calendar_default_calendar', $default_calendar)),
);
}
$p['blocks']['itip']['name'] = $this->gettext('itipoptions');
// Invitations handling
if (!isset($no_override['calendar_itip_after_action'])) {
if (!$p['current']) {
$p['blocks']['itip']['content'] = true;
return $p;
}
$field_id = 'rcmfd_after_action';
$select = new html_select(array('name' => '_after_action', 'id' => $field_id,
'onchange' => "\$('#{$field_id}_select')[this.value == 4 ? 'show' : 'hide']()"));
$select->add($this->gettext('afternothing'), '');
$select->add($this->gettext('aftertrash'), 1);
$select->add($this->gettext('afterdelete'), 2);
$select->add($this->gettext('afterflagdeleted'), 3);
$select->add($this->gettext('aftermoveto'), 4);
$val = $this->rc->config->get('calendar_itip_after_action', $this->defaults['calendar_itip_after_action']);
if ($val !== null && $val !== '' && !is_int($val)) {
$folder = $val;
$val = 4;
}
$folders = $this->rc->folder_selector(array(
'id' => $field_id . '_select',
'name' => '_after_action_folder',
'maxlength' => 30,
'folder_filter' => 'mail',
'folder_rights' => 'w',
'style' => $val !== 4 ? 'display:none' : '',
));
$p['blocks']['itip']['options']['after_action'] = array(
'title' => html::label($field_id, Q($this->gettext('afteraction'))),
'content' => $select->show($val) . $folders->show($folder),
);
}
// category definitions
if (!$this->driver->nocategories && !isset($no_override['calendar_categories'])) {
$p['blocks']['categories']['name'] = $this->gettext('categories');
if (!$p['current']) {
$p['blocks']['categories']['content'] = true;
return $p;
}
$categories = (array) $this->driver->list_categories();
$categories_list = '';
foreach ($categories as $name => $color) {
$key = md5($name);
$field_class = 'rcmfd_category_' . str_replace(' ', '_', $name);
$category_remove = new html_inputfield(array('type' => 'button', 'value' => 'X', 'class' => 'button', 'onclick' => '$(this).parent().remove()', 'title' => $this->gettext('remove_category')));
$category_name = new html_inputfield(array('name' => "_categories[$key]", 'class' => $field_class, 'size' => 30, 'disabled' => $this->driver->categoriesimmutable));
$category_color = new html_inputfield(array('name' => "_colors[$key]", 'class' => "$field_class colors", 'size' => 6));
$hidden = $this->driver->categoriesimmutable ? html::tag('input', array('type' => 'hidden', 'name' => "_categories[$key]", 'value' => $name)) : '';
$categories_list .= html::div(null, $hidden . $category_name->show($name) . '&nbsp;' . $category_color->show($color) . '&nbsp;' . $category_remove->show());
}
$p['blocks']['categories']['options']['category_' . $name] = array(
'content' => html::div(array('id' => 'calendarcategories'), $categories_list),
);
$field_id = 'rcmfd_new_category';
$new_category = new html_inputfield(array('name' => '_new_category', 'id' => $field_id, 'size' => 30));
$add_category = new html_inputfield(array('type' => 'button', 'class' => 'button', 'value' => $this->gettext('add_category'), 'onclick' => "rcube_calendar_add_category()"));
$p['blocks']['categories']['options']['categories'] = array(
'content' => $new_category->show('') . '&nbsp;' . $add_category->show(),
);
$this->rc->output->add_script('function rcube_calendar_add_category(){
var name = $("#rcmfd_new_category").val();
if (name.length) {
var input = $("<input>").attr("type", "text").attr("name", "_categories[]").attr("size", 30).val(name);
var color = $("<input>").attr("type", "text").attr("name", "_colors[]").attr("size", 6).addClass("colors").val("000000");
var button = $("<input>").attr("type", "button").attr("value", "X").addClass("button").click(function(){ $(this).parent().remove() });
$("<div>").append(input).append("&nbsp;").append(color).append("&nbsp;").append(button).appendTo("#calendarcategories");
color.miniColors({ colorValues:(rcmail.env.mscolors || []) });
$("#rcmfd_new_category").val("");
}
}');
$this->rc->output->add_script('$("#rcmfd_new_category").keypress(function(event){
if (event.which == 13) {
rcube_calendar_add_category();
event.preventDefault();
}
});
', 'docready');
// load miniColors js/css files
jqueryui::miniColors();
}
// virtual birthdays calendar
if (!isset($no_override['calendar_contact_birthdays'])) {
$p['blocks']['birthdays']['name'] = $this->gettext('birthdayscalendar');
if (!$p['current']) {
$p['blocks']['birthdays']['content'] = true;
return $p;
}
$field_id = 'rcmfd_contact_birthdays';
$input = new html_checkbox(array('name' => '_contact_birthdays', 'id' => $field_id, 'value' => 1, 'onclick' => '$(".calendar_birthday_props").prop("disabled",!this.checked)'));
$p['blocks']['birthdays']['options']['contact_birthdays'] = array(
'title' => html::label($field_id, $this->gettext('displaybirthdayscalendar')),
'content' => $input->show($this->rc->config->get('calendar_contact_birthdays')?1:0),
);
$input_attrib = array(
'class' => 'calendar_birthday_props',
'disabled' => !$this->rc->config->get('calendar_contact_birthdays'),
);
$sources = array();
$checkbox = new html_checkbox(array('name' => '_birthday_adressbooks[]') + $input_attrib);
foreach ($this->rc->get_address_sources(false, true) as $source) {
$active = in_array($source['id'], (array)$this->rc->config->get('calendar_birthday_adressbooks', array())) ? $source['id'] : '';
$sources[] = html::label(null, $checkbox->show($active, array('value' => $source['id'])) . '&nbsp;' . rcube::Q($source['realname'] ?: $source['name']));
}
$p['blocks']['birthdays']['options']['birthday_adressbooks'] = array(
'title' => rcube::Q($this->gettext('birthdayscalendarsources')),
'content' => join(html::br(), $sources),
);
$field_id = 'rcmfd_birthdays_alarm';
$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(rcube_label(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(rcube_label('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(
'title' => html::label($field_id . 'value', rcube::Q($this->gettext('showalarms'))),
'content' => $select_type->show($this->rc->config->get('calendar_birthdays_alarm_type', '')) . ' ' . $input_value->show($preset[0]) . '&nbsp;' . $select_offset->show($preset[1]),
);
}
return $p;
}
/**
* Handler for preferences_save hook.
* Executed on Calendar settings form submit.
*
* @param array Original parameters
* @return array Modified parameters
*/
function preferences_save($p)
{
if ($p['section'] == 'calendar') {
$this->load_driver();
// compose default alarm preset value
$alarm_offset = rcube_utils::get_input_value('_alarm_offset', rcube_utils::INPUT_POST);
$alarm_value = rcube_utils::get_input_value('_alarm_value', rcube_utils::INPUT_POST);
$default_alarm = $alarm_offset[0] . intval($alarm_value) . $alarm_offset[1];
$birthdays_alarm_offset = rcube_utils::get_input_value('_birthdays_alarm_offset', rcube_utils::INPUT_POST);
$birthdays_alarm_value = rcube_utils::get_input_value('_birthdays_alarm_value', rcube_utils::INPUT_POST);
$birthdays_alarm_value = $birthdays_alarm_offset[0] . intval($birthdays_alarm_value) . $birthdays_alarm_offset[1];
$p['prefs'] = array(
'calendar_default_view' => rcube_utils::get_input_value('_default_view', rcube_utils::INPUT_POST),
'calendar_timeslots' => intval(rcube_utils::get_input_value('_timeslots', rcube_utils::INPUT_POST)),
'calendar_first_day' => intval(rcube_utils::get_input_value('_first_day', rcube_utils::INPUT_POST)),
'calendar_first_hour' => intval(rcube_utils::get_input_value('_first_hour', rcube_utils::INPUT_POST)),
'calendar_work_start' => intval(rcube_utils::get_input_value('_work_start', rcube_utils::INPUT_POST)),
'calendar_work_end' => intval(rcube_utils::get_input_value('_work_end', rcube_utils::INPUT_POST)),
'calendar_event_coloring' => intval(rcube_utils::get_input_value('_event_coloring', rcube_utils::INPUT_POST)),
'calendar_default_alarm_type' => rcube_utils::get_input_value('_alarm_type', rcube_utils::INPUT_POST),
'calendar_default_alarm_offset' => $default_alarm,
'calendar_default_calendar' => rcube_utils::get_input_value('_default_calendar', rcube_utils::INPUT_POST),
'calendar_date_format' => null, // clear previously saved values
'calendar_time_format' => null,
'calendar_contact_birthdays' => rcube_utils::get_input_value('_contact_birthdays', rcube_utils::INPUT_POST) ? true : false,
'calendar_birthday_adressbooks' => (array) rcube_utils::get_input_value('_birthday_adressbooks', rcube_utils::INPUT_POST),
'calendar_birthdays_alarm_type' => rcube_utils::get_input_value('_birthdays_alarm_type', rcube_utils::INPUT_POST),
'calendar_birthdays_alarm_offset' => $birthdays_alarm_value ?: null,
'calendar_itip_after_action' => intval(rcube_utils::get_input_value('_after_action', rcube_utils::INPUT_POST)),
);
if ($p['prefs']['calendar_itip_after_action'] == 4) {
$p['prefs']['calendar_itip_after_action'] = rcube_utils::get_input_value('_after_action_folder', rcube_utils::INPUT_POST, true);
}
// categories
if (!$this->driver->nocategories) {
$old_categories = $new_categories = array();
foreach ($this->driver->list_categories() as $name => $color) {
$old_categories[md5($name)] = $name;
}
$categories = (array) rcube_utils::get_input_value('_categories', rcube_utils::INPUT_POST);
$colors = (array) rcube_utils::get_input_value('_colors', rcube_utils::INPUT_POST);
foreach ($categories as $key => $name) {
$color = preg_replace('/^#/', '', strval($colors[$key]));
// rename categories in existing events -> driver's job
if ($oldname = $old_categories[$key]) {
$this->driver->replace_category($oldname, $name, $color);
unset($old_categories[$key]);
}
else
$this->driver->add_category($name, $color);
$new_categories[$name] = $color;
}
// these old categories have been removed, alter events accordingly -> driver's job
foreach ((array)$old_categories[$key] as $key => $name) {
$this->driver->remove_category($name);
}
$p['prefs']['calendar_categories'] = $new_categories;
}
}
return $p;
}
/**
* Dispatcher for calendar actions initiated by the client
*/
function calendar_action()
{
$action = rcube_utils::get_input_value('action', rcube_utils::INPUT_GPC);
$cal = rcube_utils::get_input_value('c', rcube_utils::INPUT_GPC);
$success = $reload = false;
if (isset($cal['showalarms']))
$cal['showalarms'] = intval($cal['showalarms']);
switch ($action) {
case "form-new":
case "form-edit":
echo $this->ui->calendar_editform($action, $cal);
exit;
case "new":
$success = $this->driver->create_calendar($cal);
$reload = true;
break;
case "edit":
$success = $this->driver->edit_calendar($cal);
$reload = true;
break;
case "delete":
if ($success = $this->driver->delete_calendar($cal))
$this->rc->output->command('plugin.destroy_source', array('id' => $cal['id']));
break;
case "subscribe":
if (!$this->driver->subscribe_calendar($cal))
$this->rc->output->show_message($this->gettext('errorsaving'), 'error');
return;
case "search":
$results = array();
$color_mode = $this->rc->config->get('calendar_event_coloring', $this->defaults['calendar_event_coloring']);
$query = rcube_utils::get_input_value('q', rcube_utils::INPUT_GPC);
$source = rcube_utils::get_input_value('source', rcube_utils::INPUT_GPC);
foreach ((array) $this->driver->search_calendars($query, $source) as $id => $prop) {
$editname = $prop['editname'];
unset($prop['editname']); // force full name to be displayed
$prop['active'] = false;
// let the UI generate HTML and CSS representation for this calendar
$html = $this->ui->calendar_list_item($id, $prop, $jsenv);
$cal = $jsenv[$id];
$cal['editname'] = $editname;
$cal['html'] = $html;
if (!empty($prop['color']))
$cal['css'] = $this->ui->calendar_css_classes($id, $prop, $color_mode);
$results[] = $cal;
}
// report more results available
if ($this->driver->search_more_results)
$this->rc->output->show_message('autocompletemore', 'info');
$this->rc->output->command('multi_thread_http_response', $results, rcube_utils::get_input_value('_reqid', rcube_utils::INPUT_GPC));
return;
}
if ($success)
$this->rc->output->show_message('successfullysaved', 'confirmation');
else {
$error_msg = $this->gettext('errorsaving') . ($this->driver->last_error ? ': ' . $this->driver->last_error :'');
$this->rc->output->show_message($error_msg, 'error');
}
$this->rc->output->command('plugin.unlock_saving');
if ($success && $reload)
$this->rc->output->command('plugin.reload_view');
}
/**
* Dispatcher for event actions initiated by the client
*/
function event_action()
{
$action = rcube_utils::get_input_value('action', rcube_utils::INPUT_GPC);
$event = rcube_utils::get_input_value('e', rcube_utils::INPUT_POST, true);
$success = $reload = $got_msg = false;
// force notify if hidden + active
if ((int)$this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']) === 1)
$event['_notify'] = 1;
// read old event data in order to find changes
if (($event['_notify'] || $event['_decline']) && $action != 'new') {
$old = $this->driver->get_event($event);
// load main event if savemode is 'all' or if deleting 'future' events
if (($event['_savemode'] == 'all' || ($event['_savemode'] == 'future' && $action == 'remove' && !$event['_decline'])) && $old['recurrence_id']) {
$old['id'] = $old['recurrence_id'];
$old = $this->driver->get_event($old);
}
}
switch ($action) {
case "new":
// create UID for new event
$event['uid'] = $this->generate_uid();
$this->write_preprocess($event, $action);
if ($success = $this->driver->new_event($event)) {
$event['id'] = $event['uid'];
$event['_savemode'] = 'all';
$this->cleanup_event($event);
$this->event_save_success($event, null, $action, true);
}
$reload = $success && $event['recurrence'] ? 2 : 1;
break;
case "edit":
$this->write_preprocess($event, $action);
if ($success = $this->driver->edit_event($event)) {
$this->cleanup_event($event);
$this->event_save_success($event, $old, $action, $success);
}
$reload = $success && ($event['recurrence'] || $event['_savemode'] || $event['_fromcalendar']) ? 2 : 1;
break;
case "resize":
$this->write_preprocess($event, $action);
if ($success = $this->driver->resize_event($event)) {
$this->event_save_success($event, $old, $action, $success);
}
$reload = $event['_savemode'] ? 2 : 1;
break;
case "move":
$this->write_preprocess($event, $action);
if ($success = $this->driver->move_event($event)) {
$this->event_save_success($event, $old, $action, $success);
}
$reload = $success && $event['_savemode'] ? 2 : 1;
break;
case "remove":
// remove previous deletes
$undo_time = $this->driver->undelete ? $this->rc->config->get('undo_timeout', 0) : 0;
$this->rc->session->remove('calendar_event_undo');
// search for event if only UID is given
if (!isset($event['calendar']) && $event['uid']) {
if (!($event = $this->driver->get_event($event, calendar_driver::FILTER_WRITEABLE))) {
break;
}
$undo_time = 0;
}
$success = $this->driver->remove_event($event, $undo_time < 1);
$reload = (!$success || $event['_savemode']) ? 2 : 1;
if ($undo_time > 0 && $success) {
$_SESSION['calendar_event_undo'] = array('ts' => time(), 'data' => $event);
// display message with Undo link.
$msg = html::span(null, $this->gettext('successremoval'))
. ' ' . html::a(array('onclick' => sprintf("%s.http_request('event', 'action=undo', %s.display_message('', 'loading'))",
JS_OBJECT_NAME, JS_OBJECT_NAME)), rcube_label('undo'));
$this->rc->output->show_message($msg, 'confirmation', null, true, $undo_time);
$got_msg = true;
}
else if ($success) {
$this->rc->output->show_message('calendar.successremoval', 'confirmation');
$got_msg = true;
}
// send cancellation for the main event
if ($event['_savemode'] == 'all') {
unset($old['_instance'], $old['recurrence_date'], $old['recurrence_id']);
}
// send an update for the main event's recurrence rule instead of a cancellation message
else if ($event['_savemode'] == 'future' && $success !== false && $success !== true) {
$event['_savemode'] = 'all'; // force event_save_success() to load master event
$action = 'edit';
$success = true;
}
// send iTIP reply that participant has declined the event
if ($success && $event['_decline']) {
$emails = $this->get_user_emails();
foreach ($old['attendees'] as $i => $attendee) {
if ($attendee['role'] == 'ORGANIZER')
$organizer = $attendee;
else if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) {
$old['attendees'][$i]['status'] = 'DECLINED';
$reply_sender = $attendee['email'];
}
}
if ($event['_savemode'] == 'future' && $event['id'] != $old['id']) {
$old['thisandfuture'] = true;
}
$itip = $this->load_itip();
$itip->set_sender_email($reply_sender);
if ($organizer && $itip->send_itip_message($old, 'REPLY', $organizer, 'itipsubjectdeclined', 'itipmailbodydeclined'))
$this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $organizer['name'] ? $organizer['name'] : $organizer['email']))), 'confirmation');
else
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
}
else if ($success) {
$this->event_save_success($event, $old, $action, $success);
}
break;
case "undo":
// Restore deleted event
$event = $_SESSION['calendar_event_undo']['data'];
if ($event)
$success = $this->driver->restore_event($event);
if ($success) {
$this->rc->session->remove('calendar_event_undo');
$this->rc->output->show_message('calendar.successrestore', 'confirmation');
$got_msg = true;
$reload = 2;
}
break;
case "rsvp":
$itip_sending = $this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']);
$status = rcube_utils::get_input_value('status', rcube_utils::INPUT_POST);
$attendees = rcube_utils::get_input_value('attendees', rcube_utils::INPUT_POST);
$reply_comment = $event['comment'];
$this->write_preprocess($event, 'edit');
$ev = $this->driver->get_event($event);
$ev['attendees'] = $event['attendees'];
$ev['free_busy'] = $event['free_busy'];
$ev['_savemode'] = $event['_savemode'];
// send invitation to delegatee + add it as attendee
if ($status == 'delegated' && $event['to']) {
$itip = $this->load_itip();
if ($itip->delegate_to($ev, $event['to'], (bool)$event['rsvp'], $attendees)) {
$this->rc->output->show_message('calendar.itipsendsuccess', 'confirmation');
$noreply = false;
}
}
$event = $ev;
// compose a list of attendees affected by this change
$updated_attendees = array_filter(array_map(function($j) use ($event) {
return $event['attendees'][$j];
}, $attendees));
if ($success = $this->driver->edit_rsvp($event, $status, $updated_attendees)) {
$noreply = rcube_utils::get_input_value('noreply', rcube_utils::INPUT_GPC);
$noreply = intval($noreply) || $status == 'needs-action' || $itip_sending === 0;
$reload = $event['calendar'] != $ev['calendar'] || $event['recurrence'] ? 2 : 1;
$organizer = null;
$emails = $this->get_user_emails();
foreach ($event['attendees'] as $i => $attendee) {
if ($attendee['role'] == 'ORGANIZER') {
$organizer = $attendee;
}
else if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) {
$reply_sender = $attendee['email'];
}
}
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');
else
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
}
// refresh all calendars
if ($event['calendar'] != $ev['calendar']) {
$this->rc->output->command('plugin.refresh_calendar', array('source' => null, 'refetch' => true));
$reload = 0;
}
}
break;
case "dismiss":
$event['ids'] = explode(',', $event['id']);
$plugin = $this->rc->plugins->exec_hook('dismiss_alarms', $event);
$success = $plugin['success'];
foreach ($event['ids'] as $id) {
if (strpos($id, 'cal:') === 0)
$success |= $this->driver->dismiss_alarm(substr($id, 4), $event['snooze']);
}
break;
case "changelog":
$data = $this->driver->get_event_changelog($event);
if (is_array($data) && !empty($data)) {
$lib = $this->lib;
$dtformat = $this->rc->config->get('date_format') . ' ' . $this->rc->config->get('time_format');
array_walk($data, function(&$change) use ($lib, $dtformat) {
if ($change['date']) {
$dt = $lib->adjust_timezone($change['date']);
if ($dt instanceof DateTime)
$change['date'] = $this->rc->format_date($dt, $dtformat, false);
}
});
$this->rc->output->command('plugin.render_event_changelog', $data);
}
else {
$this->rc->output->command('plugin.render_event_changelog', false);
}
$got_msg = true;
$reload = false;
break;
case "diff":
$data = $this->driver->get_event_diff($event, $event['rev1'], $event['rev2']);
if (is_array($data)) {
// convert some properties, similar to self::_client_event()
$lib = $this->lib;
array_walk($data['changes'], function(&$change, $i) use ($event, $lib) {
// convert date cols
foreach (array('start','end','created','changed') as $col) {
if ($change['property'] == $col) {
$change['old'] = $lib->adjust_timezone($change['old'], strlen($change['old']) == 10)->format('c');
$change['new'] = $lib->adjust_timezone($change['new'], strlen($change['new']) == 10)->format('c');
}
}
// create textual representation for alarms and recurrence
if ($change['property'] == 'alarms') {
if (is_array($change['old']))
$change['old_'] = libcalendaring::alarm_text($change['old']);
if (is_array($change['new']))
$change['new_'] = libcalendaring::alarm_text(array_merge((array)$change['old'], $change['new']));
}
if ($change['property'] == 'recurrence') {
if (is_array($change['old']))
$change['old_'] = $lib->recurrence_text($change['old']);
if (is_array($change['new']))
$change['new_'] = $lib->recurrence_text(array_merge((array)$change['old'], $change['new']));
}
if ($change['property'] == 'attachments') {
if (is_array($change['old']))
$change['old']['classname'] = rcube_utils::file2class($change['old']['mimetype'], $change['old']['name']);
if (is_array($change['new']))
$change['new']['classname'] = rcube_utils::file2class($change['new']['mimetype'], $change['new']['name']);
}
// compute a nice diff of description texts
if ($change['property'] == 'description') {
$change['diff_'] = libkolab::html_diff($change['old'], $change['new']);
}
});
$this->rc->output->command('plugin.event_show_diff', $data);
}
else {
- $this->rc->output->command('display_message', $this->gettext('eventdiffnotavailable'), 'error');
+ $this->rc->output->command('display_message', $this->gettext('objectdiffnotavailable'), 'error');
}
$got_msg = true;
$reload = false;
break;
case "show":
if ($event = $this->driver->get_event_revison($event, $event['rev'])) {
$this->rc->output->command('plugin.event_show_revision', $this->_client_event($event));
}
else {
- $this->rc->output->command('display_message', $this->gettext('eventnotfound'), 'error');
+ $this->rc->output->command('display_message', $this->gettext('objectnotfound'), 'error');
}
$got_msg = true;
$reload = false;
break;
case "restore":
if ($success = $this->driver->restore_event_revision($event, $event['rev'])) {
$_event = $this->driver->get_event($event);
$reload = $_event['recurrence'] ? 2 : 1;
- $this->rc->output->command('display_message', $this->gettext(array('name' => 'eventrestoresuccess', 'vars' => array('rev' => $event['rev']))), 'confirmation');
+ $this->rc->output->command('display_message', $this->gettext(array('name' => 'objectrestoresuccess', 'vars' => array('rev' => $event['rev']))), 'confirmation');
$this->rc->output->command('plugin.close_history_dialog');
}
else {
- $this->rc->output->command('display_message', $this->gettext('eventrestoreerror'), 'error');
+ $this->rc->output->command('display_message', $this->gettext('objectrestoreerror'), 'error');
$reload = 0;
}
$got_msg = true;
break;
}
// show confirmation/error message
if (!$got_msg) {
if ($success)
$this->rc->output->show_message('successfullysaved', 'confirmation');
else
$this->rc->output->show_message('calendar.errorsaving', 'error');
}
// unlock client
$this->rc->output->command('plugin.unlock_saving');
// update event object on the client or trigger a complete refretch if too complicated
if ($reload) {
$args = array('source' => $event['calendar']);
if ($reload > 1)
$args['refetch'] = true;
else if ($success && $action != 'remove')
$args['update'] = $this->_client_event($this->driver->get_event($event), true);
$this->rc->output->command('plugin.refresh_calendar', $args);
}
}
/**
* Helper method sending iTip notifications after successful event updates
*/
private function event_save_success(&$event, $old, $action, $success)
{
// $success is a new event ID
if ($success !== true) {
// send update notification on the main event
if ($event['_savemode'] == 'future' && $event['_notify'] && $old['attendees'] && $old['recurrence_id']) {
$master = $this->driver->get_event(array('id' => $old['recurrence_id'], 'calendar' => $old['calendar']), 0, true);
unset($master['_instance'], $master['recurrence_date']);
$sent = $this->notify_attendees($master, null, $action, $event['_comment']);
if ($sent < 0)
$this->rc->output->show_message('calendar.errornotifying', 'error');
$event['attendees'] = $master['attendees']; // this tricks us into the next if clause
}
// delete old reference if saved as new
if ($event['_savemode'] == 'future' || $event['_savemode'] == 'new') {
$old = null;
}
$event['id'] = $success;
$event['_savemode'] = 'all';
}
// send out notifications
if ($event['_notify'] && ($event['attendees'] || $old['attendees'])) {
$_savemode = $event['_savemode'];
// send notification for the main event when savemode is 'all'
if ($action != 'remove' && $_savemode == 'all' && ($event['recurrence_id'] || $old['recurrence_id'] || ($old && $old['id'] != $event['id']))) {
$event['id'] = $event['recurrence_id'] ?: ($old['recurrence_id'] ?: $old['id']);
$event = $this->driver->get_event($event, 0, true);
unset($event['_instance'], $event['recurrence_date']);
}
else {
// make sure we have the complete record
$event = $action == 'remove' ? $old : $this->driver->get_event($event, 0, true);
}
$event['_savemode'] = $_savemode;
if ($old) {
$old['thisandfuture'] = $_savemode == 'future';
}
// only notify if data really changed (TODO: do diff check on client already)
if (!$old || $action == 'remove' || self::event_diff($event, $old)) {
$sent = $this->notify_attendees($event, $old, $action, $event['_comment']);
if ($sent > 0)
$this->rc->output->show_message('calendar.itipsendsuccess', 'confirmation');
else if ($sent < 0)
$this->rc->output->show_message('calendar.errornotifying', 'error');
}
}
}
/**
* Handler for load-requests from fullcalendar
* This will return pure JSON formatted output
*/
function load_events()
{
$events = $this->driver->load_events(
rcube_utils::get_input_value('start', rcube_utils::INPUT_GET),
rcube_utils::get_input_value('end', rcube_utils::INPUT_GET),
($query = rcube_utils::get_input_value('q', rcube_utils::INPUT_GET)),
rcube_utils::get_input_value('source', rcube_utils::INPUT_GET)
);
echo $this->encode($events, !empty($query));
exit;
}
/**
* Handler for requests fetching event counts for calendars
*/
public function count_events()
{
// don't update session on these requests (avoiding race conditions)
$this->rc->session->nowrite = true;
$start = rcube_utils::get_input_value('start', rcube_utils::INPUT_GET);
if (!$start) {
$start = new DateTime('today 00:00:00', $this->timezone);
$start = $start->format('U');
}
$counts = $this->driver->count_events(
rcube_utils::get_input_value('source', rcube_utils::INPUT_GET),
$start,
rcube_utils::get_input_value('end', rcube_utils::INPUT_GET)
);
$this->rc->output->command('plugin.update_counts', array('counts' => $counts));
}
/**
* Load event data from an iTip message attachment
*/
public function itip_events($msgref)
{
$path = explode('/', $msgref);
$msg = array_pop($path);
$mbox = join('/', $path);
list($uid, $mime_id) = explode('#', $msg);
$events = array();
if ($event = $this->lib->mail_get_itip_object($mbox, $uid, $mime_id, 'event')) {
$partstat = 'NEEDS-ACTION';
/*
$user_emails = $this->lib->get_user_emails();
foreach ($event['attendees'] as $attendee) {
if (in_array($attendee['email'], $user_emails)) {
$partstat = $attendee['status'];
break;
}
}
*/
$event['id'] = $event['uid'];
$event['temporary'] = true;
$event['readonly'] = true;
$event['calendar'] = '--invitation--itip';
$event['className'] = 'fc-invitation-' . strtolower($partstat);
$event['_mbox'] = $mbox;
$event['_uid'] = $uid;
$event['_part'] = $mime_id;
$events[] = $this->_client_event($event, true);
// add recurring instances
if (!empty($event['recurrence'])) {
foreach ($this->driver->get_recurring_events($event, $event['start']) as $recurring) {
$recurring['temporary'] = true;
$recurring['readonly'] = true;
$recurring['calendar'] = '--invitation--itip';
$events[] = $this->_client_event($recurring, true);
}
}
}
return $events;
}
/**
* Handler for keep-alive requests
* This will check for updated data in active calendars and sync them to the client
*/
public function refresh($attr)
{
// refresh the entire calendar every 10th time to also sync deleted events
if (rand(0,10) == 10) {
$this->rc->output->command('plugin.refresh_calendar', array('refetch' => true));
return;
}
$counts = array();
foreach ($this->driver->list_calendars(calendar_driver::FILTER_ACTIVE) as $cal) {
$events = $this->driver->load_events(
rcube_utils::get_input_value('start', rcube_utils::INPUT_GPC),
rcube_utils::get_input_value('end', rcube_utils::INPUT_GPC),
rcube_utils::get_input_value('q', rcube_utils::INPUT_GPC),
$cal['id'],
1,
$attr['last']
);
foreach ($events as $event) {
$this->rc->output->command('plugin.refresh_calendar',
array('source' => $cal['id'], 'update' => $this->_client_event($event)));
}
// refresh count for this calendar
if ($cal['counts']) {
$today = new DateTime('today 00:00:00', $this->timezone);
$counts += $this->driver->count_events($cal['id'], $today->format('U'));
}
}
if (!empty($counts)) {
$this->rc->output->command('plugin.update_counts', array('counts' => $counts));
}
}
/**
* Handler for pending_alarms plugin hook triggered by the calendar module on keep-alive requests.
* This will check for pending notifications and pass them to the client
*/
public function pending_alarms($p)
{
$this->load_driver();
$time = $p['time'] ?: time();
if ($alarms = $this->driver->pending_alarms($time)) {
foreach ($alarms as $alarm) {
$alarm['id'] = 'cal:' . $alarm['id']; // prefix ID with cal:
$p['alarms'][] = $alarm;
}
}
// get alarms for birthdays calendar
if ($this->rc->config->get('calendar_contact_birthdays') && $this->rc->config->get('calendar_birthdays_alarm_type') == 'DISPLAY') {
$cache = $this->rc->get_cache('calendar.birthdayalarms', 'db');
foreach ($this->driver->load_birthday_events($time, $time + 86400 * 60) as $e) {
$alarm = libcalendaring::get_next_alarm($e);
// overwrite alarm time with snooze value (or null if dismissed)
if ($dismissed = $cache->get($e['id']))
$alarm['time'] = $dismissed['notifyat'];
// add to list if alarm is set
if ($alarm && $alarm['time'] && $alarm['time'] <= $time) {
$e['id'] = 'cal:bday:' . $e['id'];
$e['notifyat'] = $alarm['time'];
$p['alarms'][] = $e;
}
}
}
return $p;
}
/**
* Handler for alarm dismiss hook triggered by libcalendaring
*/
public function dismiss_alarms($p)
{
$this->load_driver();
foreach ((array)$p['ids'] as $id) {
if (strpos($id, 'cal:bday:') === 0) {
$p['success'] |= $this->driver->dismiss_birthday_alarm(substr($id, 9), $p['snooze']);
}
else if (strpos($id, 'cal:') === 0) {
$p['success'] |= $this->driver->dismiss_alarm(substr($id, 4), $p['snooze']);
}
}
return $p;
}
/**
* Handler for check-recent requests which are accidentally sent to calendar taks
*/
function check_recent()
{
// NOP
$this->rc->output->send();
}
/**
* Hook triggered when a contact is saved
*/
function contact_update($p)
{
// clear birthdays calendar cache
if (!empty($p['record']['birthday'])) {
$cache = $this->rc->get_cache('calendar.birthdays', 'db');
$cache->remove();
}
}
/**
*
*/
function import_events()
{
// Upload progress update
if (!empty($_GET['_progress'])) {
rcube_upload_progress();
}
@set_time_limit(0);
// process uploaded file if there is no error
$err = $_FILES['_data']['error'];
if (!$err && $_FILES['_data']['tmp_name']) {
$calendar = rcube_utils::get_input_value('calendar', rcube_utils::INPUT_GPC);
$rangestart = $_REQUEST['_range'] ? date_create("now -" . intval($_REQUEST['_range']) . " months") : 0;
// extract zip file
if ($_FILES['_data']['type'] == 'application/zip') {
$count = 0;
if (class_exists('ZipArchive', false)) {
$zip = new ZipArchive();
if ($zip->open($_FILES['_data']['tmp_name'])) {
$randname = uniqid('zip-' . session_id(), true);
$tmpdir = slashify($this->rc->config->get('temp_dir', sys_get_temp_dir())) . $randname;
mkdir($tmpdir, 0700);
// extract each ical file from the archive and import it
for ($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
if (preg_match('/\.ics$/i', $filename)) {
$tmpfile = $tmpdir . '/' . basename($filename);
if (copy('zip://' . $_FILES['_data']['tmp_name'] . '#'.$filename, $tmpfile)) {
$count += $this->import_from_file($tmpfile, $calendar, $rangestart, $errors);
unlink($tmpfile);
}
}
}
rmdir($tmpdir);
$zip->close();
}
else {
$errors = 1;
$msg = 'Failed to open zip file.';
}
}
else {
$errors = 1;
$msg = 'Zip files are not supported for import.';
}
}
else {
// attempt to import teh uploaded file directly
$count = $this->import_from_file($_FILES['_data']['tmp_name'], $calendar, $rangestart, $errors);
}
if ($count) {
$this->rc->output->command('display_message', $this->gettext(array('name' => 'importsuccess', 'vars' => array('nr' => $count))), 'confirmation');
$this->rc->output->command('plugin.import_success', array('source' => $calendar, 'refetch' => true));
}
else if (!$errors) {
$this->rc->output->command('display_message', $this->gettext('importnone'), 'notice');
$this->rc->output->command('plugin.import_success', array('source' => $calendar));
}
else {
$this->rc->output->command('plugin.import_error', array('message' => $this->gettext('importerror') . ($msg ? ': ' . $msg : '')));
}
}
else {
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
$msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array(
'size' => show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
}
else {
$msg = rcube_label('fileuploaderror');
}
$this->rc->output->command('plugin.import_error', array('message' => $msg));
}
$this->rc->output->send('iframe');
}
/**
* Helper function to parse and import a single .ics file
*/
private function import_from_file($filepath, $calendar, $rangestart, &$errors)
{
$user_email = $this->rc->user->get_username();
$ical = $this->get_ical();
$errors = !$ical->fopen($filepath);
$count = $i = 0;
foreach ($ical as $event) {
// keep the browser connection alive on long import jobs
if (++$i > 100 && $i % 100 == 0) {
echo "<!-- -->";
ob_flush();
}
// TODO: correctly handle recurring events which start before $rangestart
if ($event['end'] < $rangestart && (!$event['recurrence'] || ($event['recurrence']['until'] && $event['recurrence']['until'] < $rangestart)))
continue;
$event['_owner'] = $user_email;
$event['calendar'] = $calendar;
if ($this->driver->new_event($event)) {
$count++;
}
else {
$errors++;
}
}
return $count;
}
/**
* Construct the ics file for exporting events to iCalendar format;
*/
function export_events($terminate = true)
{
$start = rcube_utils::get_input_value('start', rcube_utils::INPUT_GET);
$end = rcube_utils::get_input_value('end', rcube_utils::INPUT_GET);
if (!isset($start))
$start = 'today -1 year';
if (!is_numeric($start))
$start = strtotime($start . ' 00:00:00');
if (!$end)
$end = 'today +10 years';
if (!is_numeric($end))
$end = strtotime($end . ' 23:59:59');
$event_id = rcube_utils::get_input_value('id', rcube_utils::INPUT_GET);
$attachments = rcube_utils::get_input_value('attachments', rcube_utils::INPUT_GET);
$calid = $filename = rcube_utils::get_input_value('source', rcube_utils::INPUT_GET);
$calendars = $this->driver->list_calendars();
$events = array();
if ($calendars[$calid]) {
$filename = $calendars[$calid]['name'] ? $calendars[$calid]['name'] : $calid;
$filename = asciiwords(html_entity_decode($filename)); // to 7bit ascii
if (!empty($event_id)) {
if ($event = $this->driver->get_event(array('calendar' => $calid, 'id' => $event_id), 0, true)) {
if ($event['recurrence_id']) {
$event = $this->driver->get_event(array('calendar' => $calid, 'id' => $event['recurrence_id']), 0, true);
}
$events = array($event);
$filename = asciiwords($event['title']);
if (empty($filename))
$filename = 'event';
}
}
else {
$events = $this->driver->load_events($start, $end, null, $calid, 0);
if (empty($filename))
$filename = $calid;
}
}
header("Content-Type: text/calendar");
header("Content-Disposition: inline; filename=".$filename.'.ics');
$this->get_ical()->export($events, '', true, $attachments ? array($this->driver, 'get_attachment_body') : null);
if ($terminate)
exit;
}
/**
* Handler for iCal feed requests
*/
function ical_feed_export()
{
$session_exists = !empty($_SESSION['user_id']);
// process HTTP auth info
if (!empty($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
$_POST['_user'] = $_SERVER['PHP_AUTH_USER']; // used for rcmail::autoselect_host()
$auth = $this->rc->plugins->exec_hook('authenticate', array(
'host' => $this->rc->autoselect_host(),
'user' => trim($_SERVER['PHP_AUTH_USER']),
'pass' => $_SERVER['PHP_AUTH_PW'],
'cookiecheck' => true,
'valid' => true,
));
if ($auth['valid'] && !$auth['abort'])
$this->rc->login($auth['user'], $auth['pass'], $auth['host']);
}
// require HTTP auth
if (empty($_SESSION['user_id'])) {
header('WWW-Authenticate: Basic realm="Roundcube Calendar"');
header('HTTP/1.0 401 Unauthorized');
exit;
}
// decode calendar feed hash
$format = 'ics';
$calhash = rcube_utils::get_input_value('_cal', rcube_utils::INPUT_GET);
if (preg_match(($suff_regex = '/\.([a-z0-9]{3,5})$/i'), $calhash, $m)) {
$format = strtolower($m[1]);
$calhash = preg_replace($suff_regex, '', $calhash);
}
if (!strpos($calhash, ':'))
$calhash = base64_decode($calhash);
list($user, $_GET['source']) = explode(':', $calhash, 2);
// sanity check user
if ($this->rc->user->get_username() == $user) {
$this->load_driver();
$this->export_events(false);
}
else {
header('HTTP/1.0 404 Not Found');
}
// don't save session data
if (!$session_exists)
session_destroy();
exit;
}
/**
*
*/
function load_settings()
{
$this->lib->load_settings();
$this->defaults += $this->lib->defaults;
$settings = array();
// configuration
$settings['default_calendar'] = $this->rc->config->get('calendar_default_calendar');
$settings['default_view'] = (string)$this->rc->config->get('calendar_default_view', $this->defaults['calendar_default_view']);
$settings['date_agenda'] = (string)$this->rc->config->get('calendar_date_agenda', $this->defaults['calendar_date_agenda']);
$settings['timeslots'] = (int)$this->rc->config->get('calendar_timeslots', $this->defaults['calendar_timeslots']);
$settings['first_day'] = (int)$this->rc->config->get('calendar_first_day', $this->defaults['calendar_first_day']);
$settings['first_hour'] = (int)$this->rc->config->get('calendar_first_hour', $this->defaults['calendar_first_hour']);
$settings['work_start'] = (int)$this->rc->config->get('calendar_work_start', $this->defaults['calendar_work_start']);
$settings['work_end'] = (int)$this->rc->config->get('calendar_work_end', $this->defaults['calendar_work_end']);
$settings['agenda_range'] = (int)$this->rc->config->get('calendar_agenda_range', $this->defaults['calendar_agenda_range']);
$settings['agenda_sections'] = $this->rc->config->get('calendar_agenda_sections', $this->defaults['calendar_agenda_sections']);
$settings['event_coloring'] = (int)$this->rc->config->get('calendar_event_coloring', $this->defaults['calendar_event_coloring']);
$settings['time_indicator'] = (int)$this->rc->config->get('calendar_time_indicator', $this->defaults['calendar_time_indicator']);
$settings['invite_shared'] = (int)$this->rc->config->get('calendar_allow_invite_shared', $this->defaults['calendar_allow_invite_shared']);
$settings['invitation_calendars'] = (bool)$this->rc->config->get('kolab_invitation_calendars', false);
$settings['itip_notify'] = (int)$this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']);
// get user identity to create default attendee
if ($this->ui->screen == 'calendar') {
foreach ($this->rc->user->list_emails() as $rec) {
if (!$identity)
$identity = $rec;
$identity['emails'][] = $rec['email'];
$settings['identities'][$rec['identity_id']] = $rec['email'];
}
$identity['emails'][] = $this->rc->user->get_username();
$settings['identity'] = array('name' => $identity['name'], 'email' => strtolower($identity['email']), 'emails' => ';' . strtolower(join(';', $identity['emails'])));
}
return $settings;
}
/**
* Encode events as JSON
*
* @param array Events as array
* @param boolean Add CSS class names according to calendar and categories
* @return string JSON encoded events
*/
function encode($events, $addcss = false)
{
$json = array();
foreach ($events as $event) {
$json[] = $this->_client_event($event, $addcss);
}
return json_encode($json);
}
/**
* Convert an event object to be used on the client
*/
private function _client_event($event, $addcss = false)
{
// compose a human readable strings for alarms_text and recurrence_text
if ($event['valarms']) {
$event['alarms_text'] = libcalendaring::alarms_text($event['valarms']);
$event['valarms'] = libcalendaring::to_client_alarms($event['valarms']);
}
if ($event['recurrence']) {
$event['recurrence_text'] = $this->lib->recurrence_text($event['recurrence']);
$event['recurrence'] = $this->lib->to_client_recurrence($event['recurrence'], $event['allday']);
unset($event['recurrence_date']);
}
foreach ((array)$event['attachments'] as $k => $attachment) {
$event['attachments'][$k]['classname'] = rcube_utils::file2class($attachment['mimetype'], $attachment['name']);
}
// 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;
}
}
}
// check for organizer in attendees list
$organizer = null;
foreach ((array)$event['attendees'] as $i => $attendee) {
if ($attendee['role'] == 'ORGANIZER') {
$organizer = $attendee;
}
if ($attendee['status'] == 'DELEGATED' && $attendee['rsvp'] == false) {
$event['attendees'][$i]['noreply'] = true;
}
else {
unset($event['attendees'][$i]['noreply']);
}
}
if ($organizer === null && !empty($event['organizer'])) {
$organizer = $event['organizer'];
$organizer['role'] = 'ORGANIZER';
if (!is_array($event['attendees']))
$event['attendees'] = array();
array_unshift($event['attendees'], $organizer);
}
// mapping url => vurl because of the fullcalendar client script
$event['vurl'] = $event['url'];
unset($event['url']);
return array(
'_id' => $event['calendar'] . ':' . $event['id'], // unique identifier for fullcalendar
'start' => $this->lib->adjust_timezone($event['start'], $event['allday'])->format('c'),
'end' => $this->lib->adjust_timezone($event['end'], $event['allday'])->format('c'),
// 'changed' might be empty for event recurrences (Bug #2185)
'changed' => $event['changed'] ? $this->lib->adjust_timezone($event['changed'])->format('c') : null,
'created' => $event['created'] ? $this->lib->adjust_timezone($event['created'])->format('c') : null,
'title' => strval($event['title']),
'description' => strval($event['description']),
'location' => strval($event['location']),
'className' => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') .
'fc-event-cat-' . asciiwords(strtolower(join('-', (array)$event['categories'])), true) .
rtrim(' ' . $event['className']),
'allDay' => ($event['allday'] == 1),
) + $event;
}
/**
* Generate a unique identifier for an event
*/
public function generate_uid()
{
return strtoupper(md5(time() . uniqid(rand())) . '-' . substr(md5($this->rc->user->get_username()), 0, 16));
}
/**
* TEMPORARY: generate random event data for testing
* Create events by opening http://<roundcubeurl>/?_task=calendar&_action=randomdata&_num=500&_date=2014-08-01&_dev=120
*/
public function generate_randomdata()
{
@set_time_limit(0);
$num = $_REQUEST['_num'] ? intval($_REQUEST['_num']) : 100;
$date = $_REQUEST['_date'] ?: 'now';
$dev = $_REQUEST['_dev'] ?: 30;
$cats = array_keys($this->driver->list_categories());
$cals = $this->driver->list_calendars(calendar_driver::FILTER_ACTIVE);
$count = 0;
while ($count++ < $num) {
$spread = intval($dev) * 86400; // days
$refdate = strtotime($date);
$start = round(($refdate + rand(-$spread, $spread)) / 600) * 600;
$duration = round(rand(30, 360) / 30) * 30 * 60;
$allday = rand(0,20) > 18;
$alarm = rand(-30,12) * 5;
$fb = rand(0,2);
if (date('G', $start) > 23)
$start -= 3600;
if ($allday) {
$start = strtotime(date('Y-m-d 00:00:00', $start));
$duration = 86399;
}
$title = '';
$len = rand(2, 12);
$words = explode(" ", "The Hough transform is named after Paul Hough who patented the method in 1962. It is a technique which can be used to isolate features of a particular shape within an image. Because it requires that the desired features be specified in some parametric form, the classical Hough transform is most commonly used for the de- tection of regular curves such as lines, circles, ellipses, etc. A generalized Hough transform can be employed in applications where a simple analytic description of a feature(s) is not possible. Due to the computational complexity of the generalized Hough algorithm, we restrict the main focus of this discussion to the classical Hough transform. Despite its domain restrictions, the classical Hough transform (hereafter referred to without the classical prefix ) retains many applications, as most manufac- tured parts (and many anatomical parts investigated in medical imagery) contain feature boundaries which can be described by regular curves. The main advantage of the Hough transform technique is that it is tolerant of gaps in feature boundary descriptions and is relatively unaffected by image noise.");
// $chars = "!# abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890";
for ($i = 0; $i < $len; $i++)
$title .= $words[rand(0,count($words)-1)] . " ";
$this->driver->new_event(array(
'uid' => $this->generate_uid(),
'start' => new DateTime('@'.$start),
'end' => new DateTime('@'.($start + $duration)),
'allday' => $allday,
'title' => rtrim($title),
'free_busy' => $fb == 2 ? 'outofoffice' : ($fb ? 'busy' : 'free'),
'categories' => $cats[array_rand($cats)],
'calendar' => array_rand($cals),
'alarms' => $alarm > 0 ? "-{$alarm}M:DISPLAY" : '',
'priority' => rand(0,9),
));
}
$this->rc->output->redirect('');
}
/**
* Handler for attachments upload
*/
public function attachment_upload()
{
$this->lib->attachment_upload(self::SESSION_KEY, 'cal-');
}
/**
* Handler for attachments download/displaying
*/
public function attachment_get()
{
// show loading page
if (!empty($_GET['_preload'])) {
return $this->lib->attachment_loading_page();
}
$event_id = rcube_utils::get_input_value('_event', rcube_utils::INPUT_GPC);
$calendar = rcube_utils::get_input_value('_cal', rcube_utils::INPUT_GPC);
$id = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
$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);
// show part page
if (!empty($_GET['_frame'])) {
$this->lib->attachment = $attachment;
$this->register_handler('plugin.attachmentframe', array($this->lib, 'attachment_frame'));
$this->register_handler('plugin.attachmentcontrols', array($this->lib, 'attachment_header'));
$this->rc->output->send('calendar.attachment');
}
// deliver attachment content
else if ($attachment) {
$attachment['body'] = $this->driver->get_attachment_body($id, $event);
$this->lib->attachment_get($attachment);
}
// if we arrive here, the requested part was not found
header('HTTP/1.1 404 Not Found');
exit;
}
/**
* Prepares new/edited event properties before save
*/
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['allday'] = (bool)$event['allday'];
// start/end is all we need for 'move' action (#1480)
if ($action == 'move') {
return;
}
// convert the submitted recurrence settings
if (is_array($event['recurrence'])) {
$event['recurrence'] = $this->lib->from_client_recurrence($event['recurrence'], $event['start']);
}
// convert the submitted alarm values
if ($event['valarms']) {
$event['valarms'] = libcalendaring::from_client_alarms($event['valarms']);
}
$attachments = array();
$eventid = 'cal-'.$event['id'];
if (is_array($_SESSION[self::SESSION_KEY]) && $_SESSION[self::SESSION_KEY]['id'] == $eventid) {
if (!empty($_SESSION[self::SESSION_KEY]['attachments'])) {
foreach ($_SESSION[self::SESSION_KEY]['attachments'] as $id => $attachment) {
if (is_array($event['attachments']) && in_array($id, $event['attachments'])) {
$attachments[$id] = $this->rc->plugins->exec_hook('attachment_get', $attachment);
}
}
}
}
$event['attachments'] = $attachments;
// convert link references into simple URIs
if (array_key_exists('links', $event)) {
$event['links'] = array_map(function($link) {
return is_array($link) ? $link['uri'] : strval($link);
}, (array)$event['links']);
}
// check for organizer in attendees
if ($action == 'new' || $action == 'edit') {
if (!$event['attendees'])
$event['attendees'] = array();
$emails = $this->get_user_emails();
$organizer = $owner = false;
foreach ((array)$event['attendees'] as $i => $attendee) {
if ($attendee['role'] == 'ORGANIZER')
$organizer = $i;
if ($attendee['email'] == in_array(strtolower($attendee['email']), $emails))
$owner = $i;
if (!isset($attendee['rsvp']))
$event['attendees'][$i]['rsvp'] = true;
else if (is_string($attendee['rsvp']))
$event['attendees'][$i]['rsvp'] = $attendee['rsvp'] == 'true' || $attendee['rsvp'] == '1';
}
// set new organizer identity
if ($organizer !== false && !empty($event['_identity']) && ($identity = $this->rc->user->get_identity($event['_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) {
$event['attendees'][$owner]['role'] = 'ORGANIZER';
unset($event['attendees'][$owner]['rsvp']);
}
}
// mapping url => vurl because of the fullcalendar client script
if (array_key_exists('vurl', $event)) {
$event['url'] = $event['vurl'];
unset($event['vurl']);
}
}
/**
* Releases some resources after successful event save
*/
private function cleanup_event(&$event)
{
// remove temp. attachment files
if (!empty($_SESSION[self::SESSION_KEY]) && ($eventid = $_SESSION[self::SESSION_KEY]['id'])) {
$this->rc->plugins->exec_hook('attachments_cleanup', array('group' => $eventid));
$this->rc->session->remove(self::SESSION_KEY);
}
}
/**
* Send out an invitation/notification to all event attendees
*/
private function notify_attendees($event, $old, $action = 'edit', $comment = null)
{
if ($action == 'remove' || ($event['status'] == 'CANCELLED' && $old['status'] != $event['status'])) {
$event['cancelled'] = true;
$is_cancelled = true;
}
$itip = $this->load_itip();
$emails = $this->get_user_emails();
$itip_notify = (int)$this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']);
// add comment to the iTip attachment
$event['comment'] = $comment;
// set a valid recurrence-id if this is a recurrence instance
libcalendaring::identify_recurrence_instance($event);
// compose multipart message using PEAR:Mail_Mime
$method = $action == 'remove' ? 'CANCEL' : 'REQUEST';
$message = $itip->compose_itip_message($event, $method, !$old || $event['sequence'] > $old['sequence']);
// list existing attendees from $old event
$old_attendees = array();
foreach ((array)$old['attendees'] as $attendee) {
$old_attendees[] = $attendee['email'];
}
// send to every attendee
$sent = 0; $current = array();
foreach ((array)$event['attendees'] as $attendee) {
$current[] = strtolower($attendee['email']);
// skip myself for obvious reasons
if (!$attendee['email'] || in_array(strtolower($attendee['email']), $emails))
continue;
// skip if notification is disabled for this attendee
if ($attendee['noreply'] && $itip_notify & 2)
continue;
// skip if this attendee has delegated and set RSVP=FALSE
if ($attendee['status'] == 'DELEGATED' && $attendee['rsvp'] === false)
continue;
// which template to use for mail text
$is_new = !in_array($attendee['email'], $old_attendees);
$is_rsvp = $is_new || $event['sequence'] > $old['sequence'];
$bodytext = $is_cancelled ? 'eventcancelmailbody' : ($is_new ? 'invitationmailbody' : 'eventupdatemailbody');
$subject = $is_cancelled ? 'eventcancelsubject' : ($is_new ? 'invitationsubject' : ($event['title'] ? 'eventupdatesubject':'eventupdatesubjectempty'));
$event['comment'] = $comment;
// finally send the message
if ($itip->send_itip_message($event, $method, $attendee, $subject, $bodytext, $message, $is_rsvp))
$sent++;
else
$sent = -100;
}
// TODO: on change of a recurring (main) event, also send updates to differing attendess of recurrence exceptions
// send CANCEL message to removed attendees
foreach ((array)$old['attendees'] as $attendee) {
if ($attendee['role'] == 'ORGANIZER' || !$attendee['email'] || in_array(strtolower($attendee['email']), $current))
continue;
$vevent = $old;
$vevent['cancelled'] = $is_cancelled;
$vevent['attendees'] = array($attendee);
$vevent['comment'] = $comment;
if ($itip->send_itip_message($vevent, 'CANCEL', $attendee, 'eventcancelsubject', 'eventcancelmailbody'))
$sent++;
else
$sent = -100;
}
return $sent;
}
/**
* Echo simple free/busy status text for the given user and time range
*/
public function freebusy_status()
{
$email = rcube_utils::get_input_value('email', rcube_utils::INPUT_GPC);
$start = rcube_utils::get_input_value('start', rcube_utils::INPUT_GPC);
$end = rcube_utils::get_input_value('end', rcube_utils::INPUT_GPC);
// convert dates into unix timestamps
if (!empty($start) && !is_numeric($start)) {
$dts = new DateTime($start, $this->timezone);
$start = $dts->format('U');
}
if (!empty($end) && !is_numeric($end)) {
$dte = new DateTime($end, $this->timezone);
$end = $dte->format('U');
}
if (!$start) $start = time();
if (!$end) $end = $start + 3600;
$fbtypemap = array(calendar::FREEBUSY_UNKNOWN => 'UNKNOWN', calendar::FREEBUSY_FREE => 'FREE', calendar::FREEBUSY_BUSY => 'BUSY', calendar::FREEBUSY_TENTATIVE => 'TENTATIVE', calendar::FREEBUSY_OOF => 'OUT-OF-OFFICE');
$status = 'UNKNOWN';
// if the backend has free-busy information
$fblist = $this->driver->get_freebusy_list($email, $start, $end);
if (is_array($fblist)) {
$status = 'FREE';
foreach ($fblist as $slot) {
list($from, $to, $type) = $slot;
if ($from < $end && $to > $start) {
$status = isset($type) && $fbtypemap[$type] ? $fbtypemap[$type] : 'BUSY';
break;
}
}
}
// let this information be cached for 5min
send_future_expire_header(300);
echo $status;
exit;
}
/**
* Return a list of free/busy time slots within the given period
* Echo data in JSON encoding
*/
public function freebusy_times()
{
$email = rcube_utils::get_input_value('email', rcube_utils::INPUT_GPC);
$start = rcube_utils::get_input_value('start', rcube_utils::INPUT_GPC);
$end = rcube_utils::get_input_value('end', rcube_utils::INPUT_GPC);
$interval = intval(rcube_utils::get_input_value('interval', rcube_utils::INPUT_GPC));
$strformat = $interval > 60 ? 'Ymd' : 'YmdHis';
// convert dates into unix timestamps
if (!empty($start) && !is_numeric($start)) {
$dts = rcube_utils::anytodatetime($start, $this->timezone);
$start = $dts ? $dts->format('U') : null;
}
if (!empty($end) && !is_numeric($end)) {
$dte = rcube_utils::anytodatetime($end, $this->timezone);
$end = $dte ? $dte->format('U') : null;
}
if (!$start) $start = time();
if (!$end) $end = $start + 86400 * 30;
if (!$interval) $interval = 60; // 1 hour
if (!$dte) {
$dts = new DateTime('@'.$start);
$dts->setTimezone($this->timezone);
}
$fblist = $this->driver->get_freebusy_list($email, $start, $end);
$slots = array();
// 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);
// 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 :-)
break;
}
}
}
$slots[$s] = $status;
$times[$s] = intval($dt->format($strformat));
$t = $t_end;
}
$dte = new DateTime('@'.$t_end);
$dte->setTimezone($this->timezone);
// let this information be cached for 5min
send_future_expire_header(300);
echo json_encode(array(
'email' => $email,
'start' => $dts->format('c'),
'end' => $dte->format('c'),
'interval' => $interval,
'slots' => $slots,
'times' => $times,
));
exit;
}
/**
* Handler for printing calendars
*/
public function print_view()
{
$title = $this->gettext('print');
$view = rcube_utils::get_input_value('view', rcube_utils::INPUT_GPC);
if (!in_array($view, array('agendaWeek', 'agendaDay', 'month', 'table')))
$view = 'agendaDay';
$this->rc->output->set_env('view',$view);
if ($date = rcube_utils::get_input_value('date', rcube_utils::INPUT_GPC))
$this->rc->output->set_env('date', $date);
if ($range = rcube_utils::get_input_value('range', rcube_utils::INPUT_GPC))
$this->rc->output->set_env('listRange', intval($range));
if (isset($_REQUEST['sections']))
$this->rc->output->set_env('listSections', rcube_utils::get_input_value('sections', rcube_utils::INPUT_GPC));
if ($search = rcube_utils::get_input_value('search', rcube_utils::INPUT_GPC)) {
$this->rc->output->set_env('search', $search);
$title .= ' "' . $search . '"';
}
// Add CSS stylesheets to the page header
$skin_path = $this->local_skin_path();
$this->include_stylesheet($skin_path . '/fullcalendar.css');
$this->include_stylesheet($skin_path . '/print.css');
// Add JS files to the page header
$this->include_script('print.js');
$this->include_script('lib/js/fullcalendar.js');
$this->register_handler('plugin.calendar_css', array($this->ui, 'calendar_css'));
$this->register_handler('plugin.calendar_list', array($this->ui, 'calendar_list'));
$this->rc->output->set_pagetitle($title);
$this->rc->output->send("calendar.print");
}
/**
*
*/
public function get_inline_ui()
{
foreach (array('save','cancel','savingdata') as $label)
$texts['calendar.'.$label] = $this->gettext($label);
$texts['calendar.new_event'] = $this->gettext('createfrommail');
$this->ui->init_templates();
$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('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"
);
exit;
}
/**
* Compare two event objects and return differing properties
*
* @param array Event A
* @param array Event B
* @return array List of differing event properties
*/
public static function event_diff($a, $b)
{
$diff = array();
$ignore = array('changed' => 1, 'attachments' => 1);
foreach (array_unique(array_merge(array_keys($a), array_keys($b))) as $key) {
if (!$ignore[$key] && $key[0] != '_' && $a[$key] != $b[$key])
$diff[] = $key;
}
// only compare number of attachments
if (count($a['attachments']) != count($b['attachments']))
$diff[] = 'attachments';
return $diff;
}
/**
* Update attendee properties on the given event object
*
* @param array The event object to be altered
* @param array List of hash arrays each represeting an updated/added attendee
*/
public static function merge_attendee_data(&$event, $attendees, $removed = null)
{
if (!empty($attendees) && !is_array($attendees[0])) {
$attendees = array($attendees);
}
foreach ($attendees as $attendee) {
$found = false;
foreach ($event['attendees'] as $i => $candidate) {
if ($candidate['email'] == $attendee['email']) {
$event['attendees'][$i] = $attendee;
$found = true;
break;
}
}
if (!$found) {
$event['attendees'][] = $attendee;
}
}
// filter out removed attendees
if (!empty($removed)) {
$event['attendees'] = array_filter($event['attendees'], function($attendee) use ($removed) {
return !in_array($attendee['email'], $removed);
});
}
}
/**** Resource management functions ****/
/**
* Getter for the configured implementation of the resource directory interface
*/
private function resources_directory()
{
if (is_object($this->resources_dir)) {
return $this->resources_dir;
}
if ($driver_name = $this->rc->config->get('calendar_resources_driver')) {
$driver_class = 'resources_driver_' . $driver_name;
require_once($this->home . '/drivers/resources_driver.php');
require_once($this->home . '/drivers/' . $driver_name . '/' . $driver_class . '.php');
$this->resources_dir = new $driver_class($this);
}
return $this->resources_dir;
}
/**
* Handler for resoruce autocompletion requests
*/
public function resources_autocomplete()
{
$search = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC, true);
$sid = rcube_utils::get_input_value('_reqid', rcube_utils::INPUT_GPC);
$maxnum = (int)$this->rc->config->get('autocomplete_max', 15);
$results = array();
if ($directory = $this->resources_directory()) {
foreach ($directory->load_resources($search, $maxnum) as $rec) {
$results[] = array(
'name' => $rec['name'],
'email' => $rec['email'],
'type' => $rec['_type'],
);
}
}
$this->rc->output->command('ksearch_query_results', $results, $search, $sid);
$this->rc->output->send();
}
/**
* Handler for load-requests for resource data
*/
function resources_list()
{
$data = array();
if ($directory = $this->resources_directory()) {
foreach ($directory->load_resources() as $rec) {
$data[] = $rec;
}
}
$this->rc->output->command('plugin.resource_data', $data);
$this->rc->output->send();
}
/**
* Handler for requests loading resource owner information
*/
function resources_owner()
{
if ($directory = $this->resources_directory()) {
$id = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
$data = $directory->get_resource_owner($id);
}
$this->rc->output->command('plugin.resource_owner', $data);
$this->rc->output->send();
}
/**
* Deliver event data for a resource's calendar
*/
function resources_calendar()
{
$events = array();
if ($directory = $this->resources_directory()) {
$events = $directory->get_resource_calendar(
rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC),
rcube_utils::get_input_value('start', rcube_utils::INPUT_GET),
rcube_utils::get_input_value('end', rcube_utils::INPUT_GET));
}
echo $this->encode($events);
exit;
}
/**** Event invitation plugin hooks ****/
/**
* Handler for calendar/itip-status requests
*/
function event_itip_status()
{
$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);
// 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);
$calendar_select = new html_select(array('name' => 'calendar', 'id' => 'itip-saveto', 'is_escaped' => true));
$calendar_select->add('--', '');
$numcals = 0;
foreach ($calendars as $calendar) {
if ($calendar['editable']) {
$calendar_select->add($calendar['name'], $calendar['id']);
$numcals++;
}
}
if ($numcals <= 1)
$calendar_select = null;
}
if ($calendar_select) {
$default_calendar = $this->get_default_calendar(true, $data['sensitivity'] == 'confidential');
$response['select'] = html::span('folder-select', $this->gettext('saveincalendar') . '&nbsp;' .
$calendar_select->show($default_calendar['id']));
}
else if ($data['nosave']) {
$response['select'] = html::tag('input', array('type' => 'hidden', 'name' => 'calendar', 'id' => 'itip-saveto', 'value' => ''));
}
// render small agenda view for the respective day
if ($data['method'] == 'REQUEST' && !empty($data['date']) && $response['action'] == 'rsvp') {
$event_start = rcube_utils::anytodatetime($data['date']);
$day_start = new Datetime(gmdate('Y-m-d 00:00', $data['date']), $this->lib->timezone);
$day_end = new Datetime(gmdate('Y-m-d 23:59', $data['date']), $this->lib->timezone);
// get events on that day from the user's personal calendars
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL);
$events = $this->driver->load_events($day_start->format('U'), $day_end->format('U'), null, array_keys($calendars));
usort($events, function($a, $b) { return $a['start'] > $b['start'] ? 1 : -1; });
$before = $after = array();
foreach ($events as $event) {
// TODO: skip events with free_busy == 'free' ?
if ($event['uid'] == $data['uid'] || $event['end'] < $day_start || $event['start'] > $day_end)
continue;
else if ($event['start'] < $event_start)
$before[] = $this->mail_agenda_event_row($event);
else
$after[] = $this->mail_agenda_event_row($event);
}
$response['append'] = array(
'selector' => '.calendar-agenda-preview',
'replacements' => array(
'%before%' => !empty($before) ? join("\n", array_slice($before, -3)) : html::div('event-row no-event', $this->gettext('noearlierevents')),
'%after%' => !empty($after) ? join("\n", array_slice($after, 0, 3)) : html::div('event-row no-event', $this->gettext('nolaterevents')),
),
);
}
$this->rc->output->command('plugin.update_itip_object_status', $response);
}
/**
* Handler for calendar/itip-remove requests
*/
function event_itip_remove()
{
$success = false;
$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);
// search for event if only UID is given
if ($event = $this->driver->get_event(array('uid' => $uid, '_instance' => $instance), calendar_driver::FILTER_WRITEABLE)) {
$event['_savemode'] = $savemode;
$success = $this->driver->remove_event($event, true);
}
if ($success) {
$this->rc->output->show_message('calendar.successremoval', 'confirmation');
}
else {
$this->rc->output->show_message('calendar.errorsaving', 'error');
}
}
/**
* Handler for URLs that allow an invitee to respond on his invitation mail
*/
public function itip_attend_response($p)
{
if ($p['action'] == 'attend') {
$this->ui->init();
$this->rc->output->set_env('task', 'calendar'); // override some env vars
$this->rc->output->set_env('refresh_interval', 0);
$this->rc->output->set_pagetitle($this->gettext('calendar'));
$itip = $this->load_itip();
$token = rcube_utils::get_input_value('_t', rcube_utils::INPUT_GPC);
// read event info stored under the given token
if ($invitation = $itip->get_invitation($token)) {
$this->token = $token;
$this->event = $invitation['event'];
// show message about cancellation
if ($invitation['cancelled']) {
$this->invitestatus = html::div('rsvp-status declined', $itip->gettext('eventcancelled'));
}
// save submitted RSVP status
else if (!empty($_POST['rsvp'])) {
$status = null;
foreach (array('accepted','tentative','declined') as $method) {
if ($_POST['rsvp'] == $itip->gettext('itip' . $method)) {
$status = $method;
break;
}
}
// send itip reply to organizer
$invitation['event']['comment'] = rcube_utils::get_input_value('_comment', rcube_utils::INPUT_POST);
if ($status && $itip->update_invitation($invitation, $invitation['attendee'], strtoupper($status))) {
$this->invitestatus = html::div('rsvp-status ' . strtolower($status), $itip->gettext('youhave'.strtolower($status)));
}
else
$this->rc->output->command('display_message', $this->gettext('errorsaving'), 'error', -1);
// if user is logged in...
if ($this->rc->user->ID) {
$this->load_driver();
$invitation = $itip->get_invitation($token);
// save the event to his/her default calendar if not yet present
if (!$this->driver->get_event($this->event) && ($calendar = $this->get_default_calendar(true, $invitation['event']['sensitivity'] == 'confidential'))) {
$invitation['event']['calendar'] = $calendar['id'];
if ($this->driver->new_event($invitation['event']))
$this->rc->output->command('display_message', $this->gettext(array('name' => 'importedsuccessfully', 'vars' => array('calendar' => $calendar['name']))), 'confirmation');
}
}
}
$this->register_handler('plugin.event_inviteform', array($this, 'itip_event_inviteform'));
$this->register_handler('plugin.event_invitebox', array($this->ui, 'event_invitebox'));
if (!$this->invitestatus) {
$this->itip->set_rsvp_actions(array('accepted','tentative','declined'));
$this->register_handler('plugin.event_rsvp_buttons', array($this->ui, 'event_rsvp_buttons'));
}
$this->rc->output->set_pagetitle($itip->gettext('itipinvitation') . ' ' . $this->event['title']);
}
else
$this->rc->output->command('display_message', $this->gettext('itipinvalidrequest'), 'error', -1);
$this->rc->output->send('calendar.itipattend');
}
}
/**
*
*/
public function itip_event_inviteform($attrib)
{
$hidden = new html_hiddenfield(array('name' => "_t", 'value' => $this->token));
return html::tag('form', array('action' => $this->rc->url(array('task' => 'calendar', 'action' => 'attend')), 'method' => 'post', 'noclose' => true) + $attrib) . $hidden->show();
}
/**
*
*/
private function mail_agenda_event_row($event, $class = '')
{
$time = $event['allday'] ? $this->gettext('all-day') :
$this->rc->format_date($event['start'], $this->rc->config->get('time_format')) . ' - ' .
$this->rc->format_date($event['end'], $this->rc->config->get('time_format'));
return html::div(rtrim('event-row ' . $class),
html::span('event-date', $time) .
html::span('event-title', Q($event['title']))
);
}
/**
*
*/
public function mail_messages_list($p)
{
if (in_array('attachment', (array)$p['cols']) && !empty($p['messages'])) {
foreach ($p['messages'] as $header) {
$part = new StdClass;
$part->mimetype = $header->ctype;
if (libcalendaring::part_is_vcalendar($part)) {
$header->list_flags['attachmentClass'] = 'ical';
}
else if (in_array($header->ctype, array('multipart/alternative', 'multipart/mixed'))) {
// TODO: fetch bodystructure and search for ical parts. Maybe too expensive?
if (!empty($header->structure) && is_array($header->structure->parts)) {
foreach ($header->structure->parts as $part) {
if (libcalendaring::part_is_vcalendar($part) && !empty($part->ctype_parameters['method'])) {
$header->list_flags['attachmentClass'] = 'ical';
break;
}
}
}
}
}
}
}
/**
* Add UI element to copy event invitations or updates to the calendar
*/
public function mail_messagebody_html($p)
{
// load iCalendar functions (if necessary)
if (!empty($this->lib->ical_parts)) {
$this->get_ical();
$this->load_itip();
}
$html = '';
$has_events = false;
$ical_objects = $this->lib->get_mail_ical_objects();
// show a box for every event in the file
foreach ($ical_objects as $idx => $event) {
if ($event['_type'] != 'event') // skip non-event objects (#2928)
continue;
$has_events = true;
// get prepared inline UI for this event object
if ($ical_objects->method) {
$append = '';
// prepare a small agenda preview to be filled with actual event data on async request
if ($ical_objects->method == 'REQUEST') {
$append = html::div('calendar-agenda-preview',
html::tag('h3', 'preview-title', $this->gettext('agenda') . ' ' .
html::span('date', $this->rc->format_date($event['start'], $this->rc->config->get('date_format')))
) . '%before%' . $this->mail_agenda_event_row($event, 'current') . '%after%');
}
$html .= html::div('calendar-invitebox',
$this->itip->mail_itip_inline_ui(
$event,
$ical_objects->method,
$ical_objects->mime_id . ':' . $idx,
'calendar',
rcube_utils::anytodatetime($ical_objects->message_date),
$this->rc->url(array('task' => 'calendar')) . '&view=agendaDay&date=' . $event['start']->format('U')
) . $append
);
}
// limit listing
if ($idx >= 3)
break;
}
// prepend event boxes to message body
if ($html) {
$this->ui->init();
$p['content'] = $html . $p['content'];
$this->rc->output->add_label('calendar.savingdata','calendar.deleteventconfirm','calendar.declinedeleteconfirm');
}
// add "Save to calendar" button into attachment menu
if ($has_events) {
$this->add_button(array(
'id' => 'attachmentsavecal',
'name' => 'attachmentsavecal',
'type' => 'link',
'wrapper' => 'li',
'command' => 'attachment-save-calendar',
'class' => 'icon calendarlink',
'classact' => 'icon calendarlink active',
'innerclass' => 'icon calendar',
'label' => 'calendar.savetocalendar',
), 'attachmentmenu');
}
return $p;
}
/**
* Handler for POST request to import an event attached to a mail message
*/
public function mail_import_itip()
{
$itip_sending = $this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']);
$uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST);
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST);
$mime_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_POST);
$status = rcube_utils::get_input_value('_status', rcube_utils::INPUT_POST);
$delete = intval(rcube_utils::get_input_value('_del', rcube_utils::INPUT_POST));
$noreply = intval(rcube_utils::get_input_value('_noreply', rcube_utils::INPUT_POST));
$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);
$error_msg = $this->gettext('errorimportingevent');
$success = false;
$delegate = null;
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');
return;
}
}
// successfully parsed events?
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));
$itip = $this->load_itip();
if ($itip->delegate_to($event, $delegate, $rsvpme ? true : false)) {
$this->rc->output->show_message('calendar.itipsendsuccess', 'confirmation');
}
else {
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
}
// the delegator is set to non-participant, thus save as non-blocking
$event['free_busy'] = 'free';
}
// 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];
// select default calendar except user explicitly selected 'none'
if (!$calendar && !$dontsave)
$calendar = $this->get_default_calendar(true, $event['sensitivity'] == 'confidential');
$metadata = array(
'uid' => $event['uid'],
'_instance' => $event['_instance'],
'changed' => is_object($event['changed']) ? $event['changed']->format('U') : 0,
'sequence' => intval($event['sequence']),
'fallback' => strtoupper($status),
'method' => $event['_method'],
'task' => 'calendar',
);
// update my attendee status according to submitted method
if (!empty($status)) {
$organizer = null;
$emails = $this->get_user_emails();
foreach ($event['attendees'] as $i => $attendee) {
if ($attendee['role'] == 'ORGANIZER') {
$organizer = $attendee;
}
else if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) {
$event['attendees'][$i]['status'] = strtoupper($status);
if (!in_array($event['attendees'][$i]['status'], array('NEEDS-ACTION','DELEGATED')))
$event['attendees'][$i]['rsvp'] = false; // unset RSVP attribute
$metadata['attendee'] = $attendee['email'];
$metadata['rsvp'] = $attendee['role'] != 'NON-PARTICIPANT';
$reply_sender = $attendee['email'];
$event_attendee = $attendee;
}
}
// add attendee with this user's default identity if not listed
if (!$reply_sender) {
$sender_identity = $this->rc->user->list_emails(true);
$event['attendees'][] = array(
'name' => $sender_identity['name'],
'email' => $sender_identity['email'],
'role' => 'OPT-PARTICIPANT',
'status' => strtoupper($status),
);
$metadata['attendee'] = $sender_identity['email'];
}
}
// 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);
if ($existing) {
// forward savemode for correct updates of recurring events
$existing['_savemode'] = $savemode ?: $event['_savemode'];
// only update attendee status
if ($event['_method'] == 'REPLY') {
// try to identify the attendee using the email sender address
$existing_attendee = -1;
$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'])) {
$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'])) {
$event_attendee = $attendee;
$update_attendees[] = $attendee;
$metadata['fallback'] = $attendee['status'];
$metadata['attendee'] = $attendee['email'];
$metadata['rsvp'] = $attendee['rsvp'] || $attendee['role'] != 'NON-PARTICIPANT';
if ($attendee['status'] != 'DELEGATED') {
break;
}
}
// 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)) {
$update_attendees[] = $attendee;
if (!in_array($attendee['email'], $existing_attendee_emails)) {
$existing['attendees'][] = $attendee;
}
}
}
// if delegatee has declined, set delegator's RSVP=True
if ($event_attendee && $event_attendee['status'] == 'DECLINED' && $event_attendee['delegated-from']) {
foreach ($existing['attendees'] as $i => $attendee) {
if ($attendee['email'] == $event_attendee['delegated-from']) {
$existing['attendees'][$i]['rsvp'] = true;
break;
}
}
}
// found matching attendee entry in both existing and new events
if ($existing_attendee >= 0 && $event_attendee) {
$existing['attendees'][$existing_attendee] = $event_attendee;
$success = $this->driver->update_attendees($existing, $update_attendees);
}
// update the entire attendees block
else if (($event['sequence'] >= $existing['sequence'] || $event['changed'] >= $existing['changed']) && $event_attendee) {
$existing['attendees'][] = $event_attendee;
$success = $this->driver->update_attendees($existing, $update_attendees);
}
else {
$error_msg = $this->gettext('newerversionexists');
}
}
// delete the event when declined (#1670)
else if ($status == 'declined' && $delete) {
$deleted = $this->driver->remove_event($existing, true);
$success = true;
}
// import the (newer) event
else if ($event['sequence'] >= $existing['sequence'] || $event['changed'] >= $existing['changed']) {
$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;
}
}
}
}
}
// set status=CANCELLED on CANCEL messages
if ($event['_method'] == 'CANCEL')
$event['status'] = 'CANCELLED';
// show me as free when declined (#1670)
if ($status == 'declined' || $event['status'] == 'CANCELLED' || $event_attendee['role'] == 'NON-PARTICIPANT')
$event['free_busy'] = 'free';
$success = $this->driver->edit_event($event);
}
else if (!empty($status)) {
$existing['attendees'] = $event['attendees'];
if ($status == 'declined' || $event_attendee['role'] == 'NON-PARTICIPANT') // show me as free when declined (#1670)
$existing['free_busy'] = 'free';
$success = $this->driver->edit_event($existing);
}
else
$error_msg = $this->gettext('newerversionexists');
}
else if (!$existing && ($status != 'declined' || $this->rc->config->get('kolab_invitation_calendars'))) {
if ($status == 'declined' || $event['status'] == 'CANCELLED' || $event_attendee['role'] == 'NON-PARTICIPANT') {
$event['free_busy'] = 'free';
}
// if the RSVP reply only refers to a single instance:
// store unmodified master event with current instance as exception
if (!empty($instance) && !empty($savemode) && $savemode != 'all') {
$master = $this->lib->mail_get_itip_object($mbox, $uid, $mime_id, 'event');
if ($master['recurrence'] && !$master['_instance']) {
// compute recurring events until this instance's date
if ($recurrence_date = rcube_utils::anytodatetime($instance, $master['start']->getTimezone())) {
$recurrence_date->setTime(23,59,59);
foreach ($this->driver->get_recurring_events($master, $master['start'], $recurrence_date) as $recurring) {
if ($recurring['_instance'] == $instance) {
// copy attendees block with my partstat to exception
$recurring['attendees'] = $event['attendees'];
$master['recurrence']['EXCEPTIONS'][] = $recurring;
$event = $recurring; // set reference for iTip reply
break;
}
}
$master['calendar'] = $event['calendar'] = $calendar['id'];
$success = $this->driver->new_event($master);
}
else {
$master = null;
}
}
else {
$master = null;
}
}
// save to the selected/default calendar
if (!$master) {
$event['calendar'] = $calendar['id'];
$success = $this->driver->new_event($event);
}
}
else if ($status == 'declined')
$error_msg = null;
}
else if ($status == 'declined' || $dontsave)
$error_msg = null;
else
$error_msg = $this->gettext('nowritecalendarfound');
}
if ($success) {
$message = $event['_method'] == 'REPLY' ? 'attendeupdateesuccess' : ($deleted ? 'successremoval' : ($existing ? 'updatedsuccessfully' : 'importedsuccessfully'));
$this->rc->output->command('display_message', $this->gettext(array('name' => $message, 'vars' => array('calendar' => $calendar['name']))), 'confirmation');
}
if ($success || $dontsave) {
$metadata['calendar'] = $event['calendar'];
$metadata['nosave'] = $dontsave;
$metadata['rsvp'] = intval($metadata['rsvp']);
$metadata['after_action'] = $this->rc->config->get('calendar_itip_after_action', $this->defaults['calendar_itip_after_action']);
$this->rc->output->command('plugin.itip_message_processed', $metadata);
$error_msg = null;
}
else if ($error_msg) {
$this->rc->output->command('display_message', $error_msg, 'error');
}
// 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);
$itip = $this->load_itip();
$itip->set_sender_email($reply_sender);
if ($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');
else
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
}
$this->rc->output->send();
}
/**
* Handler for calendar/itip-remove requests
*/
function mail_itip_decline_reply()
{
$uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST);
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST);
$mime_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_POST);
if (($event = $this->lib->mail_get_itip_object($mbox, $uid, $mime_id, 'event')) && $event['_method'] == 'REPLY') {
$event['comment'] = rcube_utils::get_input_value('_comment', rcube_utils::INPUT_POST);
foreach ($event['attendees'] as $_attendee) {
if ($_attendee['role'] != 'ORGANIZER') {
$attendee = $_attendee;
break;
}
}
$itip = $this->load_itip();
if ($itip->send_itip_message($event, 'CANCEL', $attendee, 'itipsubjectcancel', 'itipmailbodycancel'))
$this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $attendee['name'] ? $attendee['name'] : $attendee['email']))), 'confirmation');
else
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
}
else {
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
}
}
/**
* Handler for calendar/itip-delegate requests
*/
function mail_itip_delegate()
{
// forward request to mail_import_itip() with the right status
$_POST['_status'] = $_REQUEST['_status'] = 'delegated';
$this->mail_import_itip();
}
/**
* Import the full payload from a mail message attachment
*/
public function mail_import_attachment()
{
$uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST);
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST);
$mime_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_POST);
$charset = RCMAIL_CHARSET;
// establish imap connection
$imap = $this->rc->get_storage();
$imap->set_mailbox($mbox);
if ($uid && $mime_id) {
$part = $imap->get_message_part($uid, $mime_id);
if ($part->ctype_parameters['charset'])
$charset = $part->ctype_parameters['charset'];
// $headers = $imap->get_message_headers($uid);
if ($part) {
$events = $this->get_ical()->import($part, $charset);
}
}
$success = $existing = 0;
if (!empty($events)) {
// find writeable calendar to store event
$cal_id = !empty($_REQUEST['_calendar']) ? rcube_utils::get_input_value('_calendar', rcube_utils::INPUT_POST) : null;
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL);
foreach ($events as $event) {
// save to calendar
$calendar = $calendars[$cal_id] ?: $this->get_default_calendar(true, $event['sensitivity'] == 'confidential');
if ($calendar && $calendar['editable'] && $event['_type'] == 'event') {
$event['calendar'] = $calendar['id'];
if (!$this->driver->get_event($event['uid'], calendar_driver::FILTER_WRITEABLE)) {
$success += (bool)$this->driver->new_event($event);
}
else {
$existing++;
}
}
}
}
if ($success) {
$this->rc->output->command('display_message', $this->gettext(array(
'name' => 'importsuccess',
'vars' => array('nr' => $success),
)), 'confirmation');
}
else if ($existing) {
$this->rc->output->command('display_message', $this->gettext('importwarningexists'), 'warning');
}
else {
$this->rc->output->command('display_message', $this->gettext('errorimportingevent'), 'error');
}
}
/**
* Read email message and return contents for a new event based on that message
*/
public function mail_message2event()
{
$uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST);
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST);
$event = array();
// establish imap connection
$imap = $this->rc->get_storage();
$imap->set_mailbox($mbox);
$message = new rcube_message($uid);
if ($message->headers) {
$event['title'] = trim($message->subject);
$event['description'] = trim($message->first_text_part());
$this->load_driver();
// add a reference to the email message
if ($msgref = $this->driver->get_message_reference($message->headers, $mbox)) {
$event['links'] = array($msgref);
}
// copy mail attachments to event
else if ($message->attachments) {
$eventid = 'cal-';
if (!is_array($_SESSION[self::SESSION_KEY]) || $_SESSION[self::SESSION_KEY]['id'] != $eventid) {
$_SESSION[self::SESSION_KEY] = array();
$_SESSION[self::SESSION_KEY]['id'] = $eventid;
$_SESSION[self::SESSION_KEY]['attachments'] = array();
}
foreach ((array)$message->attachments as $part) {
$attachment = array(
'data' => $imap->get_message_part($uid, $part->mime_id, $part),
'size' => $part->size,
'name' => $part->filename,
'mimetype' => $part->mimetype,
'group' => $eventid,
);
$attachment = $this->rc->plugins->exec_hook('attachment_save', $attachment);
if ($attachment['status'] && !$attachment['abort']) {
$id = $attachment['id'];
$attachment['classname'] = rcube_utils::file2class($attachment['mimetype'], $attachment['name']);
// store new attachment in session
unset($attachment['status'], $attachment['abort'], $attachment['data']);
$_SESSION[self::SESSION_KEY]['attachments'][$id] = $attachment;
$attachment['id'] = 'rcmfile' . $attachment['id']; // add prefix to consider it 'new'
$event['attachments'][] = $attachment;
}
}
}
$this->rc->output->command('plugin.mail2event_dialog', $event);
}
else {
$this->rc->output->command('display_message', $this->gettext('messageopenerror'), 'error');
}
$this->rc->output->send();
}
/**
* Handler for the 'message_compose' plugin hook. This will check for
* a compose parameter 'calendar_event' and create an attachment with the
* referenced event in iCal format
*/
public function mail_message_compose($args)
{
// set the submitted event ID as attachment
if (!empty($args['param']['calendar_event'])) {
$this->load_driver();
list($cal, $id) = explode(':', $args['param']['calendar_event'], 2);
if ($event = $this->driver->get_event(array('id' => $id, 'calendar' => $cal))) {
$filename = asciiwords($event['title']);
if (empty($filename))
$filename = 'event';
// save ics to a temp file and register as attachment
$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['param']['subject'] = $event['title'];
}
}
return $args;
}
/**
* Get a list of email addresses of the current user (from login and identities)
*/
public function get_user_emails()
{
return $this->lib->get_user_emails();
}
/**
* Build an absolute URL with the given parameters
*/
public function get_url($param = array())
{
$param += array('task' => 'calendar');
return $this->rc->url($param, true, true);
}
public function ical_feed_hash($source)
{
return base64_encode($this->rc->user->get_username() . ':' . $source);
}
/**
* Handler for user_delete plugin hook
*/
public function user_delete($args)
{
// delete itipinvitations entries related to this user
$db = $this->rc->get_dbh();
$table_itipinvitations = $db->table_name('itipinvitations', true);
$db->query("DELETE FROM $table_itipinvitations WHERE `user_id` = ?", $args['user']->ID);
$this->load_driver();
return $this->driver->user_delete($args);
}
/**
* Magic getter for public access to protected members
*/
public function __get($name)
{
switch ($name) {
case 'ical':
return $this->get_ical();
case 'itip':
return $this->load_itip();
case 'driver':
$this->load_driver();
return $this->driver;
}
return null;
}
}
diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index 6c26e5a2..84c5adbf 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -1,4271 +1,4272 @@
/**
* Client UI Javascript for the Calendar plugin
*
* @author Lazlo Westerhof <hello@lazlo.me>
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* @licstart The following is the entire license notice for the
* JavaScript code in this file.
*
* Copyright (C) 2010, Lazlo Westerhof <hello@lazlo.me>
* Copyright (C) 2014-2015, 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
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @licend The above is the entire license notice
* for the JavaScript code in this file.
*/
// Roundcube calendar UI client class
function rcube_calendar_ui(settings)
{
// extend base class
rcube_calendar.call(this, settings);
/*** member vars ***/
this.is_loading = false;
this.selected_event = null;
this.selected_calendar = null;
this.search_request = null;
this.saving_lock;
this.calendars = {};
this.quickview_sources = [];
/*** private vars ***/
var DAY_MS = 86400000;
var HOUR_MS = 3600000;
var me = this;
var gmt_offset = (new Date().getTimezoneOffset() / -60) - (settings.timezone || 0) - (settings.dst || 0);
var client_timezone = new Date().getTimezoneOffset();
var day_clicked = day_clicked_ts = 0;
var ignore_click = false;
var event_defaults = { free_busy:'busy', alarms:'' };
var event_attendees = [];
var calendars_list;
var calenders_search_list;
var calenders_search_container;
var search_calendars = {};
var attendees_list;
var resources_list;
var resources_treelist;
var resources_data = {};
var resources_index = [];
var resource_owners = {};
var resources_events_source = { url:null, editable:false };
var freebusy_ui = { workinhoursonly:false, needsupdate:false };
var freebusy_data = {};
var current_view = null;
var count_sources = [];
var exec_deferred = bw.ie6 ? 5 : 1;
var sensitivitylabels = { 'public':rcmail.gettext('public','calendar'), 'private':rcmail.gettext('private','calendar'), 'confidential':rcmail.gettext('confidential','calendar') };
var ui_loading = rcmail.set_busy(true, 'loading');
// general datepicker settings
var datepicker_settings = {
// translate from fullcalendar format to datepicker format
dateFormat: settings['date_format'].replace(/M/g, 'm').replace(/mmmmm/, 'MM').replace(/mmm/, 'M').replace(/dddd/, 'DD').replace(/ddd/, 'D').replace(/yy/g, 'y'),
firstDay : settings['first_day'],
dayNamesMin: settings['days_short'],
monthNames: settings['months'],
monthNamesShort: settings['months'],
changeMonth: false,
showOtherMonths: true,
selectOtherMonths: true
};
// global fullcalendar settings
var fullcalendar_defaults = {
aspectRatio: 1,
ignoreTimezone: true, // will treat the given date strings as in local (browser's) timezone
monthNames : settings.months,
monthNamesShort : settings.months_short,
dayNames : settings.days,
dayNamesShort : settings.days_short,
firstDay : settings.first_day,
firstHour : settings.first_hour,
slotMinutes : 60/settings.timeslots,
timeFormat: {
'': settings.time_format,
agenda: settings.time_format + '{ - ' + settings.time_format + '}',
list: settings.time_format + '{ - ' + settings.time_format + '}',
table: settings.time_format + '{ - ' + settings.time_format + '}'
},
axisFormat : settings.time_format,
columnFormat: {
month: 'ddd', // Mon
week: 'ddd ' + settings.date_short, // Mon 9/7
day: 'dddd ' + settings.date_short, // Monday 9/7
table: settings.date_agenda
},
titleFormat: {
month: 'MMMM yyyy',
week: settings.dates_long,
day: 'dddd ' + settings['date_long'],
table: settings.dates_long
},
listPage: 7, // advance one week in agenda view
listRange: settings.agenda_range,
listSections: settings.agenda_sections,
tableCols: ['handle', 'date', 'time', 'title', 'location'],
defaultView: rcmail.env.view || settings.default_view,
allDayText: rcmail.gettext('all-day', 'calendar'),
buttonText: {
prev: '&nbsp;&#9668;&nbsp;',
next: '&nbsp;&#9658;&nbsp;',
today: settings['today'],
day: rcmail.gettext('day', 'calendar'),
week: rcmail.gettext('week', 'calendar'),
month: rcmail.gettext('month', 'calendar'),
table: rcmail.gettext('agenda', 'calendar')
},
listTexts: {
until: rcmail.gettext('until', 'calendar'),
past: rcmail.gettext('pastevents', 'calendar'),
today: rcmail.gettext('today', 'calendar'),
tomorrow: rcmail.gettext('tomorrow', 'calendar'),
thisWeek: rcmail.gettext('thisweek', 'calendar'),
nextWeek: rcmail.gettext('nextweek', 'calendar'),
thisMonth: rcmail.gettext('thismonth', 'calendar'),
nextMonth: rcmail.gettext('nextmonth', 'calendar'),
future: rcmail.gettext('futureevents', 'calendar'),
week: rcmail.gettext('weekofyear', 'calendar')
},
currentTimeIndicator: settings.time_indicator,
// event rendering
eventRender: function(event, element, view) {
if (view.name != 'list' && view.name != 'table') {
var prefix = event.sensitivity && event.sensitivity != 'public' ? String(sensitivitylabels[event.sensitivity]).toUpperCase()+': ' : '';
element.attr('title', prefix + event.title);
}
if (view.name != 'month') {
if (event.location) {
element.find('div.fc-event-title').after('<div class="fc-event-location">@&nbsp;' + Q(event.location) + '</div>');
}
if (event.sensitivity && event.sensitivity != 'public')
element.find('div.fc-event-time').append('<i class="fc-icon-sensitive"></i>');
if (event.recurrence)
element.find('div.fc-event-time').append('<i class="fc-icon-recurring"></i>');
if (event.alarms || (event.valarms && event.valarms.length))
element.find('div.fc-event-time').append('<i class="fc-icon-alarms"></i>');
}
if (event.status) {
element.addClass('cal-event-status-' + String(event.status).toLowerCase());
}
element.attr('aria-label', event.title + ', ' + me.event_date_text(event, true));
},
// render element indicating more (invisible) events
overflowRender: function(data, element) {
element.html(rcmail.gettext('andnmore', 'calendar').replace('$nr', data.count))
.click(function(e){ me.fisheye_view(data.date); });
},
// callback when a specific event is clicked
eventClick: function(event, ev, view) {
if (!event.temp && String(event.className).indexOf('fc-type-freebusy') < 0)
event_show_dialog(event, ev);
}
};
/*** imports ***/
var Q = this.quote_html;
var text2html = this.text2html;
var event_date_text = this.event_date_text;
var parse_datetime = this.parse_datetime;
var date2unixtime = this.date2unixtime;
var fromunixtime = this.fromunixtime;
var parseISO8601 = this.parseISO8601;
var date2servertime = this.date2ISO8601;
var render_message_links = this.render_message_links;
/*** private methods ***/
// same as str.split(delimiter) but it ignores delimiters within quoted strings
var explode_quoted_string = function(str, delimiter)
{
var result = [],
strlen = str.length,
q, p, i, char, last;
for (q = p = i = 0; i < strlen; i++) {
char = str.charAt(i);
if (char == '"' && last != '\\') {
q = !q;
}
else if (!q && char == delimiter) {
result.push(str.substring(p, i));
p = i + 1;
}
last = char;
}
result.push(str.substr(p));
return result;
};
// Change the first charcter to uppercase
var ucfirst = function(str)
{
return str.charAt(0).toUpperCase() + str.substr(1);
};
// clone the given date object and optionally adjust time
var clone_date = function(date, adjust)
{
var d = new Date(date.getTime());
// set time to 00:00
if (adjust == 1) {
d.setHours(0);
d.setMinutes(0);
}
// set time to 23:59
else if (adjust == 2) {
d.setHours(23);
d.setMinutes(59);
}
return d;
};
// fix date if jumped over a DST change
var fix_date = function(date)
{
if (date.getHours() == 23)
date.setTime(date.getTime() + HOUR_MS);
else if (date.getHours() > 0)
date.setHours(0);
};
var date2timestring = function(date, dateonly)
{
return date2servertime(date).replace(/[^0-9]/g, '').substr(0, (dateonly ? 8 : 14));
}
var format_datetime = function(date, mode, voice)
{
return me.format_datetime(date, mode, voice);
}
var render_link = function(url)
{
var islink = false, href = url;
if (url.match(/^[fhtpsmailo]+?:\/\//i)) {
islink = true;
}
else if (url.match(/^[a-z0-9.-:]+(\/|$)/i)) {
islink = true;
href = 'http://' + url;
}
return islink ? '<a href="' + Q(href) + '" target="_blank">' + Q(url) + '</a>' : Q(url);
}
// determine whether the given date is on a weekend
var is_weekend = function(date)
{
return date.getDay() == 0 || date.getDay() == 6;
};
var is_workinghour = function(date)
{
if (settings['work_start'] > settings['work_end'])
return date.getHours() >= settings['work_start'] || date.getHours() < settings['work_end'];
else
return date.getHours() >= settings['work_start'] && date.getHours() < settings['work_end'];
};
// check if the event has 'real' attendees, excluding the current user
var has_attendees = function(event)
{
return (event.attendees && event.attendees.length && (event.attendees.length > 1 || String(event.attendees[0].email).toLowerCase() != settings.identity.email));
};
// check if the current user is an attendee of this event
var is_attendee = function(event, role, email)
{
var emails = email ? ';'+email.toLowerCase() : settings.identity.emails;
for (var i=0; event.attendees && i < event.attendees.length; i++) {
if ((!role || event.attendees[i].role == role) && event.attendees[i].email && emails.indexOf(';'+event.attendees[i].email.toLowerCase()) >= 0)
return event.attendees[i];
}
return false;
};
// check if the current user is the organizer
var is_organizer = function(event, email)
{
return is_attendee(event, 'ORGANIZER', email) || !event.id;
};
/**
* Check permissions on the given calendar object
*/
var has_permission = function(cal, perm)
{
// multiple chars means "either of"
if (String(perm).length > 1) {
for (var i=0; i < perm.length; i++) {
if (has_permission(cal, perm[i]))
return true;
}
}
if (cal.rights && String(cal.rights).indexOf(perm) >= 0) {
return true;
}
return (perm == 'i' && cal.editable) || (perm == 'v' && cal.editable);
}
var load_attachment = function(event, att)
{
var query = { _id: att.id, _event: event.recurrence_id || event.id, _cal:event.calendar, _frame: 1 };
if (event.rev)
query._rev = event.rev;
// 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)) {
return;
}
}
query._frame = null;
query._download = 1;
rcmail.goto_url('get-attachment', query, false);
};
// build event attachments list
var event_show_attachments = function(list, container, event, edit)
{
var i, id, len, img, content, li, elem,
ul = document.createElement('UL');
ul.className = 'attachmentslist';
for (i=0, len=list.length; i<len; i++) {
elem = list[i];
li = document.createElement('LI');
li.className = elem.classname;
if (edit) {
rcmail.env.attachments[elem.id] = elem;
// delete icon
content = $('<a href="#delete" />')
.attr('title', rcmail.gettext('delete'))
.attr('aria-label', rcmail.gettext('delete') + ' ' + Q(elem.name))
.addClass('delete')
.click({id: elem.id}, function(e) { remove_attachment(this, e.data.id); return false; });
if (!rcmail.env.deleteicon)
content.html(rcmail.gettext('delete'));
else {
img = document.createElement('IMG');
img.src = rcmail.env.deleteicon;
img.alt = rcmail.gettext('delete');
content.append(img);
}
content.appendTo(li);
}
// name/link
content = $('<a href="#load" />')
.html(Q(elem.name))
.addClass('file')
.click({event: event, att: elem}, function(e) {
load_attachment(e.data.event, e.data.att);
return false;
})
.appendTo(li);
ul.appendChild(li);
}
if (edit && rcmail.gui_objects.attachmentlist) {
ul.id = rcmail.gui_objects.attachmentlist.id;
rcmail.gui_objects.attachmentlist = ul;
}
container.empty().append(ul);
};
var remove_attachment = function(elem, id)
{
$(elem.parentNode).hide();
rcmail.env.deleted_attachments.push(id);
delete rcmail.env.attachments[id];
};
// event details dialog (show only)
var event_show_dialog = function(event, ev, temp)
{
var $dialog = $("#eventshow");
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:false, rights:'lrs' };
if (!temp)
me.selected_event = event;
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
// remove status-* 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(' ');
});
// convert start/end dates if not done yet by fullcalendar
if (typeof event.start == 'string')
event.start = parseISO8601(event.start);
if (typeof event.end == 'string')
event.end = parseISO8601(event.end);
// allow other plugins to do actions when event form is opened
rcmail.triggerEvent('calendar-event-init', {o: event});
$dialog.find('div.event-section, div.event-line').hide();
$('#event-title').html(Q(event.title)).show();
if (event.location)
$('#event-location').html('@ ' + text2html(event.location)).show();
if (event.description)
$('#event-description').show().children('.event-text').html(text2html(event.description, 300, 6));
if (event.vurl)
$('#event-url').show().children('.event-text').html(render_link(event.vurl));
// render from-to in a nice human-readable way
// -> now shown in dialog title
// $('#event-date').html(Q(me.event_date_text(event))).show();
if (event.recurrence && event.recurrence_text)
$('#event-repeat').show().children('.event-text').html(Q(event.recurrence_text));
if (event.valarms && event.alarms_text)
$('#event-alarm').show().children('.event-text').html(Q(event.alarms_text));
if (calendar.name)
$('#event-calendar').show().children('.event-text').html(Q(calendar.name)).attr('class', 'event-text cal-'+calendar.id).css('color', calendar.textColor || calendar.color || '');
if (event.categories)
$('#event-category').show().children('.event-text').html(Q(event.categories)).attr('class', 'event-text cat-'+String(event.categories).toLowerCase().replace(rcmail.identifier_expr, ''));
if (event.free_busy)
$('#event-free-busy').show().children('.event-text').html(Q(rcmail.gettext(event.free_busy, 'calendar')));
if (event.priority > 0) {
var priolabels = [ '', rcmail.gettext('highest'), rcmail.gettext('high'), '', '', rcmail.gettext('normal'), '', '', rcmail.gettext('low'), rcmail.gettext('lowest') ];
$('#event-priority').show().children('.event-text').html(Q(event.priority+' '+priolabels[event.priority]));
}
if (event.status) {
var status_lc = String(event.status).toLowerCase();
$('#event-status').show().children('.event-text').html(Q(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]));
$dialog.addClass('sensitivity-'+event.sensitivity);
}
if (event.created || event.changed) {
var created = parseISO8601(event.created),
changed = parseISO8601(event.changed)
$('#event-created-changed .event-created').html(Q(created ? format_datetime(created) : rcmail.gettext('unknown','calendar')))
$('#event-created-changed .event-changed').html(Q(changed ? format_datetime(changed) : rcmail.gettext('unknown','calendar')))
$('#event-created-changed').show()
}
// create attachments list
if ($.isArray(event.attachments)) {
event_show_attachments(event.attachments, $('#event-attachments').children('.event-text'), event);
if (event.attachments.length > 0) {
$('#event-attachments').show();
}
}
else if (calendar.attachments) {
// fetch attachments, some drivers doesn't set 'attachments' prop of the event?
}
// build attachments list
$('#event-links').hide();
if ($.isArray(event.links) && event.links.length) {
render_message_links(event.links || [], $('#event-links').children('.event-text'), false, 'calendar');
$('#event-links').show();
}
// list event attendees
if (calendar.attendees && event.attendees) {
// sort resources to the end
event.attendees.sort(function(a,b) {
var j = a.cutype == 'RESOURCE' ? 1 : 0,
k = b.cutype == 'RESOURCE' ? 1 : 0;
return (j - k);
});
var data, mystatus = null, rsvp, line, morelink, html = '', overflow = '';
for (var j=0; j < event.attendees.length; j++) {
data = event.attendees[j];
if (data.email) {
if (data.role == 'ORGANIZER')
organizer = true;
else if (settings.identity.emails.indexOf(';'+data.email) >= 0) {
mystatus = data.status.toLowerCase();
if (data.status == 'NEEDS-ACTION' || data.status == 'TENTATIVE' || data.rsvp)
rsvp = mystatus;
}
}
line = event_attendee_html(data);
if (morelink)
overflow += line;
else
html += line;
// stop listing attendees
if (j == 7 && event.attendees.length >= 7) {
morelink = $('<a href="#more" class="morelink"></a>').html(rcmail.gettext('andnmore', 'calendar').replace('$nr', event.attendees.length - j - 1));
}
}
if (html && (event.attendees.length > 1 || !organizer)) {
$('#event-attendees').show()
.children('.event-text')
.html(html)
.find('a.mailtolink').click(event_attendee_click);
// display all attendees in a popup when clicking the "more" link
if (morelink) {
$('#event-attendees .event-text').append(morelink);
morelink.click(function(e){
rcmail.show_popup_dialog(
'<div id="all-event-attendees" class="event-attendees">' + html + overflow + '</div>',
rcmail.gettext('tabattendees','calendar'),
null,
{ width:450, modal:false });
$('#all-event-attendees a.mailtolink').click(event_attendee_click);
return false;
})
}
}
if (mystatus && !rsvp) {
$('#event-partstat').show().children('.changersvp')
.removeClass('accepted tentative declined delegated needs-action')
.addClass(mystatus)
.children('.event-text')
.html(Q(rcmail.gettext('itip' + mystatus, 'libcalendaring')));
}
var show_rsvp = rsvp && !is_organizer(event) && event.status != 'CANCELLED' && has_permission(calendar, 'v');
$('#event-rsvp')[(show_rsvp ? 'show' : 'hide')]();
$('#event-rsvp .rsvp-buttons input').prop('disabled', false).filter('input[rel='+mystatus+']').prop('disabled', true);
if (show_rsvp && event.comment)
$('#event-rsvp-comment').show().children('.event-text').html(Q(event.comment));
$('#event-rsvp a.reply-comment-toggle').show();
$('#event-rsvp .itip-reply-comment textarea').hide().val('');
if (event.recurrence && event.id) {
var sel = event._savemode || (event.thisandfuture ? 'future' : (event.isexception ? 'current' : 'all'));
$('#event-rsvp .rsvp-buttons').addClass('recurring');
}
else {
$('#event-rsvp .rsvp-buttons').removeClass('recurring');
}
}
var buttons = [];
if (!temp && calendar.editable && event.editable !== false) {
buttons.push({
text: rcmail.gettext('edit', 'calendar'),
click: function() {
event_edit_dialog('edit', event);
}
});
}
if (!temp && has_permission(calendar, 'td') && event.editable !== false) {
buttons.push({
text: rcmail.gettext('delete', 'calendar'),
'class': 'delete',
click: function() {
me.delete_event(event);
$dialog.dialog('close');
}
});
}
if (!buttons.length) {
buttons.push({
text: rcmail.gettext('close', 'calendar'),
click: function(){
$dialog.dialog('close');
}
});
}
// open jquery UI dialog
$dialog.dialog({
modal: false,
resizable: !bw.ie6,
closeOnEscape: (!bw.ie6 && !bw.ie7), // disable for performance reasons
title: me.event_date_text(event),
open: function() {
$dialog.attr('aria-hidden', 'false');
setTimeout(function(){
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
}, 5);
},
close: function() {
$dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
rcmail.command('menu-close','eventoptionsmenu');
$('.libcal-rsvp-replymode').hide();
},
dragStart: function() {
rcmail.command('menu-close','eventoptionsmenu');
$('.libcal-rsvp-replymode').hide();
},
resizeStart: function() {
rcmail.command('menu-close','eventoptionsmenu');
$('.libcal-rsvp-replymode').hide();
},
buttons: buttons,
minWidth: 320,
width: 420
}).show();
// remember opener element (to be focused on close)
$dialog.data('opener', ev && rcube_event.is_keyboard(ev) ? ev.target : null);
// set voice title on dialog widget
$dialog.dialog('widget').removeAttr('aria-labelledby')
.attr('aria-label', me.event_date_text(event, true) + ', ', event.title);
// set dialog size according to content
me.dialog_resize($dialog.get(0), $dialog.height(), 420);
// add link for "more options" drop-down
if (!temp && !event.temporary && event.calendar != '_resource') {
$('<a>')
.attr('href', '#')
.html(rcmail.gettext('eventoptions','calendar'))
.addClass('dropdown-link')
.click(function(e) {
return rcmail.command('menu-open','eventoptionsmenu', this, e)
})
.appendTo($dialog.parent().find('.ui-dialog-buttonset'));
}
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> ';
};
// event handler for clicks on an attendee link
var event_attendee_click = function(e)
{
var cutype = $(this).attr('data-cutype'),
mailto = this.href.substr(7);
if (rcmail.env.calendar_resources && cutype == 'RESOURCE') {
event_resources_dialog(mailto);
}
else {
rcmail.command('compose', mailto, e ? e.target : null, e);
}
return false;
};
// bring up the event dialog (jquery-ui popup)
var event_edit_dialog = function(action, event)
{
// copy opener element from show dialog
var op_elem = $("#eventshow:ui-dialog").data('opener');
// close show dialog first
$("#eventshow:ui-dialog").data('opener', null).dialog('close');
var $dialog = $('<div>');
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:true, rights: action=='new' ? 'lrwitd' : 'lrs' };
me.selected_event = $.extend($.extend({}, event_defaults), event); // clone event object (with defaults)
event = me.selected_event; // change reference to clone
freebusy_ui.needsupdate = false;
// reset dialog first
$('#eventtabs').get(0).reset();
$('#event-panel-recurrence input, #event-panel-recurrence select, #event-panel-attachments input').prop('disabled', false);
$('#event-panel-recurrence, #event-panel-attachments').removeClass('disabled');
// allow other plugins to do actions when event form is opened
rcmail.triggerEvent('calendar-event-init', {o: event});
// event details
var title = $('#edit-title').val(event.title || '');
var location = $('#edit-location').val(event.location || '');
var description = $('#edit-description').text(event.description || '');
var vurl = $('#edit-url').val(event.vurl || '');
var categories = $('#edit-categories').val(event.categories);
var calendars = $('#edit-calendar').val(event.calendar);
var eventstatus = $('#edit-event-status').val(event.status);
var freebusy = $('#edit-free-busy').val(event.free_busy);
var priority = $('#edit-priority').val(event.priority);
var sensitivity = $('#edit-sensitivity').val(event.sensitivity);
var duration = Math.round((event.end.getTime() - event.start.getTime()) / 1000);
var startdate = $('#edit-startdate').val($.fullCalendar.formatDate(event.start, settings['date_format'])).data('duration', duration);
var starttime = $('#edit-starttime').val($.fullCalendar.formatDate(event.start, settings['time_format'])).show();
var enddate = $('#edit-enddate').val($.fullCalendar.formatDate(event.end, settings['date_format']));
var endtime = $('#edit-endtime').val($.fullCalendar.formatDate(event.end, settings['time_format'])).show();
var allday = $('#edit-allday').get(0);
var notify = $('#edit-attendees-donotify').get(0);
var invite = $('#edit-attendees-invite').get(0);
var comment = $('#edit-attendees-comment');
invite.checked = settings.itip_notify & 1 > 0;
notify.checked = has_attendees(event) && invite.checked;
if (event.allDay) {
starttime.val("12:00").hide();
endtime.val("13:00").hide();
allday.checked = true;
}
else {
allday.checked = false;
}
// set calendar selection according to permissions
calendars.find('option').each(function(i, opt) {
var cal = me.calendars[opt.value] || {};
$(opt).prop('disabled', !(cal.editable || (action == 'new' && has_permission(cal, 'i'))))
});
// set alarm(s)
me.set_alarms_edit('#edit-alarms', action != 'new' && event.valarms && calendar.alarms ? event.valarms : []);
// enable/disable alarm property according to backend support
$('#edit-alarms')[(calendar.alarms ? 'show' : 'hide')]();
// check categories drop-down: add value if not exists
if (event.categories && !categories.find("option[value='"+event.categories+"']").length) {
$('<option>').attr('value', event.categories).text(event.categories).appendTo(categories).prop('selected', true);
}
if ($.isArray(event.links) && event.links.length) {
render_message_links(event.links, $('#edit-event-links .event-text'), true, 'calendar');
$('#edit-event-links').show();
}
else {
$('#edit-event-links').hide();
}
// show warning if editing a recurring event
if (event.id && event.recurrence) {
var sel = event._savemode || (event.thisandfuture ? 'future' : (event.isexception ? 'current' : 'all'));
$('#edit-recurring-warning').show();
$('input.edit-recurring-savemode[value="'+sel+'"]').prop('checked', true).change();
}
else
$('#edit-recurring-warning').hide();
// init attendees tab
var organizer = !event.attendees || is_organizer(event),
allow_invitations = organizer || (calendar.owner && calendar.owner == 'anonymous') || settings.invite_shared;
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')]();
var load_attendees_tab = function()
{
var j, data, reply_selected = 0;
if (event.attendees) {
for (j=0; j < event.attendees.length; j++) {
data = event.attendees[j];
// reset attendee status
if (event._savemode == 'new' && data.role != 'ORGANIZER') {
data.status = 'NEEDS-ACTION';
delete data.noreply;
}
add_attendee(data, !allow_invitations);
if (allow_invitations && data.role != 'ORGANIZER' && !data.noreply)
reply_selected++;
}
}
// make sure comment box is visible if at least one attendee has reply enabled
// or global "send invitations" checkbox is checked
$('#eventedit .attendees-commentbox')[(reply_selected || invite.checked ? 'show' : 'hide')]();
// select the correct organizer identity
var identity_id = 0;
$.each(settings.identities, function(i,v){
if (organizer && typeof organizer == 'object' && v == organizer.email) {
identity_id = i;
return false;
}
});
$('#edit-identities-list').val(identity_id);
$('#edit-attendees-form')[(allow_invitations?'show':'hide')]();
$('#edit-attendee-schedule')[(calendar.freebusy?'show':'hide')]();
};
// attachments
var load_attachments_tab = function()
{
rcmail.enable_command('remove-attachment', calendar.editable && !event.recurrence_id);
rcmail.env.deleted_attachments = [];
// we're sharing some code for uploads handling with app.js
rcmail.env.attachments = [];
rcmail.env.compose_id = event.id; // for rcmail.async_upload_form()
if ($.isArray(event.attachments)) {
event_show_attachments(event.attachments, $('#edit-attachments'), event, true);
}
else {
$('#edit-attachments > ul').empty();
// fetch attachments, some drivers doesn't set 'attachments' array for event?
}
};
// init dialog buttons
var buttons = [];
// save action
buttons.push({
text: rcmail.gettext('save', 'calendar'),
'class': 'mainaction',
click: function() {
var start = parse_datetime(allday.checked ? '12:00' : starttime.val(), startdate.val());
var end = parse_datetime(allday.checked ? '13:00' : endtime.val(), enddate.val());
// basic input validatetion
if (start.getTime() > end.getTime()) {
alert(rcmail.gettext('invalideventdates', 'calendar'));
return false;
}
// post data to server
var data = {
calendar: event.calendar,
start: date2servertime(start),
end: date2servertime(end),
allday: allday.checked?1:0,
title: title.val(),
description: description.val(),
location: location.val(),
categories: categories.val(),
vurl: vurl.val(),
free_busy: freebusy.val(),
priority: priority.val(),
sensitivity: sensitivity.val(),
status: eventstatus.val(),
recurrence: me.serialize_recurrence(endtime.val()),
valarms: me.serialize_alarms('#edit-alarms'),
attendees: event_attendees,
links: me.selected_event.links,
deleted_attachments: rcmail.env.deleted_attachments,
attachments: []
};
// uploaded attachments list
for (var i in rcmail.env.attachments)
if (i.match(/^rcmfile(.+)/))
data.attachments.push(RegExp.$1);
// read attendee roles
$('select.edit-attendee-role').each(function(i, elem){
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;
if (allow_invitations) {
$.each(data.attendees, function (i, v) {
if (v.role != 'ORGANIZER') {
if ($('input.edit-attendee-reply[value="' + v.email + '"]').prop('checked') || v.cutype == 'RESOURCE') {
need_invitation = true;
delete data.attendees[i]['noreply'];
}
else if (settings.itip_notify > 0) {
data.attendees[i].noreply = 1;
}
}
});
}
// tell server to send notifications
if ((data.attendees.length || (event.id && event.attendees.length)) && allow_invitations && (notify.checked || invite.checked || need_invitation)) {
data._notify = settings.itip_notify;
data._comment = comment.val();
}
data.calendar = calendars.val();
if (event.id) {
data.id = event.id;
if (event.recurrence)
data._savemode = $('input.edit-recurring-savemode:checked').val();
if (data.calendar && data.calendar != event.calendar)
data._fromcalendar = event.calendar;
}
update_event(action, data);
$dialog.dialog("close");
} // end click:
});
if (event.id) {
buttons.push({
text: rcmail.gettext('delete', 'calendar'),
'class': 'delete',
click: function() {
me.delete_event(event);
$dialog.dialog('close');
}
});
}
buttons.push({
text: rcmail.gettext('cancel', 'calendar'),
click: function() {
$dialog.dialog("close");
}
});
// show/hide tabs according to calendar's feature support
$('#edit-tab-attendees')[(calendar.attendees?'show':'hide')]();
$('#edit-tab-resources')[(rcmail.env.calendar_resources?'show':'hide')]();
$('#edit-tab-attachments')[(calendar.attachments?'show':'hide')]();
// activate the first tab
$('#eventtabs').tabs('option', 'active', 0);
// hack: set task to 'calendar' to make all dialog actions work correctly
var comm_path_before = rcmail.env.comm_path;
rcmail.env.comm_path = comm_path_before.replace(/_task=[a-z]+/, '_task=calendar');
var editform = $("#eventedit");
// open jquery UI dialog
$dialog.dialog({
modal: true,
resizable: (!bw.ie6 && !bw.ie7), // disable for performance reasons
closeOnEscape: false,
title: rcmail.gettext((action == 'edit' ? 'edit_event' : 'new_event'), 'calendar'),
open: function() {
editform.attr('aria-hidden', 'false');
},
close: function() {
editform.hide().attr('aria-hidden', 'true').appendTo(document.body);
$dialog.dialog("destroy").remove();
rcmail.ksearch_blur();
freebusy_data = {};
rcmail.env.comm_path = comm_path_before; // restore comm_path
if (op_elem)
$(op_elem).focus();
},
buttons: buttons,
minWidth: 500,
width: 600
}).append(editform.show()); // adding form content AFTERWARDS massively speeds up opening on IE6
// set dialog size according to form content
me.dialog_resize($dialog.get(0), editform.height() + (bw.ie ? 20 : 0), 550);
title.select();
// init other tabs asynchronously
window.setTimeout(function(){ me.set_recurrence_edit(event); }, exec_deferred);
if (calendar.attendees)
window.setTimeout(load_attendees_tab, exec_deferred);
if (calendar.attachments)
window.setTimeout(load_attachments_tab, exec_deferred);
};
// show event changelog in a dialog
var event_history_dialog = function(event)
{
if (!event.id || !window.libkolab_audittrail)
return false
// render dialog
var $dialog = libkolab_audittrail.object_history_dialog({
module: 'calendar',
container: '#eventhistory',
- title: rcmail.gettext('eventchangelog','calendar') + ' - ' + event.title + ', ' + me.event_date_text(event),
+ title: rcmail.gettext('objectchangelog','calendar') + ' - ' + event.title + ', ' + me.event_date_text(event),
// callback function for list actions
listfunc: function(action, rev) {
me.loading_lock = rcmail.set_busy(true, 'loading', me.loading_lock);
rcmail.http_post('event', { action:action, e:{ id:event.id, calendar:event.calendar, rev: rev } }, me.loading_lock);
},
// callback function for comparing two object revisions
comparefunc: function(rev1, rev2) {
me.loading_lock = rcmail.set_busy(true, 'loading', me.loading_lock);
rcmail.http_post('event', { action:'diff', e:{ id:event.id, calendar:event.calendar, rev1: rev1, rev2: rev2 } }, me.loading_lock);
}
});
$dialog.data('event', event);
// fetch changelog data
me.loading_lock = rcmail.set_busy(true, 'loading', me.loading_lock);
rcmail.http_post('event', { action:'changelog', e:{ id:event.id, calendar:event.calendar } }, me.loading_lock);
};
// callback from server with changelog data
var render_event_changelog = function(data)
{
var $dialog = $('#eventhistory'),
event = $dialog.data('event');
if (data === false || !data.length || !event) {
// display 'unavailable' message
$('<div class="notfound-message event-dialog-message warning">' + rcmail.gettext('objectchangelognotavailable','calendar') + '</div>')
.insertBefore($dialog.find('.changelog-table').hide());
return;
}
+ data.module = 'calendar';
libkolab_audittrail.render_changelog(data, event, me.calendars[event.calendar]);
// set dialog size according to content
me.dialog_resize($dialog.get(0), $dialog.height(), 600);
};
// callback from server with event diff data
var event_show_diff = function(data)
{
var event = me.selected_event,
$dialog = $("#eventdiff");
$dialog.find('div.event-section, div.event-line, h1.event-title-new').hide().data('set', false).find('.index').html('');
$dialog.find('div.event-section.clone, div.event-line.clone').remove();
// always show event title and date
$('.event-title', $dialog).text(event.title).removeClass('event-text-old').show();
$('.event-date', $dialog).text(me.event_date_text(event)).show();
// show each property change
$.each(data.changes, function(i,change) {
var prop = change.property, r2, html = false,
row = $('div.event-' + prop, $dialog).first();
// special case: title
if (prop == 'title') {
$('.event-title', $dialog).addClass('event-text-old').text(change['old'] || '--');
$('.event-title-new', $dialog).text(change['new'] || '--').show();
}
// no display container for this property
if (!row.length) {
return true;
}
// clone row if already exists
if (row.data('set')) {
r2 = row.clone().addClass('clone').insertAfter(row);
row = r2;
}
// format dates
if (['start','end','changed'].indexOf(prop) >= 0) {
if (change['old']) change.old_ = me.format_datetime(parseISO8601(change['old']));
if (change['new']) change.new_ = me.format_datetime(parseISO8601(change['new']));
}
// render description text
else if (prop == 'description') {
// TODO: show real text diff
if (!change.diff_ && change['old']) change.old_ = text2html(change['old']);
if (!change.diff_ && change['new']) change.new_ = text2html(change['new']);
html = true;
}
// 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']));
html = true;
}
// localize priority values
else if (prop == 'priority') {
var priolabels = [ '', rcmail.gettext('highest'), rcmail.gettext('high'), '', '', rcmail.gettext('normal'), '', '', rcmail.gettext('low'), rcmail.gettext('lowest') ];
if (change['old']) change.old_ = change['old'] + ' ' + (priolabels[change['old']] || '');
if (change['new']) change.new_ = change['new'] + ' ' + (priolabels[change['new']] || '');
}
// localize status
else if (prop == 'status') {
var status_lc = String(event.status).toLowerCase();
if (change['old']) change.old_ = rcmail.gettext(String(change['old']).toLowerCase(), 'calendar');
if (change['new']) change.new_ = rcmail.gettext(String(change['new']).toLowerCase(), 'calendar');
}
// format attachments struct
if (prop == 'attachments') {
if (change['old']) event_show_attachments([change['old']], row.children('.event-text-old'), event, false);
else row.children('.event-text-old').text('--');
if (change['new']) event_show_attachments([$.extend({}, change['old'] || {}, change['new'])], row.children('.event-text-new'), event, false);
else row.children('.event-text-new').text('--');
// remove click handler as we're currentyl not able to display the according attachment contents
$('.attachmentslist li a', row).unbind('click').removeAttr('href');
}
else if (change.diff_) {
row.children('.event-text-diff').html(change.diff_);
row.children('.event-text-old, .event-text-new').hide();
}
else {
if (!html) {
// escape HTML characters
change.old_ = Q(change.old_ || change['old'] || '--')
change.new_ = Q(change.new_ || change['new'] || '--')
}
row.children('.event-text-old').html(change.old_ || change['old'] || '--');
row.children('.event-text-new').html(change.new_ || change['new'] || '--');
}
// display index number
if (typeof change.index != 'undefined') {
row.find('.index').html('(' + change.index + ')');
}
row.show().data('set', true);
// hide event-date line
if (prop == 'start' || prop == 'end')
$('.event-date', $dialog).hide();
});
var buttons = {};
buttons[rcmail.gettext('close', 'calendar')] = function() {
$dialog.dialog('close');
};
// open jquery UI dialog
$dialog.dialog({
modal: false,
resizable: true,
closeOnEscape: true,
- title: rcmail.gettext('eventdiff','calendar').replace('$rev1', data.rev1).replace('$rev2', data.rev2) + ' - ' + event.title,
+ title: rcmail.gettext('objectdiff','calendar').replace('$rev1', data.rev1).replace('$rev2', data.rev2) + ' - ' + event.title,
open: function() {
$dialog.attr('aria-hidden', 'false');
setTimeout(function(){
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
}, 5);
},
close: function() {
$dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
},
buttons: buttons,
minWidth: 320,
width: 450
}).show();
// set dialog size according to content
me.dialog_resize($dialog.get(0), $dialog.height(), 400);
};
// close the event history dialog
var close_history_dialog = function()
{
$('#eventhistory, #eventdiff').each(function(i, elem) {
var $dialog = $(elem);
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
});
}
// exports
this.event_show_diff = event_show_diff;
this.event_show_dialog = event_show_dialog;
this.event_history_dialog = event_history_dialog;
this.render_event_changelog = render_event_changelog;
this.close_history_dialog = close_history_dialog;
// open a dialog to display detailed free-busy information and to find free slots
var event_freebusy_dialog = function()
{
var $dialog = $('#eventfreebusy'),
event = me.selected_event;
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
if (!event_attendees.length)
return false;
// set form elements
var allday = $('#edit-allday').get(0);
var duration = Math.round((event.end.getTime() - event.start.getTime()) / 1000);
freebusy_ui.startdate = $('#schedule-startdate').val($.fullCalendar.formatDate(event.start, settings['date_format'])).data('duration', duration);
freebusy_ui.starttime = $('#schedule-starttime').val($.fullCalendar.formatDate(event.start, settings['time_format'])).show();
freebusy_ui.enddate = $('#schedule-enddate').val($.fullCalendar.formatDate(event.end, settings['date_format']));
freebusy_ui.endtime = $('#schedule-endtime').val($.fullCalendar.formatDate(event.end, settings['time_format'])).show();
if (allday.checked) {
freebusy_ui.starttime.val("12:00").hide();
freebusy_ui.endtime.val("13:00").hide();
event.allDay = true;
}
// read attendee roles from drop-downs
$('select.edit-attendee-role').each(function(i, elem){
if (event_attendees[i])
event_attendees[i].role = $(elem).val();
});
// render time slots
var now = new Date(), fb_start = new Date(), fb_end = new Date();
fb_start.setTime(event.start);
fb_start.setHours(0); fb_start.setMinutes(0); fb_start.setSeconds(0); fb_start.setMilliseconds(0);
fb_end.setTime(fb_start.getTime() + DAY_MS);
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.start = fb_start;
freebusy_ui.end = new Date(freebusy_ui.start.getTime() + DAY_MS * freebusy_ui.numdays);
render_freebusy_grid(0);
// render list of attendees
freebusy_ui.attendees = {};
var domid, dispname, data, role_html, list_html = '';
for (var i=0; i < event_attendees.length; i++) {
data = event_attendees[i];
dispname = Q(data.name || data.email);
domid = String(data.email).replace(rcmail.identifier_expr, '');
role_html = '<a class="attendee-role-toggle" id="rcmlia' + domid + '" title="' + Q(rcmail.gettext('togglerole', 'calendar')) + '">&nbsp;</a>';
list_html += '<div class="attendee ' + String(data.role).toLowerCase() + '" id="rcmli' + domid + '">' + role_html + dispname + '</div>';
// clone attendees data for local modifications
freebusy_ui.attendees[i] = freebusy_ui.attendees[domid] = $.extend({}, data);
}
// add total row
list_html += '<div class="attendee spacer">&nbsp;</div>';
list_html += '<div class="attendee total">' + rcmail.gettext('reqallattendees','calendar') + '</div>';
$('#schedule-attendees-list').html(list_html)
.unbind('click.roleicons')
.bind('click.roleicons', function(e){
// toggle attendee status upon click on icon
if (e.target.id && e.target.id.match(/rcmlia(.+)/)) {
var attendee, domid = RegExp.$1,
roles = [ 'REQ-PARTICIPANT', 'OPT-PARTICIPANT', 'NON-PARTICIPANT', 'CHAIR' ];
if ((attendee = freebusy_ui.attendees[domid]) && attendee.role != 'ORGANIZER') {
var req = attendee.role != 'OPT-PARTICIPANT' && attendee.role != 'NON-PARTICIPANT';
var j = $.inArray(attendee.role, roles);
j = (j+1) % roles.length;
attendee.role = roles[j];
$(e.target).parent().attr('class', 'attendee '+String(attendee.role).toLowerCase());
// update total display if required-status changed
if (req != (roles[j] != 'OPT-PARTICIPANT' && roles[j] != 'NON-PARTICIPANT')) {
compute_freebusy_totals();
update_freebusy_display(attendee.email);
}
}
}
return false;
});
// enable/disable buttons
$('#shedule-find-prev').button('option', 'disabled', (fb_start.getTime() < now.getTime()));
// dialog buttons
var buttons = {};
buttons[rcmail.gettext('select', 'calendar')] = function() {
$('#edit-startdate').val(freebusy_ui.startdate.val());
$('#edit-starttime').val(freebusy_ui.starttime.val());
$('#edit-enddate').val(freebusy_ui.enddate.val());
$('#edit-endtime').val(freebusy_ui.endtime.val());
// write role changes back to main dialog
$('select.edit-attendee-role').each(function(i, elem){
if (event_attendees[i] && freebusy_ui.attendees[i]) {
event_attendees[i].role = freebusy_ui.attendees[i].role;
$(elem).val(event_attendees[i].role);
}
});
if (freebusy_ui.needsupdate)
update_freebusy_status(me.selected_event);
freebusy_ui.needsupdate = false;
$dialog.dialog("close");
};
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
$dialog.dialog("close");
};
$dialog.dialog({
modal: true,
resizable: true,
closeOnEscape: (!bw.ie6 && !bw.ie7),
title: rcmail.gettext('scheduletime', 'calendar'),
open: function() {
$dialog.attr('aria-hidden', 'false').find('#shedule-find-next, #shedule-find-prev').not(':disabled').first().focus();
},
close: function() {
if (bw.ie6)
$("#edit-attendees-table").css('visibility','visible');
$dialog.dialog("destroy").attr('aria-hidden', 'true').hide();
// TODO: focus opener button
},
resizeStop: function() {
render_freebusy_overlay();
},
buttons: buttons,
minWidth: 640,
width: 850
}).show();
// hide edit dialog on IE6 because of drop-down elements
if (bw.ie6)
$("#edit-attendees-table").css('visibility','hidden');
// adjust dialog size to fit grid without scrolling
var gridw = $('#schedule-freebusy-times').width();
var overflow = gridw - $('#attendees-freebusy-table td.times').width() + 1;
me.dialog_resize($dialog.get(0), $dialog.height() + (bw.ie ? 20 : 0), 800 + Math.max(0, overflow));
// fetch data from server
freebusy_ui.loading = 0;
load_freebusy_data(freebusy_ui.start, freebusy_ui.interval);
};
// render an HTML table showing free-busy status for all the event attendees
var render_freebusy_grid = function(delta)
{
if (delta) {
freebusy_ui.start.setTime(freebusy_ui.start.getTime() + DAY_MS * delta);
fix_date(freebusy_ui.start);
// skip weekends if in workinhoursonly-mode
if (Math.abs(delta) == 1 && freebusy_ui.workinhoursonly) {
while (is_weekend(freebusy_ui.start))
freebusy_ui.start.setTime(freebusy_ui.start.getTime() + DAY_MS * delta);
fix_date(freebusy_ui.start);
}
freebusy_ui.end = new Date(freebusy_ui.start.getTime() + DAY_MS * freebusy_ui.numdays);
}
var dayslots = Math.floor(1440 / freebusy_ui.interval);
var date_format = 'ddd '+ (dayslots <= 2 ? settings.date_short : settings.date_format);
var lastdate, datestr, css,
curdate = new Date(),
allday = (freebusy_ui.interval == 1440),
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);
if (datestr != lastdate) {
if (lastdate && !allday) break;
dates_row += '<th colspan="' + dayslots + '" class="boxtitle date' + $.fullCalendar.formatDate(curdate, 'ddMMyyyy') + '">' + Q(datestr) + '</th>';
lastdate = datestr;
}
// 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">&nbsp;</td>';
t += freebusy_ui.interval * 60000;
}
dates_row += '</tr>';
times_row += '</tr>';
// render list of attendees
var domid, data, list_html = '', times_html = '';
for (var i=0; i < event_attendees.length; i++) {
data = event_attendees[i];
domid = String(data.email).replace(rcmail.identifier_expr, '');
times_html += '<tr id="fbrow' + domid + '">' + slots_row + '</tr>';
}
// add line for all/required attendees
times_html += '<tr class="spacer"><td colspan="' + (dayslots * freebusy_ui.numdays) + '">&nbsp;</td>';
times_html += '<tr id="fbrowall">' + slots_row + '</tr>';
var table = $('#schedule-freebusy-times');
table.children('thead').html(dates_row + times_row);
table.children('tbody').html(times_html);
// initialize event handlers on grid
if (!freebusy_ui.grid_events) {
freebusy_ui.grid_events = true;
table.children('thead').click(function(e){
// move event to the clicked date/time
if (e.target.id && e.target.id.match(/t-(\d+)/)) {
var newstart = new Date(RegExp.$1 * 1000);
// set time to 00:00
if (me.selected_event.allDay) {
newstart.setMinutes(0);
newstart.setHours(0);
}
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
if (!freebusy_ui.loading) {
if (freebusy_ui.start < freebusy_data.start || freebusy_ui.end > freebusy_data.end || freebusy_ui.interval != freebusy_data.interval) {
load_freebusy_data(freebusy_ui.start, freebusy_ui.interval);
}
else {
for (var email, i=0; i < event_attendees.length; i++) {
if ((email = event_attendees[i].email))
update_freebusy_display(email);
}
}
}
// render current event date/time selection over grid table
// use timeout to let the dom attributes (width/height/offset) be set first
window.setTimeout(function(){ render_freebusy_overlay(); }, 10);
};
// render overlay element over the grid to visiualize the current event date/time
var render_freebusy_overlay = function()
{
var overlay = $('#schedule-event-time');
if (me.selected_event.end.getTime() <= freebusy_ui.start.getTime() || me.selected_event.start.getTime() >= freebusy_ui.end.getTime()) {
overlay.hide();
if (overlay.data('isdraggable'))
overlay.draggable('disable');
}
else {
var 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;
}
slotstart = 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();
// configure draggable
if (!overlay.data('isdraggable')) {
overlay.draggable({
axis: 'x',
scroll: true,
stop: function(e, ui){
// convert pixels to time
var px = ui.position.left;
var range_p = $('#schedule-freebusy-times').width();
var range_t = freebusy_ui.end.getTime() - freebusy_ui.start.getTime();
var newstart = new Date(freebusy_ui.start.getTime() + px * (range_t / range_p));
newstart.setSeconds(0); newstart.setMilliseconds(0);
// snap to day boundaries
if (me.selected_event.allDay) {
if (newstart.getHours() >= 12) // snap to next day
newstart.setTime(newstart.getTime() + DAY_MS);
newstart.setMinutes(0);
newstart.setHours(0);
}
else {
// round to 5 minutes
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);
}
// update event times and display
update_freebusy_dates(newstart, new Date(newstart.getTime() + freebusy_ui.startdate.data('duration') * 1000));
if (me.selected_event.allDay)
render_freebusy_overlay();
}
}).data('isdraggable', true);
}
else
overlay.draggable('enable');
}
else
overlay.draggable('disable').hide();
}
};
// fetch free-busy information for each attendee from server
var load_freebusy_data = function(from, interval)
{
var start = new Date(from.getTime() - DAY_MS * 2); // start 2 days before event
fix_date(start);
var end = new Date(start.getTime() + DAY_MS * Math.max(14, freebusy_ui.numdays + 7)); // load min. 14 days
freebusy_ui.numrequired = 0;
freebusy_data.all = [];
freebusy_data.required = [];
// load free-busy information for every attendee
var domid, email;
for (var i=0; i < event_attendees.length; i++) {
if ((email = event_attendees[i].email)) {
domid = String(email).replace(rcmail.identifier_expr, '');
$('#rcmli' + domid).addClass('loading');
freebusy_ui.loading++;
$.ajax({
type: 'GET',
dataType: 'json',
url: rcmail.url('freebusy-times'),
data: { email:email, start:date2servertime(clone_date(start, 1)), end:date2servertime(clone_date(end, 2)), interval:interval, _remote:1 },
success: function(data) {
freebusy_ui.loading--;
// find attendee
var attendee = null;
for (var i=0; i < event_attendees.length; i++) {
if (freebusy_ui.attendees[i].email == data.email) {
attendee = freebusy_ui.attendees[i];
break;
}
}
// copy data to member var
var ts, req = attendee.role != 'OPT-PARTICIPANT';
freebusy_data.start = parseISO8601(data.start);
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];
// set totals
if (!freebusy_data.required[ts])
freebusy_data.required[ts] = [0,0,0,0];
if (req)
freebusy_data.required[ts][data.slots[i]]++;
if (!freebusy_data.all[ts])
freebusy_data.all[ts] = [0,0,0,0];
freebusy_data.all[ts][data.slots[i]]++;
}
freebusy_data.end = parseISO8601(data.end);
freebusy_data.interval = data.interval;
// hide loading indicator
var domid = String(data.email).replace(rcmail.identifier_expr, '');
$('#rcmli' + domid).removeClass('loading');
// update display
update_freebusy_display(data.email);
}
});
// count required attendees
if (freebusy_ui.attendees[i].role != 'OPT-PARTICIPANT')
freebusy_ui.numrequired++;
}
}
};
// re-calculate total status after role change
var compute_freebusy_totals = function()
{
freebusy_ui.numrequired = 0;
freebusy_data.all = [];
freebusy_data.required = [];
var email, req, status;
for (var i=0; i < event_attendees.length; i++) {
if (!(email = event_attendees[i].email))
continue;
req = freebusy_ui.attendees[i].role != 'OPT-PARTICIPANT';
if (req)
freebusy_ui.numrequired++;
for (var ts in freebusy_data[email]) {
if (!freebusy_data.required[ts])
freebusy_data.required[ts] = [0,0,0,0];
if (!freebusy_data.all[ts])
freebusy_data.all[ts] = [0,0,0,0];
status = freebusy_data[email][ts];
freebusy_data.all[ts][status]++;
if (req)
freebusy_data.required[ts][status]++;
}
}
};
// update free-busy grid with status loaded from server
var update_freebusy_display = function(email)
{
var status_classes = ['unknown','free','busy','tentative','out-of-office'];
var domid = String(email).replace(rcmail.identifier_expr, '');
var row = $('#fbrow' + domid);
var rowall = $('#fbrowall').children();
var dateonly = freebusy_ui.interval > 60,
t, ts = date2timestring(freebusy_ui.start, dateonly),
curdate = new Date(),
fbdata = freebusy_data[email];
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');
// 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];
}
cell.className = (workinghours ? 'workinghours ' : 'offhours ') + req_status + ' all-' + all_status;
}
t += freebusy_ui.interval * 60000;
});
}
};
// write changed event date/times back to form fields
var update_freebusy_dates = function(start, end)
{
// fix all-day evebt times
if (me.selected_event.allDay) {
var numdays = Math.floor((me.selected_event.end.getTime() - me.selected_event.start.getTime()) / DAY_MS);
start.setHours(12);
start.setMinutes(0);
end.setTime(start.getTime() + numdays * DAY_MS);
end.setHours(13);
end.setMinutes(0);
}
me.selected_event.start = start;
me.selected_event.end = end;
freebusy_ui.startdate.val($.fullCalendar.formatDate(start, settings['date_format']));
freebusy_ui.starttime.val($.fullCalendar.formatDate(start, settings['time_format']));
freebusy_ui.enddate.val($.fullCalendar.formatDate(end, settings['date_format']));
freebusy_ui.endtime.val($.fullCalendar.formatDate(end, settings['time_format']));
freebusy_ui.needsupdate = true;
};
// attempt to find a time slot where all attemdees are available
var freebusy_find_slot = function(dir)
{
// exit if free-busy data isn't available yet
if (!freebusy_data || !freebusy_data.start)
return false;
var event = me.selected_event,
eventstart = clone_date(event.start, event.allDay ? 1 : 0).getTime(), // calculate with integers
eventend = clone_date(event.end, event.allDay ? 2 : 0).getTime(),
duration = eventend - eventstart - (event.allDay ? HOUR_MS : 0), /* make sure we don't cross day borders on DST change */
sinterval = freebusy_data.interval * 60000,
intvlslots = 1,
numslots = Math.ceil(duration / sinterval),
checkdate, slotend, email, ts, slot, slotdate = new Date();
// 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) {
slotdate.setTime(slot);
// fix slot if just crossed a DST change
if (event.allDay) {
fix_date(slotdate);
slot = slotdate.getTime();
}
slotend = slot + sinterval;
if ((dir > 0 && slotend <= eventstart) || (dir < 0 && slot >= eventend)) // skip
continue;
// respect workingours setting
if (freebusy_ui.workinhoursonly) {
if (is_weekend(slotdate) || (freebusy_data.interval <= 60 && !is_workinghour(slotdate))) { // skip off-hours
candidatestart = candidateend = false;
candidatecount = 0;
continue;
}
}
if (!candidatestart)
candidatestart = slot;
// check freebusy data for all attendees
ts = date2timestring(slotdate, freebusy_data.interval > 60);
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;
break;
}
}
// occupied slot
if (!candidatestart) {
slot += Math.max(0, intvlslots - candidatecount - 1) * sinterval * dir;
candidatecount = 0;
continue;
}
// 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);
}
success = true;
break;
}
}
// update event date/time display
if (success) {
update_freebusy_dates(event.start, event.end);
// move freebusy grid if necessary
var offset = Math.ceil((event.start.getTime() - freebusy_ui.end.getTime()) / DAY_MS);
if (event.start.getTime() >= freebusy_ui.end.getTime())
render_freebusy_grid(Math.max(1, offset));
else if (event.end.getTime() <= freebusy_ui.start.getTime())
render_freebusy_grid(Math.min(-1, offset));
else
render_freebusy_overlay();
var now = new Date();
$('#shedule-find-prev').button('option', 'disabled', (event.start.getTime() < now.getTime()));
// speak new selection
rcmail.display_message(rcmail.gettext('suggestedslot', 'calendar') + ': ' + me.event_date_text(event, true), 'voice');
}
else {
alert(rcmail.gettext('noslotfound','calendar'));
}
};
// update event properties and attendees availability if event times have changed
var event_times_changed = function()
{
if (me.selected_event) {
var allday = $('#edit-allday').get(0);
me.selected_event.allDay = allday.checked;
me.selected_event.start = parse_datetime(allday.checked ? '12:00' : $('#edit-starttime').val(), $('#edit-startdate').val());
me.selected_event.end = parse_datetime(allday.checked ? '13:00' : $('#edit-endtime').val(), $('#edit-enddate').val());
if (event_attendees)
freebusy_ui.needsupdate = true;
$('#edit-startdate').data('duration', Math.round((me.selected_event.end.getTime() - me.selected_event.start.getTime()) / 1000));
}
};
// add the given list of participants
var add_attendees = function(names, params)
{
names = explode_quoted_string(names.replace(/,\s*$/, ''), ',');
// parse name/email pairs
var item, email, name, success = false;
for (var i=0; i < names.length; i++) {
email = name = '';
item = $.trim(names[i]);
if (!item.length) {
continue;
} // address in brackets without name (do nothing)
else if (item.match(/^<[^@]+@[^>]+>$/)) {
email = item.replace(/[<>]/g, '');
} // address without brackets and without name (add brackets)
else if (rcube_check_email(item)) {
email = item;
} // address with name
else if (item.match(/([^\s<@]+@[^>]+)>*$/)) {
email = RegExp.$1;
name = item.replace(email, '').replace(/^["\s<>]+/, '').replace(/["\s<>]+$/, '');
}
if (email) {
add_attendee($.extend({ email:email, name:name }, params));
success = true;
}
else {
alert(rcmail.gettext('noemailwarning'));
}
}
return success;
};
// add the given attendee to the list
var add_attendee = function(data, readonly, before)
{
if (!me.selected_event)
return false;
// check for dupes...
var exists = false;
$.each(event_attendees, function(i, v){ exists |= (v.email == data.email); });
if (exists)
return false;
var calendar = me.selected_event && me.calendars[me.selected_event.calendar] ? me.calendars[me.selected_event.calendar] : me.calendars[me.selected_calendar];
var dispname = Q(data.name || data.email);
if (data.email)
dispname = '<a href="mailto:' + data.email + '" title="' + Q(data.email) + '" class="mailtolink" data-cutype="' + data.cutype + '">' + dispname + '</a>';
// role selection
var organizer = data.role == 'ORGANIZER';
var opts = {};
if (organizer)
opts.ORGANIZER = rcmail.gettext('calendar.roleorganizer');
opts['REQ-PARTICIPANT'] = rcmail.gettext('calendar.rolerequired');
opts['OPT-PARTICIPANT'] = rcmail.gettext('calendar.roleoptional');
opts['NON-PARTICIPANT'] = rcmail.gettext('calendar.rolenonparticipant');
if (data.cutype != 'RESOURCE')
opts['CHAIR'] = rcmail.gettext('calendar.rolechair');
if (organizer && !readonly)
dispname = rcmail.env['identities-selector'];
var select = '<select class="edit-attendee-role"' + (organizer || readonly ? ' disabled="true"' : '') + ' aria-label="' + rcmail.gettext('role','calendar') + '">';
for (var r in opts)
select += '<option value="'+ r +'" class="' + r.toLowerCase() + '"' + (data.role == r ? ' selected="selected"' : '') +'>' + Q(opts[r]) + '</option>';
select += '</select>';
// availability
var avail = data.email ? 'loading' : 'unknown';
// 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 || '';
// send invitation checkbox
var invbox = '<input type="checkbox" class="edit-attendee-reply" value="' + Q(data.email) +'" title="' + Q(rcmail.gettext('calendar.sendinvitations')) + '" '
+ (!data.noreply && settings.itip_notify & 1 ? 'checked="checked" ' : '') + '/>';
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'];
// add expand button for groups
if (data.cutype == 'GROUP') {
dispname += ' <a href="#expand" data-email="' + Q(data.email) + '" class="iconbutton add expandlink" title="' + rcmail.gettext('expandattendeegroup','libcalendaring') + '">' +
rcmail.gettext('expandattendeegroup','libcalendaring') + '</a>';
}
var img_src = rcmail.assets_path('program/resources/blank.gif');
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>' +
(data.cutype != 'RESOURCE' ? '<td class="invite">' + (organizer || readonly || !invbox ? '' : invbox) + '</td>' : '') +
'<td class="options">' + (organizer || readonly ? '' : dellink) + '</td>';
var table = rcmail.env.calendar_resources && data.cutype == 'RESOURCE' ? resources_list : attendees_list;
var tr = $('<tr>')
.addClass(String(data.role).toLowerCase())
.html(html);
if (before)
tr.insertBefore(before)
else
tr.appendTo(table);
tr.find('a.deletelink').click({ id:(data.email || data.name) }, function(e) { remove_attendee(this, e.data.id); return false; });
tr.find('a.mailtolink').click(event_attendee_click);
tr.find('a.expandlink').click(data, function(e) { me.expand_attendee_group(e, add_attendee, remove_attendee); return false; });
tr.find('input.edit-attendee-reply').click(function() {
var enabled = $('#edit-attendees-invite:checked').length || $('input.edit-attendee-reply:checked').length;
$('#eventedit .attendees-commentbox')[enabled ? 'show' : 'hide']();
});
// select organizer identity
if (data.identity_id)
$('#edit-identities-list').val(data.identity_id);
// check free-busy status
if (avail == 'loading') {
check_freebusy_status(tr.find('img.availabilityicon'), data.email, me.selected_event);
}
event_attendees.push(data);
return true;
};
// iterate over all attendees and update their free-busy status display
var update_freebusy_status = function(event)
{
attendees_list.find('img.availabilityicon').each(function(i,v) {
var email, icon = $(this);
if (email = icon.attr('data-email'))
check_freebusy_status(icon, email, event);
});
freebusy_ui.needsupdate = false;
};
// load free-busy status from server and update icon accordingly
var check_freebusy_status = function(icon, email, event)
{
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { freebusy:false };
if (!calendar.freebusy) {
$(icon).attr('class', 'availabilityicon unknown');
return;
}
icon = $(icon).attr('class', 'availabilityicon loading');
$.ajax({
type: 'GET',
dataType: 'html',
url: rcmail.url('freebusy-status'),
data: { email:email, start:date2servertime(clone_date(event.start, event.allDay?1:0)), end:date2servertime(clone_date(event.end, event.allDay?2:0)), _remote: 1 },
success: function(status){
var avail = String(status).toLowerCase();
icon.removeClass('loading').addClass(avail).attr('alt', rcmail.gettext('avail' + avail, 'calendar'));
},
error: function(){
icon.removeClass('loading').addClass('unknown').attr('alt', rcmail.gettext('availunknown', 'calendar'));
}
});
};
// remove an attendee from the list
var remove_attendee = function(elem, id)
{
$(elem).closest('tr').remove();
event_attendees = $.grep(event_attendees, function(data){ return (data.name != id && data.email != id) });
};
// open a dialog to display detailed free-busy information and to find free slots
var event_resources_dialog = function(search)
{
var $dialog = $('#eventresourcesdialog');
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
// dialog buttons
var buttons = {};
buttons[rcmail.gettext('addresource', 'calendar')] = function() {
rcmail.command('add-resource');
};
buttons[rcmail.gettext('close')] = function() {
$dialog.dialog("close");
};
// open jquery UI dialog
$dialog.dialog({
modal: true,
resizable: true,
closeOnEscape: true,
title: rcmail.gettext('findresources', 'calendar'),
open: function() {
$dialog.attr('aria-hidden', 'false');
},
close: function() {
$dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
},
resize: function(e) {
var container = $(rcmail.gui_objects.resourceinfocalendar);
container.fullCalendar('option', 'height', container.height() + 4);
},
buttons: buttons,
width: 900,
height: 500
}).show();
// define add-button as main action
$('.ui-dialog-buttonset .ui-button', $dialog.parent()).first().addClass('mainaction').attr('id', 'rcmbtncalresadd');
me.dialog_resize($dialog.get(0), 540, Math.min(1000, $(window).width() - 50));
// set search query
$('#resourcesearchbox').val(search || '');
// initialize the treelist widget
if (!resources_treelist) {
resources_treelist = new rcube_treelist_widget(rcmail.gui_objects.resourceslist, {
id_prefix: 'rcres',
id_encode: rcmail.html_identifier_encode,
id_decode: rcmail.html_identifier_decode,
selectable: true,
save_state: true
});
resources_treelist.addEventListener('select', function(node) {
if (resources_data[node.id]) {
resource_showinfo(resources_data[node.id]);
rcmail.enable_command('add-resource', me.selected_event && $("#eventedit").is(':visible') ? true : false);
}
else {
rcmail.enable_command('add-resource', false);
$(rcmail.gui_objects.resourceinfo).hide();
$(rcmail.gui_objects.resourceownerinfo).hide();
$(rcmail.gui_objects.resourceinfocalendar).fullCalendar('removeEventSource', resources_events_source);
}
});
// fetch (all) resource data from server
me.loading_lock = rcmail.set_busy(true, 'loading', me.loading_lock);
rcmail.http_request('resources-list', {}, me.loading_lock);
// register button
rcmail.register_button('add-resource', 'rcmbtncalresadd', 'uibutton');
// initialize resource calendar display
var resource_cal = $(rcmail.gui_objects.resourceinfocalendar);
resource_cal.fullCalendar($.extend({}, fullcalendar_defaults, {
header: { left: '', center: '', right: '' },
height: resource_cal.height() + 4,
defaultView: 'agendaWeek',
eventSources: [],
slotMinutes: 60,
allDaySlot: false,
eventRender: function(event, element, view) {
var title = rcmail.get_label(event.status, 'calendar');
element.addClass('status-' + event.status);
element.find('.fc-event-head').hide();
element.find('.fc-event-title').text(title);
element.attr('aria-label', me.event_date_text(event, true) + ': ' + title);
}
}));
$('#resource-calendar-prev').click(function(){
resource_cal.fullCalendar('prev');
return false;
});
$('#resource-calendar-next').click(function(){
resource_cal.fullCalendar('next');
return false;
});
}
else if (search) {
resource_search();
}
else {
resource_render_list(resources_index);
}
if (me.selected_event && me.selected_event.start) {
$(rcmail.gui_objects.resourceinfocalendar).fullCalendar('gotoDate', me.selected_event.start);
}
};
// render the resource details UI box
var resource_showinfo = function(resource)
{
// inline function to render a resource attribute
function render_attrib(value) {
if (typeof value == 'boolean') {
return value ? rcmail.get_label('yes') : rcmail.get_label('no');
}
return value;
}
if (rcmail.gui_objects.resourceinfo) {
var tr, table = $(rcmail.gui_objects.resourceinfo).show().find('tbody').html(''),
attribs = $.extend({ name:resource.name }, resource.attributes||{})
attribs.description = resource.description;
for (var k in attribs) {
if (typeof attribs[k] == 'undefined')
continue;
table.append($('<tr>').addClass(k)
.append('<td class="title">' + Q(ucfirst(rcmail.get_label(k, 'calendar'))) + '</td>')
.append('<td class="value">' + text2html(render_attrib(attribs[k])) + '</td>')
);
}
$(rcmail.gui_objects.resourceownerinfo).hide();
$(rcmail.gui_objects.resourceinfocalendar).fullCalendar('removeEventSource', resources_events_source);
if (resource.owner) {
// display cached data
if (resource_owners[resource.owner]) {
resource_owner_load(resource_owners[resource.owner]);
}
else {
// fetch owner data from server
me.loading_lock = rcmail.set_busy(true, 'loading', me.loading_lock);
rcmail.http_request('resources-owner', { _id: resource.owner }, me.loading_lock);
}
}
// load resource calendar
resources_events_source.url = "./?_task=calendar&_action=resources-calendar&_id="+urlencode(resource.ID);
$(rcmail.gui_objects.resourceinfocalendar).fullCalendar('addEventSource', resources_events_source);
}
};
// callback from server for resource listing
var resource_data_load = function(data)
{
var resources_tree = {};
// store data by ID
$.each(data, function(i, rec) {
resources_data[rec.ID] = rec;
// assign parent-relations
if (rec.members) {
$.each(rec.members, function(j, m){
resources_tree[m] = rec.ID;
});
}
});
// walk the parent-child tree to determine the depth of each node
$.each(data, function(i, rec) {
rec._depth = 0;
if (resources_tree[rec.ID])
rec.parent_id = resources_tree[rec.ID];
var parent_id = resources_tree[rec.ID];
while (parent_id) {
rec._depth++;
parent_id = resources_tree[parent_id];
}
});
// sort by depth, collection and name
data.sort(function(a,b) {
var j = a._type == 'collection' ? 1 : 0,
k = b._type == 'collection' ? 1 : 0,
d = a._depth - b._depth;
if (!d) d = (k - j);
if (!d) d = b.name < a.name ? 1 : -1;
return d;
});
$.each(data, function(i, rec) {
resources_index.push(rec.ID);
});
// apply search filter...
if ($('#resourcesearchbox').val() != '')
resource_search();
else // ...or render full list
resource_render_list(resources_index);
rcmail.set_busy(false, null, me.loading_lock);
};
// renders the given list of resource records into the treelist
var resource_render_list = function(index) {
var rec, link;
resources_treelist.reset();
$.each(index, function(i, dn) {
if (rec = resources_data[dn]) {
link = $('<a>').attr('href', '#')
.attr('rel', rec.ID)
.html(Q(rec.name));
resources_treelist.insert({ id:rec.ID, html:link, classes:[rec._type], collapsed:true }, rec.parent_id, false);
}
});
};
// callback from server for owner information display
var resource_owner_load = function(data)
{
if (data) {
// cache this!
resource_owners[data.ID] = data;
var table = $(rcmail.gui_objects.resourceownerinfo).find('tbody').html('');
for (var k in data) {
if (k == 'event' || k == 'ID')
continue;
table.append($('<tr>').addClass(k)
.append('<td class="title">' + Q(ucfirst(rcmail.get_label(k, 'calendar'))) + '</td>')
.append('<td class="value">' + text2html(data[k]) + '</td>')
);
}
table.parent().show();
}
}
// quick-filter the loaded resource data
var resource_search = function()
{
var dn, rec, dataset = [],
q = $('#resourcesearchbox').val().toLowerCase();
if (q.length && resources_data) {
// search by iterating over all resource records
for (dn in resources_data) {
rec = resources_data[dn];
if ((rec.name && String(rec.name).toLowerCase().indexOf(q) >= 0)
|| (rec.email && String(rec.email).toLowerCase().indexOf(q) >= 0)
|| (rec.description && String(rec.description).toLowerCase().indexOf(q) >= 0)
) {
dataset.push(rec.ID);
}
}
resource_render_list(dataset);
// select single match
if (dataset.length == 1) {
resources_treelist.select(dataset[0]);
}
}
else {
$('#resourcesearchbox').val('');
}
};
//
var reset_resource_search = function()
{
$('#resourcesearchbox').val('').focus();
resource_render_list(resources_index);
};
//
var add_resource2event = function()
{
var resource = resources_data[resources_treelist.get_selection()];
if (resource) {
if (add_attendee($.extend({ role:'REQ-PARTICIPANT', status:'NEEDS-ACTION', cutype:'RESOURCE' }, resource)))
rcmail.display_message(rcmail.get_label('resourceadded', 'calendar'), 'confirmation');
}
}
// when the user accepts or declines an event invitation
var event_rsvp = function(response, delegate, replymode)
{
var btn;
if (typeof response == 'object') {
btn = $(response);
response = btn.attr('rel')
}
else {
btn = $('#event-rsvp input.button[rel='+response+']');
}
// show menu to select rsvp reply mode (current or all)
if (me.selected_event && me.selected_event.recurrence && !replymode) {
rcube_libcalendaring.itip_rsvp_recurring(btn, function(resp, mode) {
event_rsvp(resp, null, mode);
});
return;
}
if (me.selected_event && me.selected_event.attendees && response) {
// bring up delegation dialog
if (response == 'delegated' && !delegate) {
rcube_libcalendaring.itip_delegate_dialog(function(data) {
data.rsvp = data.rsvp ? 1 : '';
event_rsvp('delegated', data, replymode);
});
return;
}
// update attendee status
attendees = [];
for (var data, i=0; i < me.selected_event.attendees.length; i++) {
data = me.selected_event.attendees[i];
if (settings.identity.emails.indexOf(';'+String(data.email).toLowerCase()) >= 0) {
data.status = response.toUpperCase();
data.rsvp = 0; // unset RSVP flag
if (data.status == 'DELEGATED') {
data['delegated-to'] = delegate.to;
data.rsvp = delegate.rsvp
}
else {
if (data['delegated-to']) {
delete data['delegated-to'];
if (data.role == 'NON-PARTICIPANT' && data.status != 'DECLINED')
data.role = 'REQ-PARTICIPANT';
}
}
attendees.push(i)
}
else if (response != 'DELEGATED' && data['delegated-from'] &&
settings.identity.emails.indexOf(';'+String(data['delegated-from']).toLowerCase()) >= 0) {
delete data['delegated-from'];
}
// set free_busy status to transparent if declined (#4425)
if (data.status == 'DECLINED' || data.role == 'NON-PARTICIPANT') {
me.selected_event.free_busy = 'free';
}
else {
me.selected_event.free_busy = 'busy';
}
}
// submit status change to server
var submit_data = $.extend({}, me.selected_event, { source:null, comment:$('#reply-comment-event-rsvp').val(), _savemode: replymode || 'all' }, (delegate || {})),
noreply = $('#noreply-event-rsvp:checked').length ? 1 : 0;
// import event from mail (temporary iTip event)
if (submit_data._mbox && submit_data._uid) {
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
rcmail.http_post('mailimportitip', {
_mbox: submit_data._mbox,
_uid: submit_data._uid,
_part: submit_data._part,
_status: response,
_to: (delegate ? delegate.to : null),
_rsvp: (delegate && delegate.rsvp) ? 1 : 0,
_noreply: noreply,
_comment: submit_data.comment,
_instance: submit_data._instance,
_savemode: submit_data._savemode
});
}
else if (settings.invitation_calendars) {
update_event('rsvp', submit_data, { status:response, noreply:noreply, attendees:attendees });
}
else {
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
rcmail.http_post('event', { action:'rsvp', e:submit_data, status:response, attendees:attendees, noreply:noreply });
}
event_show_dialog(me.selected_event);
}
};
// add the given date to the RDATE list
var add_rdate = function(date)
{
var li = $('<li>')
.attr('data-value', date2servertime(date))
.html('<span>' + Q($.fullCalendar.formatDate(date, settings['date_format'])) + '</span>')
.appendTo('#edit-recurrence-rdates');
$('<a>').attr('href', '#del')
.addClass('iconbutton delete')
.html(rcmail.get_label('delete', 'calendar'))
.attr('title', rcmail.get_label('delete', 'calendar'))
.appendTo(li);
};
// re-sort the list items by their 'data-value' attribute
var sort_rdates = function()
{
var mylist = $('#edit-recurrence-rdates'),
listitems = mylist.children('li').get();
listitems.sort(function(a, b) {
var compA = $(a).attr('data-value');
var compB = $(b).attr('data-value');
return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
})
$.each(listitems, function(idx, item) { mylist.append(item); });
}
// remove the link reference matching the given uri
function remove_link(elem)
{
var $elem = $(elem), uri = $elem.attr('data-uri');
me.selected_event.links = $.grep(me.selected_event.links, function(link) { return link.uri != uri; });
// remove UI list item
$elem.hide().closest('li').addClass('deleted');
}
// post the given event data to server
var update_event = function(action, data, add)
{
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
rcmail.http_post('calendar/event', $.extend({ action:action, e:data }, (add || {})));
// render event temporarily into the calendar
if ((data.start && data.end) || data.id) {
var event = data.id ? $.extend(fc.fullCalendar('clientEvents', function(e){ return e.id == data.id; })[0], data) : data;
if (data.start)
event.start = data.start;
if (data.end)
event.end = data.end;
if (data.allday !== undefined)
event.allDay = data.allday;
event.editable = false;
event.temp = true;
event.className = 'fc-event-cal-'+data.calendar+' fc-event-temp';
fc.fullCalendar(data.id ? 'updateEvent' : 'renderEvent', event);
// mark all recurring instances as temp
if (event.recurrence || event.recurrence_id) {
var base_id = event.recurrence_id ? event.recurrence_id : String(event.id).replace(/-\d+(T\d{6})?$/, '');
$.each(fc.fullCalendar('clientEvents', function(e){ return e.id == base_id || e.recurrence_id == base_id; }), function(i,ev) {
ev.temp = true;
ev.editable = false;
event.className += ' fc-event-temp';
fc.fullCalendar('updateEvent', ev);
});
}
}
};
// mouse-click handler to check if the show dialog is still open and prevent default action
var dialog_check = function(e)
{
var showd = $("#eventshow");
if (showd.is(':visible') && !$(e.target).closest('.ui-dialog').length && !$(e.target).closest('.popupmenu').length) {
showd.dialog('close');
e.stopImmediatePropagation();
ignore_click = true;
return false;
}
else if (ignore_click) {
window.setTimeout(function(){ ignore_click = false; }, 20);
return false;
}
return true;
};
// display confirm dialog when modifying/deleting an event
var update_event_confirm = function(action, event, data)
{
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) {
html += '<div class="message">' +
'<label><input class="confirm-attendees-donotify" type="checkbox"' + checked + ' value="1" name="notify" />&nbsp;' +
rcmail.gettext((action == 'remove' ? 'sendcancellation' : 'sendnotifications'), 'calendar') +
'</label></div>';
}
else {
data._notify = settings.itip_notify;
}
}
else if (action == 'remove' && is_attendee(event)) {
decline = true;
checked = event.status != 'CANCELLED' ? checked : '';
html += '<div class="message">' +
'<label><input class="confirm-attendees-decline" type="checkbox"' + checked + ' value="1" name="decline" />&nbsp;' +
rcmail.gettext('itipdeclineevent', 'calendar') +
'</label></div>';
}
else {
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');
// disable the 'future' savemode if I'm an attendee
// reason: no calendaring system supports the thisandfuture range parameter in iTip REPLY
if (action == 'remove' && _has_attendees && !_is_organizer && is_attendee(event)) {
future_disabled = ' disabled';
}
html += '<div class="message"><span class="ui-icon ui-icon-alert"></span>' +
rcmail.gettext(message_label, 'calendar') + '</div>' +
'<div class="savemode">' +
'<a href="#current" class="button">' + rcmail.gettext('currentevent', 'calendar') + '</a>' +
'<a href="#future" class="button' + future_disabled + '">' + rcmail.gettext('futurevents', 'calendar') + '</a>' +
'<a href="#all" class="button">' + rcmail.gettext('allevents', 'calendar') + '</a>' +
(action != 'remove' ? '<a href="#new" class="button">' + rcmail.gettext('saveasnew', 'calendar') + '</a>' : '') +
'</div>';
}
// show dialog
if (html) {
var $dialog = $('<div>').html(html);
$dialog.find('a.button').button().filter(':not(.disabled)').click(function(e) {
data._savemode = String(this.href).replace(/.+#/, '');
data._notify = settings.itip_notify;
// open event edit dialog when saving as new
if (data._savemode == 'new') {
event._savemode = 'new';
event_edit_dialog('edit', event);
fc.fullCalendar('refetchEvents');
}
else {
if ($dialog.find('input.confirm-attendees-donotify').length)
data._notify = $dialog.find('input.confirm-attendees-donotify').get(0).checked ? 1 : 0;
if (decline) {
data._decline = $dialog.find('input.confirm-attendees-decline:checked').length;
data._notify = 0;
}
update_event(action, data);
}
$dialog.dialog("close");
return false;
});
var buttons = [];
if (!event.recurrence) {
buttons.push({
text: rcmail.gettext((action == 'remove' ? 'delete' : 'save'), 'calendar'),
click: function() {
data._notify = notify && $dialog.find('input.confirm-attendees-donotify:checked').length ? 1 : 0;
data._decline = decline && $dialog.find('input.confirm-attendees-decline:checked').length ? 1 : 0;
update_event(action, data);
$(this).dialog("close");
}
});
}
buttons.push({
text: rcmail.gettext('cancel', 'calendar'),
click: function() {
$(this).dialog("close");
}
});
$dialog.dialog({
modal: true,
width: 460,
dialogClass: 'warning',
title: rcmail.gettext((action == 'remove' ? 'removeeventconfirm' : 'changeeventconfirm'), 'calendar'),
buttons: buttons,
open: function() {
setTimeout(function(){
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
}, 5);
},
close: function(){
$dialog.dialog("destroy").remove();
if (!rcmail.busy)
fc.fullCalendar('refetchEvents');
}
}).addClass('event-update-confirm').show();
return false;
}
// show regular confirm box when deleting
else if (action == 'remove' && !cal.undelete) {
if (!confirm(rcmail.gettext('deleteventconfirm', 'calendar')))
return false;
}
// do update
update_event(action, data);
return true;
};
var update_agenda_toolbar = function()
{
$('#agenda-listrange').val(fc.fullCalendar('option', 'listRange'));
$('#agenda-listsections').val(fc.fullCalendar('option', 'listSections'));
}
/*** public methods ***/
/**
* Remove saving lock and free the UI for new input
*/
this.unlock_saving = function()
{
if (me.saving_lock)
rcmail.set_busy(false, null, me.saving_lock);
};
// opens calendar day-view in a popup
this.fisheye_view = function(date)
{
$('#fish-eye-view:ui-dialog').dialog('close');
// create list of active event sources
var src, cals = {}, sources = [];
for (var id in this.calendars) {
src = $.extend({}, this.calendars[id]);
src.editable = false;
src.url = null;
src.events = [];
if (src.active) {
cals[id] = src;
sources.push(src);
}
}
// copy events already loaded
var events = fc.fullCalendar('clientEvents');
for (var event, i=0; i< events.length; i++) {
event = events[i];
if (event.source && (src = cals[event.source.id])) {
src.events.push(event);
}
}
var h = $(window).height() - 50;
var dialog = $('<div>')
.attr('id', 'fish-eye-view')
.dialog({
modal: true,
width: 680,
height: h,
title: $.fullCalendar.formatDate(date, 'dddd ' + settings['date_long']),
close: function(){
dialog.dialog("destroy");
me.fisheye_date = null;
}
})
.fullCalendar($.extend({}, fullcalendar_defaults, {
defaultView: 'agendaDay',
header: { left: '', center: '', right: '' },
height: h - 50,
date: date.getDate(),
month: date.getMonth(),
year: date.getFullYear(),
eventSources: sources
}));
this.fisheye_date = date;
};
// opens the given calendar in a popup dialog
this.quickview = function(id, shift)
{
var src, in_quickview = false;
$.each(this.quickview_sources, function(i,cal) {
if (cal.id == id) {
in_quickview = true;
src = cal;
}
});
// remove source from quickview
if (in_quickview && shift) {
this.quickview_sources = $.grep(this.quickview_sources, function(src) { return src.id != id; });
}
else {
if (!shift) {
// remove all current quickview event sources
if (this.quickview_active) {
fc.fullCalendar('removeEventSources');
}
this.quickview_sources = [];
// uncheck all active quickview icons
calendars_list.container.find('div.focusview')
.add('#calendars .searchresults div.focusview')
.removeClass('focusview')
.find('a.quickview').attr('aria-checked', 'false');
}
if (!in_quickview) {
// clone and modify calendar properties
src = $.extend({}, this.calendars[id]);
src.url += '&_quickview=1';
this.quickview_sources.push(src);
}
}
// disable quickview
if (this.quickview_active && !this.quickview_sources.length) {
// register regular calendar event sources
$.each(this.calendars, function(k, cal) {
if (cal.active)
fc.fullCalendar('addEventSource', cal);
});
this.quickview_active = false;
$('body').removeClass('quickview-active');
// uncheck all active quickview icons
calendars_list.container.find('div.focusview')
.add('#calendars .searchresults div.focusview')
.removeClass('focusview')
.find('a.quickview').attr('aria-checked', 'false');
}
// activate quickview
else if (!this.quickview_active) {
// remove regular calendar event sources
fc.fullCalendar('removeEventSources');
// register quickview event sources
$.each(this.quickview_sources, function(i, src) {
fc.fullCalendar('addEventSource', src);
});
this.quickview_active = true;
$('body').addClass('quickview-active');
}
// update quickview sources
else if (in_quickview) {
fc.fullCalendar('removeEventSource', src);
}
else if (src) {
fc.fullCalendar('addEventSource', src);
}
// activate quickview icon
if (this.quickview_active) {
$(calendars_list.get_item(id)).find('.calendar').first()
.add('#calendars .searchresults .cal-' + id)
[in_quickview ? 'removeClass' : 'addClass']('focusview')
.find('a.quickview').attr('aria-checked', in_quickview ? 'false' : 'true');
}
};
// disable quickview mode
function reset_quickview()
{
// remove all current quickview event sources
if (me.quickview_active) {
fc.fullCalendar('removeEventSources');
me.quickview_sources = [];
}
// register regular calendar event sources
$.each(me.calendars, function(k, cal) {
if (cal.active)
fc.fullCalendar('addEventSource', cal);
});
// uncheck all active quickview icons
calendars_list.container.find('div.focusview')
.add('#calendars .searchresults div.focusview')
.removeClass('focusview')
.find('a.quickview').attr('aria-checked', 'false');
me.quickview_active = false;
$('body').removeClass('quickview-active');
};
//public method to show the print dialog.
this.print_calendars = function(view)
{
if (!view) view = fc.fullCalendar('getView').name;
var date = fc.fullCalendar('getDate') || new Date();
var range = fc.fullCalendar('option', 'listRange');
var sections = fc.fullCalendar('option', 'listSections');
rcmail.open_window(rcmail.url('print', { view: view, date: date2unixtime(date), range: range, sections: sections, search: this.search_query }), true, true);
};
// public method to bring up the new event dialog
this.add_event = function(templ) {
if (this.selected_calendar) {
var now = new Date();
var date = fc.fullCalendar('getDate');
if (typeof date != 'Date')
date = now;
date.setHours(now.getHours()+1);
date.setMinutes(0);
var end = new Date(date.getTime());
end.setHours(date.getHours()+1);
event_edit_dialog('new', $.extend({ start:date, end:end, allDay:false, calendar:this.selected_calendar }, templ || {}));
}
};
// delete the given event after showing a confirmation dialog
this.delete_event = function(event) {
// show confirm dialog for recurring events, use jquery UI dialog
return update_event_confirm('remove', event, { id:event.id, calendar:event.calendar, attendees:event.attendees });
};
// opens a jquery UI dialog with event properties (or empty for creating a new calendar)
this.calendar_edit_dialog = function(calendar)
{
// close show dialog first
var $dialog = $("#calendarform");
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
if (!calendar)
calendar = { name:'', color:'cc0000', editable:true, showalarms:true };
var form, name, color, alarms;
$dialog.html(rcmail.get_label('loading'));
$.ajax({
type: 'GET',
dataType: 'html',
url: rcmail.url('calendar'),
data: { action:(calendar.id ? 'form-edit' : 'form-new'), c:{ id:calendar.id } },
success: function(data) {
$dialog.html(data);
// resize and reposition dialog window
form = $('#calendarpropform');
me.dialog_resize('#calendarform', form.height(), form.width());
name = $('#calendar-name').prop('disabled', !calendar.editable).val(calendar.editname || calendar.name);
color = $('#calendar-color').val(calendar.color).miniColors({ value: calendar.color, colorValues:rcmail.env.mscolors });
alarms = $('#calendar-showalarms').prop('checked', calendar.showalarms).get(0);
name.select();
}
});
// dialog buttons
var buttons = {};
buttons[rcmail.gettext('save', 'calendar')] = function() {
// form is not loaded
if (!form || !form.length)
return;
// TODO: do some input validation
if (!name.val() || name.val().length < 2) {
alert(rcmail.gettext('invalidcalendarproperties', 'calendar'));
name.select();
return;
}
// post data to server
var data = form.serializeJSON();
if (data.color)
data.color = data.color.replace(/^#/, '');
if (calendar.id)
data.id = calendar.id;
if (alarms)
data.showalarms = alarms.checked ? 1 : 0;
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
rcmail.http_post('calendar', { action:(calendar.id ? 'edit' : 'new'), c:data });
$dialog.dialog("close");
};
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
$dialog.dialog("close");
};
// open jquery UI dialog
$dialog.dialog({
modal: true,
resizable: true,
closeOnEscape: false,
title: rcmail.gettext((calendar.id ? 'editcalendar' : 'createcalendar'), 'calendar'),
open: function() {
$dialog.parent().find('.ui-dialog-buttonset .ui-button').first().addClass('mainaction');
},
close: function() {
$dialog.html('').dialog("destroy").hide();
},
buttons: buttons,
minWidth: 400,
width: 420
}).show();
};
this.calendar_remove = function(calendar)
{
this.calendar_destroy_source(calendar.id);
rcmail.http_post('calendar', { action:'subscribe', c:{ id:calendar.id, active:0, permanent:0, recursive:1 } });
return true;
};
this.calendar_delete = function(calendar)
{
if (confirm(rcmail.gettext(calendar.children ? 'deletecalendarconfirmrecursive' : 'deletecalendarconfirm', 'calendar'))) {
rcmail.http_post('calendar', { action:'delete', c:{ id:calendar.id } });
return true;
}
return false;
};
this.calendar_destroy_source = function(id)
{
var delete_ids = [];
if (this.calendars[id]) {
// find sub-calendars
if (this.calendars[id].children) {
for (var child_id in this.calendars) {
if (String(child_id).indexOf(id) == 0)
delete_ids.push(child_id);
}
}
else {
delete_ids.push(id);
}
}
// delete all calendars in the list
for (var i=0; i < delete_ids.length; i++) {
id = delete_ids[i];
calendars_list.remove(id);
fc.fullCalendar('removeEventSource', this.calendars[id]);
$('#edit-calendar option[value="'+id+'"]').remove();
delete this.calendars[id];
}
};
// open a dialog to upload an .ics file with events to be imported
this.import_events = function(calendar)
{
// close show dialog first
var $dialog = $("#eventsimport"),
form = rcmail.gui_objects.importform;
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
if (calendar)
$('#event-import-calendar').val(calendar.id);
var buttons = {};
buttons[rcmail.gettext('import', 'calendar')] = function() {
if (form && form.elements._data.value) {
rcmail.async_upload_form(form, 'import_events', function(e) {
rcmail.set_busy(false, null, me.saving_lock);
$('.ui-dialog-buttonpane button', $dialog.parent()).button('enable');
// display error message if no sophisticated response from server arrived (e.g. iframe load error)
if (me.import_succeeded === null)
rcmail.display_message(rcmail.get_label('importerror', 'calendar'), 'error');
});
// display upload indicator (with extended timeout)
var timeout = rcmail.env.request_timeout;
rcmail.env.request_timeout = 600;
me.import_succeeded = null;
me.saving_lock = rcmail.set_busy(true, 'uploading');
$('.ui-dialog-buttonpane button', $dialog.parent()).button('disable');
// restore settings
rcmail.env.request_timeout = timeout;
}
};
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
$dialog.dialog("close");
};
// open jquery UI dialog
$dialog.dialog({
modal: true,
resizable: false,
closeOnEscape: false,
title: rcmail.gettext('importevents', 'calendar'),
open: function() {
$dialog.parent().find('.ui-dialog-buttonset .ui-button').first().addClass('mainaction');
},
close: function() {
$('.ui-dialog-buttonpane button', $dialog.parent()).button('enable');
$dialog.dialog("destroy").hide();
},
buttons: buttons,
width: 520
}).show();
};
// callback from server if import succeeded
this.import_success = function(p)
{
this.import_succeeded = true;
$("#eventsimport:ui-dialog").dialog('close');
rcmail.set_busy(false, null, me.saving_lock);
rcmail.gui_objects.importform.reset();
if (p.refetch)
this.refresh(p);
};
// callback from server to report errors on import
this.import_error = function(p)
{
this.import_succeeded = false;
rcmail.set_busy(false, null, me.saving_lock);
rcmail.display_message(p.message || rcmail.get_label('importerror', 'calendar'), 'error');
}
// open a dialog to select calendars for export
this.export_events = function(calendar)
{
// close show dialog first
var $dialog = $("#eventsexport"),
form = rcmail.gui_objects.exportform;
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
if (calendar)
$('#event-export-calendar').val(calendar.id);
$('#event-export-range').change(function(e){
var custom = $('option:selected', this).val() == 'custom',
input = $('#event-export-startdate')
input.parent()[(custom?'show':'hide')]();
if (custom)
input.select();
})
var buttons = {};
buttons[rcmail.gettext('export', 'calendar')] = function() {
if (form) {
var start = 0, range = $('#event-export-range option:selected', this).val(),
source = $('#event-export-calendar option:selected').val(),
attachmt = $('#event-export-attachments').get(0).checked;
if (range == 'custom')
start = date2unixtime(parse_datetime('00:00', $('#event-export-startdate').val()));
else if (range > 0)
start = 'today -' + range + ' months';
rcmail.goto_url('export_events', { source:source, start:start, attachments:attachmt?1:0 });
}
};
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
$dialog.dialog("close");
};
// open jquery UI dialog
$dialog.dialog({
modal: true,
resizable: false,
closeOnEscape: false,
title: rcmail.gettext('exporttitle', 'calendar'),
open: function() {
$dialog.parent().find('.ui-dialog-buttonset .ui-button').first().addClass('mainaction');
},
close: function() {
$('.ui-dialog-buttonpane button', $dialog.parent()).button('enable');
$dialog.dialog("destroy").hide();
},
buttons: buttons,
width: 520
}).show();
};
// download the selected event as iCal
this.event_download = function(event)
{
if (event && event.id) {
rcmail.goto_url('export_events', { source:event.calendar, id:event.id, attachments:1 });
}
};
// open the message compose step with a calendar_event parameter referencing the selected event.
// the server-side plugin hook will pick that up and attach the event to the message.
this.event_sendbymail = function(event, e)
{
if (event && event.id) {
rcmail.command('compose', { _calendar_event:event._id }, e ? e.target : null, e);
}
};
// show URL of the given calendar in a dialog box
this.showurl = function(calendar)
{
var $dialog = $('#calendarurlbox');
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
if (calendar.feedurl) {
if (calendar.caldavurl) {
$('#caldavurl').val(calendar.caldavurl);
$('#calendarcaldavurl').show();
}
else {
$('#calendarcaldavurl').hide();
}
$dialog.dialog({
resizable: true,
closeOnEscape: true,
title: rcmail.gettext('showurl', 'calendar'),
close: function() {
$dialog.dialog("destroy").hide();
},
width: 520
}).show();
$('#calfeedurl').val(calendar.feedurl).select();
}
};
// refresh the calendar view after saving event data
this.refresh = function(p)
{
var source = me.calendars[p.source];
// helper function to update the given fullcalendar view
function update_view(view, event, source) {
var existing = view.fullCalendar('clientEvents', event._id);
if (existing.length) {
$.extend(existing[0], event);
view.fullCalendar('updateEvent', existing[0]);
// remove old recurrence instances
if (event.recurrence && !event.recurrence_id)
view.fullCalendar('removeEvents', function(e){ return e._id.indexOf(event._id+'-') == 0; });
}
else {
event.source = source; // link with source
view.fullCalendar('renderEvent', event);
}
}
// remove temp events
fc.fullCalendar('removeEvents', function(e){ return e.temp; });
if (source && (p.refetch || (p.update && !source.active))) {
// activate event source if new event was added to an invisible calendar
if (this.quickview_active) {
// map source to the quickview_sources equivalent
$.each(this.quickview_sources, function(src) {
if (src.id == source.id) {
source = src;
return false;
}
});
fc.fullCalendar('refetchEvents', source, true);
}
else if (!source.active) {
source.active = true;
fc.fullCalendar('addEventSource', source);
$('#rcmlical' + source.id + ' input').prop('checked', true);
}
else
fc.fullCalendar('refetchEvents', source, true);
fetch_counts();
}
// add/update single event object
else if (source && p.update) {
var event = p.update;
event.temp = false;
event.editable = 0;
// update fish-eye view
if (this.fisheye_date)
update_view($('#fish-eye-view'), event, source);
// update main view
event.editable = source.editable;
update_view(fc, event, source);
// update the currently displayed event dialog
if ($('#eventshow').is(':visible') && me.selected_event && me.selected_event.id == event.id)
event_show_dialog(event)
}
// refetch all calendars
else if (p.refetch) {
fc.fullCalendar('refetchEvents', undefined, true);
fetch_counts();
}
};
// modify query parameters for refresh requests
this.before_refresh = function(query)
{
var view = fc.fullCalendar('getView');
query.start = date2unixtime(view.visStart);
query.end = date2unixtime(view.visEnd);
if (this.search_query)
query.q = this.search_query;
return query;
};
// callback from server providing event counts
this.update_counts = function(p)
{
$.each(p.counts, function(cal, count) {
var li = calendars_list.get_item(cal),
bubble = $(li).children('.calendar').find('span.count');
if (!bubble.length && count > 0) {
bubble = $('<span>')
.addClass('count')
.appendTo($(li).children('.calendar').first())
}
if (count > 0) {
bubble.text(count).show();
}
else {
bubble.text('').hide();
}
});
};
// callback after an iTip message event was imported
this.itip_message_processed = function(data)
{
// remove temporary iTip source
fc.fullCalendar('removeEventSource', this.calendars['--invitation--itip']);
$('#eventshow:ui-dialog').dialog('close');
this.selected_event = null;
// refresh destination calendar source
this.refresh({ source:data.calendar, refetch:true });
this.unlock_saving();
// process 'after_action' in mail task
if (window.opener && window.opener.rcube_libcalendaring)
window.opener.rcube_libcalendaring.itip_message_processed(data);
};
// reload the calendar view by keeping the current date/view selection
this.reload_view = function()
{
var query = { view: fc.fullCalendar('getView').name },
date = fc.fullCalendar('getDate');
if (date)
query.date = date2unixtime(date);
rcmail.redirect(rcmail.url('', query));
}
// update browser location to remember current view
this.update_state = function()
{
var query = { view: current_view },
date = fc.fullCalendar('getDate');
if (date)
query.date = date2unixtime(date);
if (window.history.replaceState)
window.history.replaceState({}, document.title, rcmail.url('', query).replace('&_action=', ''));
};
this.resource_search = resource_search;
this.reset_resource_search = reset_resource_search;
this.add_resource2event = add_resource2event;
this.resource_data_load = resource_data_load;
this.resource_owner_load = resource_owner_load;
/*** event searching ***/
// execute search
this.quicksearch = function()
{
if (rcmail.gui_objects.qsearchbox) {
var q = rcmail.gui_objects.qsearchbox.value;
if (q != '') {
var id = 'search-'+q;
var sources = [];
if (me.quickview_active)
reset_quickview();
if (this._search_message)
rcmail.hide_message(this._search_message);
for (var sid in this.calendars) {
if (this.calendars[sid]) {
this.calendars[sid].url = this.calendars[sid].url.replace(/&q=.+/, '') + '&q=' + urlencode(q);
sources.push(sid);
}
}
id += '@'+sources.join(',');
// ignore if query didn't change
if (this.search_request == id) {
return;
}
// remember current view
else if (!this.search_request) {
this.default_view = fc.fullCalendar('getView').name;
}
this.search_request = id;
this.search_query = q;
// change to list view
fc.fullCalendar('option', 'listSections', 'month')
.fullCalendar('option', 'listRange', Math.max(60, settings['agenda_range']))
.fullCalendar('changeView', 'table');
update_agenda_toolbar();
// refetch events with new url (if not already triggered by changeView)
if (!this.is_loading)
fc.fullCalendar('refetchEvents');
}
else // empty search input equals reset
this.reset_quicksearch();
}
};
// reset search and get back to normal event listing
this.reset_quicksearch = function()
{
$(rcmail.gui_objects.qsearchbox).val('');
if (this._search_message)
rcmail.hide_message(this._search_message);
if (this.search_request) {
// hide bottom links of agenda view
fc.find('.fc-list-content > .fc-listappend').hide();
// restore original event sources and view mode from fullcalendar
fc.fullCalendar('option', 'listSections', settings['agenda_sections'])
.fullCalendar('option', 'listRange', settings['agenda_range']);
update_agenda_toolbar();
for (var sid in this.calendars) {
if (this.calendars[sid])
this.calendars[sid].url = this.calendars[sid].url.replace(/&q=.+/, '');
}
if (this.default_view)
fc.fullCalendar('changeView', this.default_view);
if (!this.is_loading)
fc.fullCalendar('refetchEvents');
this.search_request = this.search_query = null;
}
};
// callback if all sources have been fetched from server
this.events_loaded = function(count)
{
var addlinks, append = '';
// enhance list view when searching
if (this.search_request) {
if (!count) {
this._search_message = rcmail.display_message(rcmail.gettext('searchnoresults', 'calendar'), 'notice');
append = '<div class="message">' + rcmail.gettext('searchnoresults', 'calendar') + '</div>';
}
append += '<div class="fc-bottomlinks formlinks"></div>';
addlinks = true;
}
if (fc.fullCalendar('getView').name == 'table') {
var container = fc.find('.fc-list-content > .fc-listappend');
if (append) {
if (!container.length)
container = $('<div class="fc-listappend"></div>').appendTo(fc.find('.fc-list-content'));
container.html(append).show();
}
else if (container.length)
container.hide();
// add links to adjust search date range
if (addlinks) {
var lc = container.find('.fc-bottomlinks');
$('<a>').attr('href', '#').html(rcmail.gettext('searchearlierdates', 'calendar')).appendTo(lc).click(function(){
fc.fullCalendar('incrementDate', 0, -1, 0);
});
lc.append(" ");
$('<a>').attr('href', '#').html(rcmail.gettext('searchlaterdates', 'calendar')).appendTo(lc).click(function(){
var range = fc.fullCalendar('option', 'listRange');
if (range < 90) {
fc.fullCalendar('option', 'listRange', fc.fullCalendar('option', 'listRange') + 30).fullCalendar('render');
update_agenda_toolbar();
}
else
fc.fullCalendar('incrementDate', 0, 1, 0);
});
}
}
if (this.fisheye_date)
this.fisheye_view(this.fisheye_date);
};
// resize and reposition (center) the dialog window
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 (!?)
};
// adjust calendar view size
this.view_resize = function()
{
var footer = fc.fullCalendar('getView').name == 'table' ? $('#agendaoptions').outerHeight() : 0;
fc.fullCalendar('option', 'height', $('#calendar').height() - footer);
};
// mark the given calendar folder as selected
this.select_calendar = function(id, nolistupdate)
{
if (!nolistupdate)
calendars_list.select(id);
// trigger event hook
rcmail.triggerEvent('selectfolder', { folder:id, prefix:'rcmlical' });
this.selected_calendar = id;
};
// register the given calendar to the current view
var add_calendar_source = function(cal)
{
var color, brightness, select, id = cal.id;
me.calendars[id] = $.extend({
url: rcmail.url('calendar/load_events', { source: id }),
className: 'fc-event-cal-'+id,
id: id
}, cal);
// choose black text color when background is bright, white otherwise
if (color = settings.event_coloring % 2 ? '' : '#' + cal.color) {
if (/^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i.test(color)) {
// use information about brightness calculation found at
// http://javascriptrules.com/2009/08/05/css-color-brightness-contrast-using-javascript/
brightness = (parseInt(RegExp.$1, 16) * 299 + parseInt(RegExp.$2, 16) * 587 + parseInt(RegExp.$3, 16) * 114) / 1000;
if (brightness > 125)
me.calendars[id].textColor = 'black';
}
me.calendars[id].color = color;
}
if (fc && (cal.active || cal.subscribed)) {
if (cal.active)
fc.fullCalendar('addEventSource', me.calendars[id]);
var submit = { id: id, active: cal.active ? 1 : 0 };
if (cal.subscribed !== undefined)
submit.permanent = cal.subscribed ? 1 : 0;
rcmail.http_post('calendar', { action:'subscribe', c:submit });
}
// insert to #calendar-select options if writeable
select = $('#edit-calendar');
if (fc && has_permission(cal, 'i') && select.length && !select.find('option[value="'+id+'"]').length) {
$('<option>').attr('value', id).html(cal.name).appendTo(select);
}
}
// fetch counts for some calendars from the server
var fetch_counts = function()
{
if (count_sources.length) {
setTimeout(function() {
rcmail.http_request('calendar/count', { source:count_sources });
}, 500);
}
};
/*** startup code ***/
// create list of event sources AKA calendars
var id, cal, active, event_sources = [];
for (id in rcmail.env.calendars) {
cal = rcmail.env.calendars[id];
active = cal.active || false;
add_calendar_source(cal);
// check active calendars
$('#rcmlical'+id+' > .calendar input').prop('checked', active);
if (active) {
event_sources.push(this.calendars[id]);
}
if (cal.counts) {
count_sources.push(id);
}
if (cal.editable && !this.selected_calendar) {
this.selected_calendar = id;
rcmail.enable_command('addevent', true);
}
}
// initialize treelist widget that controls the calendars list
var widget_class = window.kolab_folderlist || rcube_treelist_widget;
calendars_list = new widget_class(rcmail.gui_objects.calendarslist, {
id_prefix: 'rcmlical',
selectable: true,
save_state: true,
keyboard: false,
searchbox: '#calendarlistsearch',
search_action: 'calendar/calendar',
search_sources: [ 'folders', 'users' ],
search_title: rcmail.gettext('calsearchresults','calendar')
});
calendars_list.addEventListener('select', function(node) {
if (node && node.id && me.calendars[node.id]) {
me.select_calendar(node.id, true);
rcmail.enable_command('calendar-edit', 'calendar-showurl', true);
rcmail.enable_command('calendar-delete', me.calendars[node.id].editable);
rcmail.enable_command('calendar-remove', me.calendars[node.id] && me.calendars[node.id].removable);
}
});
calendars_list.addEventListener('insert-item', function(p) {
var cal = p.data;
if (cal && cal.id) {
add_calendar_source(cal);
// add css classes related to this calendar to document
if (cal.css) {
$('<style type="text/css"></style>')
.html(cal.css)
.appendTo('head');
}
}
});
calendars_list.addEventListener('subscribe', function(p) {
var cal;
if ((cal = me.calendars[p.id])) {
cal.subscribed = p.subscribed || false;
rcmail.http_post('calendar', { action:'subscribe', c:{ id:p.id, active:cal.active?1:0, permanent:cal.subscribed?1:0 } });
}
});
calendars_list.addEventListener('remove', function(p) {
if (me.calendars[p.id] && me.calendars[p.id].removable) {
me.calendar_remove(me.calendars[p.id]);
}
});
calendars_list.addEventListener('search-complete', function(data) {
if (data.length)
rcmail.display_message(rcmail.gettext('nrcalendarsfound','calendar').replace('$nr', data.length), 'voice');
else
rcmail.display_message(rcmail.gettext('nocalendarsfound','calendar'), 'info');
});
calendars_list.addEventListener('click-item', function(event) {
// handle clicks on quickview icon: temprarily add this source and open in quickview
if ($(event.target).hasClass('quickview') && event.data) {
if (!me.calendars[event.data.id]) {
event.data.readonly = true;
event.data.active = false;
event.data.subscribed = false;
add_calendar_source(event.data);
}
me.quickview(event.data.id, event.shiftKey || event.metaKey || event.ctrlKey);
return false;
}
});
// init (delegate) event handler on calendar list checkboxes
$(rcmail.gui_objects.calendarslist).on('click', 'input[type=checkbox]', function(e) {
e.stopPropagation();
if (me.quickview_active) {
this.checked = !this.checked;
return false;
}
var id = this.value;
if (me.calendars[id]) { // add or remove event source on click
var action;
if (this.checked) {
action = 'addEventSource';
me.calendars[id].active = true;
}
else {
action = 'removeEventSource';
me.calendars[id].active = false;
}
// adjust checked state of original list item
if (calendars_list.is_search()) {
calendars_list.container.find('input[value="'+id+'"]').prop('checked', this.checked);
}
// add/remove event source
fc.fullCalendar(action, me.calendars[id]);
rcmail.http_post('calendar', { action:'subscribe', c:{ id:id, active:me.calendars[id].active?1:0 } });
}
})
.on('keypress', 'input[type=checkbox]', function(e) {
// select calendar on <Enter>
if (e.keyCode == 13) {
calendars_list.select(this.value);
return rcube_event.cancel(e);
}
})
// init (delegate) event handler on quickview links
.on('click', 'a.quickview', function(e) {
var id = $(this).closest('li').attr('id').replace(/^rcmlical/, '');
if (calendars_list.is_search())
id = id.replace(/--xsR$/, '');
if (me.calendars[id])
me.quickview(id, e.shiftKey || e.metaKey || e.ctrlKey);
if (!rcube_event.is_keyboard(e) && this.blur)
this.blur();
e.stopPropagation();
return false;
});
// register dbl-click handler to open calendar edit dialog
$(rcmail.gui_objects.calendarslist).on('dblclick', ':not(.virtual) > .calname', function(e){
var id = $(this).closest('li').attr('id').replace(/^rcmlical/, '');
me.calendar_edit_dialog(me.calendars[id]);
});
// select default calendar
if (settings.default_calendar && this.calendars[settings.default_calendar] && this.calendars[settings.default_calendar].editable)
this.selected_calendar = settings.default_calendar;
if (this.selected_calendar)
this.select_calendar(this.selected_calendar);
var viewdate = new Date();
if (rcmail.env.date)
viewdate.setTime(fromunixtime(rcmail.env.date));
// add source with iTip event data for rendering
if (rcmail.env.itip_events && rcmail.env.itip_events.length) {
me.calendars['--invitation--itip'] = {
events: rcmail.env.itip_events,
className: 'fc-event-cal---invitation--itip',
color: '#fff',
textColor: '#333',
editable: false,
rights: 'lrs',
attendees: true
};
event_sources.push(me.calendars['--invitation--itip']);
}
// initalize the fullCalendar plugin
var fc = $('#calendar').fullCalendar($.extend({}, fullcalendar_defaults, {
header: {
right: 'prev,next today',
center: 'title',
left: 'agendaDay,agendaWeek,month,table'
},
date: viewdate.getDate(),
month: viewdate.getMonth(),
year: viewdate.getFullYear(),
height: $('#calendar').height(),
eventSources: event_sources,
selectable: true,
selectHelper: false,
loading: function(isLoading) {
me.is_loading = isLoading;
this._rc_loading = rcmail.set_busy(isLoading, 'loading', this._rc_loading);
// trigger callback
if (!isLoading)
me.events_loaded($(this).fullCalendar('clientEvents').length);
},
// callback for date range selection
select: function(start, end, allDay, e, view) {
var range_select = (!allDay || start.getDate() != end.getDate())
if (dialog_check(e) && range_select)
event_edit_dialog('new', { start:start, end:end, allDay:allDay, calendar:me.selected_calendar });
if (range_select || ignore_click)
view.calendar.unselect();
},
// callback for clicks in all-day box
dayClick: function(date, allDay, e, view) {
var now = new Date().getTime();
if (now - day_clicked_ts < 400 && day_clicked == date.getTime()) { // emulate double-click on day
var enddate = new Date(); enddate.setTime(date.getTime() + DAY_MS - 60000);
return event_edit_dialog('new', { start:date, end:enddate, allDay:allDay, calendar:me.selected_calendar });
}
if (!ignore_click) {
view.calendar.gotoDate(date);
if (day_clicked && new Date(day_clicked).getMonth() != date.getMonth())
view.calendar.select(date, date, allDay);
}
day_clicked = date.getTime();
day_clicked_ts = now;
},
// callback when an event was dragged and finally dropped
eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc) {
if (event.end == null || event.end.getTime() < event.start.getTime()) {
event.end = new Date(event.start.getTime() + (allDay ? DAY_MS : HOUR_MS));
}
// moved to all-day section: set times to 12:00 - 13:00
if (allDay && !event.allDay) {
event.start.setHours(12);
event.start.setMinutes(0);
event.start.setSeconds(0);
event.end.setHours(13);
event.end.setMinutes(0);
event.end.setSeconds(0);
}
// moved from all-day section: set times to working hours
else if (event.allDay && !allDay) {
var newstart = event.start.getTime();
revertFunc(); // revert to get original duration
var numdays = Math.max(1, Math.round((event.end.getTime() - event.start.getTime()) / DAY_MS)) - 1;
event.start = new Date(newstart);
event.end = new Date(newstart + numdays * DAY_MS);
event.end.setHours(settings['work_end'] || 18);
event.end.setMinutes(0);
if (event.end.getTime() < event.start.getTime())
event.end = new Date(newstart + HOUR_MS);
}
// send move request to server
var data = {
id: event.id,
calendar: event.calendar,
start: date2servertime(event.start),
end: date2servertime(event.end),
allday: allDay?1:0
};
update_event_confirm('move', event, data);
},
// callback for event resizing
eventResize: function(event, delta) {
// sanitize event dates
if (event.allDay)
event.start.setHours(12);
if (!event.end || event.end.getTime() < event.start.getTime())
event.end = new Date(event.start.getTime() + HOUR_MS);
// send resize request to server
var data = {
id: event.id,
calendar: event.calendar,
start: date2servertime(event.start),
end: date2servertime(event.end)
};
update_event_confirm('resize', event, data);
},
viewDisplay: function(view) {
$('#agendaoptions')[view.name == 'table' ? 'show' : 'hide']();
if (minical) {
window.setTimeout(function(){ minical.datepicker('setDate', fc.fullCalendar('getDate')); }, exec_deferred);
if (view.name != current_view)
me.view_resize();
current_view = view.name;
me.update_state();
}
},
viewRender: function(view) {
if (fc && view.name == 'month')
fc.fullCalendar('option', 'maxHeight', Math.floor((view.element.parent().height()-18) / 6) - 35);
}
}));
// 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);
var newend = new Date(newstart.getTime() + $('#edit-startdate').data('duration') * 1000);
$('#edit-enddate').val($.fullCalendar.formatDate(newend, me.settings['date_format']));
event_times_changed();
};
// Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
// Uses the default $.datepicker.iso8601Week() function but takes firstDay setting into account.
// This is a temporary fix until http://bugs.jqueryui.com/ticket/8420 is resolved.
var iso8601Week = datepicker_settings.calculateWeek = function(date) {
var mondayOffset = Math.abs(1 - datepicker_settings.firstDay);
return $.datepicker.iso8601Week(new Date(date.getTime() + mondayOffset * 86400000));
};
var minical;
var init_calendar_ui = function()
{
// initialize small calendar widget using jQuery UI datepicker
minical = $('#datepicker').datepicker($.extend(datepicker_settings, {
inline: true,
showWeek: true,
changeMonth: true,
changeYear: true,
onSelect: function(dateText, inst) {
ignore_click = true;
var d = minical.datepicker('getDate'); //parse_datetime('0:0', dateText);
fc.fullCalendar('gotoDate', d).fullCalendar('select', d, d, true);
},
onChangeMonthYear: function(year, month, inst) {
minical.data('year', year).data('month', month);
},
beforeShowDay: function(date) {
var view = fc.fullCalendar('getView');
var active = view.visStart && date.getTime() >= view.visStart.getTime() && date.getTime() < view.visEnd.getTime();
return [ true, (active ? 'ui-datepicker-activerange ui-datepicker-active-' + view.name : ''), ''];
}
})) // set event handler for clicks on calendar week cell of the datepicker widget
.on('click', 'td.ui-datepicker-week-col', function(e) {
var cell = $(e.target);
if (e.target.tagName == 'TD') {
var base_date = minical.datepicker('getDate');
if (minical.data('month'))
base_date.setMonth(minical.data('month')-1);
if (minical.data('year'))
base_date.setYear(minical.data('year'));
base_date.setHours(12);
base_date.setDate(base_date.getDate() - ((base_date.getDay() + 6) % 7) + datepicker_settings.firstDay);
var base_kw = iso8601Week(base_date),
target_kw = parseInt(cell.html()),
wdiff = target_kw - base_kw;
if (wdiff > 10) // year jump
base_date.setYear(base_date.getFullYear() - 1);
else if (wdiff < -10)
base_date.setYear(base_date.getFullYear() + 1);
// select monday of the chosen calendar week
var day_off = base_date.getDay() - datepicker_settings.firstDay,
date = new Date(base_date.getTime() - day_off * DAY_MS + wdiff * 7 * DAY_MS);
fc.fullCalendar('gotoDate', date).fullCalendar('setDate', date).fullCalendar('changeView', 'agendaWeek');
minical.datepicker('setDate', date);
}
});
minical.find('.ui-datepicker-inline').attr('aria-labelledby', 'aria-label-minical');
if (rcmail.env.date) {
var viewdate = new Date();
viewdate.setTime(fromunixtime(rcmail.env.date));
minical.datepicker('setDate', viewdate);
}
// 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';
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) {
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();
}
}
});
$('#edit-enddate').datepicker(datepicker_settings);
$('#edit-startdate').datepicker(datepicker_settings).datepicker('option', 'onSelect', shift_enddate).change(function(){ shift_enddate(this.value); });
$('#edit-enddate').datepicker('option', 'onSelect', event_times_changed).change(event_times_changed);
$('#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);
};
});
// adjust end time when changing start
$('#edit-starttime').change(function(e) {
var dstart = $('#edit-startdate'),
newstart = parse_datetime(this.value, dstart.val()),
newend = new Date(newstart.getTime() + dstart.data('duration') * 1000);
$('#edit-endtime').val($.fullCalendar.formatDate(newend, me.settings['time_format']));
$('#edit-enddate').val($.fullCalendar.formatDate(newend, me.settings['date_format']));
event_times_changed();
});
// register events on alarms and recurrence fields
me.init_alarms_edit('#edit-alarms');
me.init_recurrence_edit('#eventedit');
// reload free-busy status when changing the organizer identity
$('#eventedit').on('change', '#edit-identities-list', function(e) {
var email = settings.identities[$(this).val()],
icon = $(this).closest('tr').find('img.availabilityicon');
if (email && icon.length) {
icon.attr('data-email', email);
check_freebusy_status(icon, email, me.selected_event);
}
});
$('#event-export-startdate').datepicker(datepicker_settings);
// init attendees autocompletion
var ac_props;
// parallel autocompletion
if (rcmail.env.autocomplete_threads > 0) {
ac_props = {
threads: rcmail.env.autocomplete_threads,
sources: rcmail.env.autocomplete_sources
};
}
rcmail.init_address_input_events($('#edit-attendee-name'), ac_props);
rcmail.addEventListener('autocomplete_insert', function(e) {
var success = false;
if (e.field.name == 'participant') {
success = add_attendees(e.insert, { role:'REQ-PARTICIPANT', status:'NEEDS-ACTION', cutype:(e.data && e.data.type == 'group' ? 'GROUP' : 'INDIVIDUAL') });
}
else if (e.field.name == 'resource' && e.data && e.data.email) {
success = add_attendee($.extend(e.data, { role:'REQ-PARTICIPANT', status:'NEEDS-ACTION', cutype:'RESOURCE' }));
}
if (e.field && success) {
e.field.value = '';
}
});
$('#edit-attendee-add').click(function(){
var input = $('#edit-attendee-name');
rcmail.ksearch_blur();
if (add_attendees(input.val(), { role:'REQ-PARTICIPANT', status:'NEEDS-ACTION', cutype:'INDIVIDUAL' })) {
input.val('');
}
});
rcmail.init_address_input_events($('#edit-resource-name'), { action:'calendar/resources-autocomplete' });
$('#edit-resource-add').click(function(){
var input = $('#edit-resource-name');
rcmail.ksearch_blur();
if (add_attendees(input.val(), { role:'REQ-PARTICIPANT', status:'NEEDS-ACTION', cutype:'RESOURCE' })) {
input.val('');
}
});
$('#edit-resource-find').click(function(){
event_resources_dialog();
return false;
});
// handle change of "send invitations" checkbox
$('#edit-attendees-invite').change(function() {
$('#edit-attendees-donotify,input.edit-attendee-reply').prop('checked', this.checked);
// hide/show comment field
$('#eventedit .attendees-commentbox')[this.checked ? 'show' : 'hide']();
});
// delegate change event to "send invitations" checkbox
$('#edit-attendees-donotify').change(function() {
$('#edit-attendees-invite').click();
return false;
});
$('#edit-attendee-schedule').click(function(){
event_freebusy_dialog();
});
$('#shedule-freebusy-prev').html(bw.ie6 ? '&lt;&lt;' : '&#9668;').button().click(function(){ render_freebusy_grid(-1); });
$('#shedule-freebusy-next').html(bw.ie6 ? '&gt;&gt;' : '&#9658;').button().click(function(){ render_freebusy_grid(1); }).parent().buttonset();
$('#shedule-find-prev').button().click(function(){ freebusy_find_slot(-1); });
$('#shedule-find-next').button().click(function(){ freebusy_find_slot(1); });
$('#schedule-freebusy-workinghours').click(function(){
freebusy_ui.workinhoursonly = this.checked;
$('#workinghourscss').remove();
if (this.checked)
$('<style type="text/css" id="workinghourscss"> td.offhours { opacity:0.3; filter:alpha(opacity=30) } </style>').appendTo('head');
});
$('#event-rsvp input.button').click(function(e) {
event_rsvp(this)
});
$('#eventedit input.edit-recurring-savemode').change(function(e) {
var sel = $('input.edit-recurring-savemode:checked').val(),
disabled = sel == 'current' || sel == 'future';
$('#event-panel-recurrence input, #event-panel-recurrence select, #event-panel-attachments input').prop('disabled', disabled);
$('#event-panel-recurrence, #event-panel-attachments')[(disabled?'addClass':'removeClass')]('disabled');
})
$('#eventshow .changersvp').click(function(e) {
var d = $('#eventshow'),
h = -$(this).closest('.event-line').toggle().height();
$('#event-rsvp').slideDown(300, function() {
h += $(this).height();
me.dialog_resize(d.get(0), d.height() + h, d.outerWidth() - 50);
});
return false;
})
// register click handler for message links
$('#edit-event-links, #event-links').on('click', 'li a.messagelink', function(e) {
rcmail.open_window(this.href);
if (!rcube_event.is_keyboard(e) && this.blur)
this.blur();
return false;
});
// register click handler for message delete buttons
$('#edit-event-links').on('click', 'li a.delete', function(e) {
remove_link(e.target);
return false;
});
$('#agenda-listrange').change(function(e){
settings['agenda_range'] = parseInt($(this).val());
fc.fullCalendar('option', 'listRange', settings['agenda_range']).fullCalendar('render');
// TODO: save new settings in prefs
}).val(settings['agenda_range']);
$('#agenda-listsections').change(function(e){
settings['agenda_sections'] = $(this).val();
fc.fullCalendar('option', 'listSections', settings['agenda_sections']).fullCalendar('render');
// TODO: save new settings in prefs
}).val(fc.fullCalendar('option', 'listSections'));
// hide event dialog when clicking somewhere into document
$(document).bind('mousedown', dialog_check);
rcmail.set_busy(false, 'loading', ui_loading);
}
// initialize more UI elements (deferred)
window.setTimeout(init_calendar_ui, exec_deferred);
// fetch counts for some calendars
fetch_counts();
// add proprietary css styles if not IE
if (!bw.ie)
$('div.fc-content').addClass('rcube-fc-content');
// IE supresses 2nd click event when double-clicking
if (bw.ie && bw.vendver < 9) {
$('div.fc-content').bind('dblclick', function(e){
if (!$(this).hasClass('fc-widget-header') && fc.fullCalendar('getView').name != 'table') {
var date = fc.fullCalendar('getDate');
var enddate = new Date(); enddate.setTime(date.getTime() + DAY_MS - 60000);
event_edit_dialog('new', { start:date, end:enddate, allDay:true, calendar:me.selected_calendar });
}
});
}
} // end rcube_calendar class
/* calendar plugin initialization */
window.rcmail && rcmail.addEventListener('init', function(evt) {
// configure toolbar buttons
rcmail.register_command('addevent', function(){ cal.add_event(); }, true);
rcmail.register_command('print', function(){ cal.print_calendars(); }, true);
// configure list operations
rcmail.register_command('calendar-create', function(){ cal.calendar_edit_dialog(null); }, true);
rcmail.register_command('calendar-edit', function(){ cal.calendar_edit_dialog(cal.calendars[cal.selected_calendar]); }, false);
rcmail.register_command('calendar-remove', function(){ cal.calendar_remove(cal.calendars[cal.selected_calendar]); }, false);
rcmail.register_command('calendar-delete', function(){ cal.calendar_delete(cal.calendars[cal.selected_calendar]); }, false);
rcmail.register_command('events-import', function(){ cal.import_events(cal.calendars[cal.selected_calendar]); }, true);
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-history', function(p, obj, e){ cal.event_history_dialog(cal.selected_event); }, false);
// search and export events
rcmail.register_command('export', function(){ cal.export_events(cal.calendars[cal.selected_calendar]); }, true);
rcmail.register_command('search', function(){ cal.quicksearch(); }, true);
rcmail.register_command('reset-search', function(){ cal.reset_quicksearch(); }, true);
// resource invitation dialog
rcmail.register_command('search-resource', function(){ cal.resource_search(); }, true);
rcmail.register_command('reset-resource-search', function(){ cal.reset_resource_search(); }, true);
rcmail.register_command('add-resource', function(){ cal.add_resource2event(); }, false);
// register callback commands
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); });
rcmail.addEventListener('plugin.import_success', function(p){ cal.import_success(p); });
rcmail.addEventListener('plugin.import_error', function(p){ cal.import_error(p); });
rcmail.addEventListener('plugin.update_counts', function(p){ cal.update_counts(p); });
rcmail.addEventListener('plugin.reload_view', function(p){ cal.reload_view(p); });
rcmail.addEventListener('plugin.resource_data', function(p){ cal.resource_data_load(p); });
rcmail.addEventListener('plugin.resource_owner', function(p){ cal.resource_owner_load(p); });
rcmail.addEventListener('plugin.render_event_changelog', function(data){ cal.render_event_changelog(data); });
rcmail.addEventListener('plugin.event_show_diff', function(data){ cal.event_show_diff(data); });
rcmail.addEventListener('plugin.close_history_dialog', function(data){ cal.close_history_dialog(); });
rcmail.addEventListener('plugin.event_show_revision', function(data){ cal.event_show_dialog(data, null, true); });
rcmail.addEventListener('plugin.itip_message_processed', function(data){ cal.itip_message_processed(data); });
rcmail.addEventListener('requestrefresh', function(q){ return cal.before_refresh(q); });
// let's go
var cal = new rcube_calendar_ui($.extend(rcmail.env.calendar_settings, rcmail.env.libcal_settings));
$(window).resize(function(e) {
// check target due to bugs in jquery
// http://bugs.jqueryui.com/ticket/7514
// http://bugs.jquery.com/ticket/9841
if (e.target == window) {
cal.view_resize();
}
}).resize();
// show calendars list when ready
$('#calendars').css('visibility', 'inherit');
// show toolbar
$('#toolbar').show();
});
diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php
index 5a1f41e8..2912bdff 100644
--- a/plugins/calendar/lib/calendar_ui.php
+++ b/plugins/calendar/lib/calendar_ui.php
@@ -1,897 +1,881 @@
<?php
/**
* User Interface class for the Calendar plugin
*
* @author Lazlo Westerhof <hello@lazlo.me>
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2010, Lazlo Westerhof <hello@lazlo.me>
* Copyright (C) 2014, 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
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class calendar_ui
{
private $rc;
private $cal;
private $ready = false;
public $screen;
function __construct($cal)
{
$this->cal = $cal;
$this->rc = $cal->rc;
$this->screen = $this->rc->task == 'calendar' ? ($this->rc->action ? $this->rc->action: 'calendar') : 'other';
}
/**
* Calendar UI initialization and requests handlers
*/
public function init()
{
if ($this->ready) // already done
return;
// add taskbar button
$this->cal->add_button(array(
'command' => 'calendar',
'class' => 'button-calendar',
'classsel' => 'button-calendar button-selected',
'innerclass' => 'button-inner',
'label' => 'calendar.calendar',
), 'taskbar');
// load basic client script
$this->cal->include_script('calendar_base.js');
$skin_path = $this->cal->local_skin_path();
$this->cal->include_stylesheet($skin_path . '/calendar.css');
$this->ready = true;
}
/**
* Register handler methods for the template engine
*/
public function init_templates()
{
$this->cal->register_handler('plugin.calendar_css', array($this, 'calendar_css'));
$this->cal->register_handler('plugin.calendar_list', array($this, 'calendar_list'));
$this->cal->register_handler('plugin.calendar_select', array($this, 'calendar_select'));
$this->cal->register_handler('plugin.identity_select', array($this, 'identity_select'));
$this->cal->register_handler('plugin.category_select', array($this, 'category_select'));
$this->cal->register_handler('plugin.status_select', array($this, 'status_select'));
$this->cal->register_handler('plugin.freebusy_select', array($this, 'freebusy_select'));
$this->cal->register_handler('plugin.priority_select', array($this, 'priority_select'));
$this->cal->register_handler('plugin.sensitivity_select', array($this, 'sensitivity_select'));
$this->cal->register_handler('plugin.alarm_select', array($this, 'alarm_select'));
$this->cal->register_handler('plugin.recurrence_form', array($this->cal->lib, 'recurrence_form'));
$this->cal->register_handler('plugin.attachments_form', array($this, 'attachments_form'));
$this->cal->register_handler('plugin.attachments_list', array($this, 'attachments_list'));
$this->cal->register_handler('plugin.filedroparea', array($this, 'file_drop_area'));
$this->cal->register_handler('plugin.attendees_list', array($this, 'attendees_list'));
$this->cal->register_handler('plugin.attendees_form', array($this, 'attendees_form'));
$this->cal->register_handler('plugin.resources_form', array($this, 'resources_form'));
$this->cal->register_handler('plugin.resources_list', array($this, 'resources_list'));
$this->cal->register_handler('plugin.resources_searchform', array($this, 'resources_search_form'));
$this->cal->register_handler('plugin.resource_info', array($this, 'resource_info'));
$this->cal->register_handler('plugin.resource_calendar', array($this, 'resource_calendar'));
$this->cal->register_handler('plugin.attendees_freebusy_table', array($this, 'attendees_freebusy_table'));
$this->cal->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify'));
$this->cal->register_handler('plugin.edit_recurring_warning', array($this, 'recurring_event_warning'));
$this->cal->register_handler('plugin.event_rsvp_buttons', array($this, 'event_rsvp_buttons'));
$this->cal->register_handler('plugin.angenda_options', array($this, 'angenda_options'));
$this->cal->register_handler('plugin.events_import_form', array($this, 'events_import_form'));
$this->cal->register_handler('plugin.events_export_form', array($this, 'events_export_form'));
- $this->cal->register_handler('plugin.event_changelog_table', array($this, 'event_changelog_table'));
+ $this->cal->register_handler('plugin.object_changelog_table', array('libkolab', 'object_changelog_table'));
$this->cal->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template
}
/**
* Adds CSS stylesheets to the page header
*/
public function addCSS()
{
$skin_path = $this->cal->local_skin_path();
$this->cal->include_stylesheet($skin_path . '/fullcalendar.css');
}
/**
* Adds JS files to the page header
*/
public function addJS()
{
$this->cal->include_script('calendar_ui.js');
$this->cal->include_script('lib/js/fullcalendar.js');
$this->rc->output->include_script('treelist.js');
// include kolab folderlist widget if available
if (in_array('libkolab', $this->cal->api->loaded_plugins())) {
$this->cal->api->include_script('libkolab/js/folderlist.js');
$this->cal->api->include_script('libkolab/js/audittrail.js');
}
jqueryui::miniColors();
}
/**
*
*/
function calendar_css($attrib = array())
{
$mode = $this->rc->config->get('calendar_event_coloring', $this->cal->defaults['calendar_event_coloring']);
$categories = $this->cal->driver->list_categories();
$css = "\n";
foreach ((array)$categories as $class => $color) {
if (empty($color))
continue;
$class = 'cat-' . asciiwords(strtolower($class), true);
$css .= ".$class { color: #$color }\n";
if ($mode > 0) {
if ($mode == 2) {
$css .= ".fc-event-$class .fc-event-bg {";
$css .= " opacity: 0.9;";
$css .= " filter: alpha(opacity=90);";
}
else {
$css .= ".fc-event-$class.fc-event-skin, ";
$css .= ".fc-event-$class .fc-event-skin, ";
$css .= ".fc-event-$class .fc-event-inner {";
}
$css .= " background-color: #" . $color . ";";
if ($mode % 2)
$css .= " border-color: #$color;";
$css .= "}\n";
}
}
$calendars = $this->cal->driver->list_calendars();
foreach ((array)$calendars as $id => $prop) {
if (!$prop['color'])
continue;
$css .= $this->calendar_css_classes($id, $prop, $mode);
}
return html::tag('style', array('type' => 'text/css'), $css);
}
/**
*
*/
public function calendar_css_classes($id, $prop, $mode)
{
$color = $prop['color'];
$class = 'cal-' . asciiwords($id, true);
$css .= "li .$class, #eventshow .$class { color: #$color }\n";
if ($mode != 1) {
if ($mode == 3) {
$css .= ".fc-event-$class .fc-event-bg {";
$css .= " opacity: 0.9;";
$css .= " filter: alpha(opacity=90);";
}
else {
$css .= ".fc-event-$class, ";
$css .= ".fc-event-$class .fc-event-inner {";
}
if (!$attrib['printmode'])
$css .= " background-color: #$color;";
if ($mode % 2 == 0)
$css .= " border-color: #$color;";
$css .= "}\n";
}
return $css . ".$class .handle { background-color: #$color; }\n";
}
/**
*
*/
function calendar_list($attrib = array())
{
$html = '';
$jsenv = array();
$tree = true;
$calendars = $this->cal->driver->list_calendars(0, $tree);
// walk folder tree
if (is_object($tree)) {
$html = $this->list_tree_html($tree, $calendars, $jsenv, $attrib);
// append birthdays calendar which isn't part of $tree
if ($bdaycal = $calendars[calendar_driver::BIRTHDAY_CALENDAR_ID]) {
$calendars = array(calendar_driver::BIRTHDAY_CALENDAR_ID => $bdaycal);
}
else {
$calendars = array(); // clear array for flat listing
}
}
else {
// fall-back to flat folder listing
$attrib['class'] .= ' flat';
}
foreach ((array)$calendars as $id => $prop) {
if ($attrib['activeonly'] && !$prop['active'])
continue;
$html .= html::tag('li', array('id' => 'rcmlical' . $id, 'class' => $prop['group']),
$content = $this->calendar_list_item($id, $prop, $jsenv, $attrib['activeonly'])
);
}
$this->rc->output->set_env('calendars', $jsenv);
$this->rc->output->add_gui_object('calendarslist', $attrib['id']);
return html::tag('ul', $attrib, $html, html::$common_attrib);
}
/**
* Return html for a structured list <ul> for the folder tree
*/
public function list_tree_html($node, $data, &$jsenv, $attrib)
{
$out = '';
foreach ($node->children as $folder) {
$id = $folder->id;
$prop = $data[$id];
$is_collapsed = false; // TODO: determine this somehow?
$content = $this->calendar_list_item($id, $prop, $jsenv, $attrib['activeonly']);
if (!empty($folder->children)) {
$content .= html::tag('ul', array('style' => ($is_collapsed ? "display:none;" : null)),
$this->list_tree_html($folder, $data, $jsenv, $attrib));
}
if (strlen($content)) {
$out .= html::tag('li', array(
'id' => 'rcmlical' . rcube_utils::html_identifier($id),
'class' => $prop['group'] . ($prop['virtual'] ? ' virtual' : ''),
),
$content);
}
}
return $out;
}
/**
* Helper method to build a calendar list item (HTML content and js data)
*/
public function calendar_list_item($id, $prop, &$jsenv, $activeonly = false)
{
// enrich calendar properties with settings from the driver
if (!$prop['virtual']) {
unset($prop['user_id']);
$prop['alarms'] = $this->cal->driver->alarms;
$prop['attendees'] = $this->cal->driver->attendees;
$prop['freebusy'] = $this->cal->driver->freebusy;
$prop['attachments'] = $this->cal->driver->attachments;
$prop['undelete'] = $this->cal->driver->undelete;
$prop['feedurl'] = $this->cal->get_url(array('_cal' => $this->cal->ical_feed_hash($id) . '.ics', 'action' => 'feed'));
$jsenv[$id] = $prop;
}
$classes = array('calendar', 'cal-' . asciiwords($id, true));
$title = $prop['title'] ?: ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ?
html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET) : '');
if ($prop['virtual'])
$classes[] = 'virtual';
else if (!$prop['editable'])
$classes[] = 'readonly';
if ($prop['subscribed'])
$classes[] = 'subscribed';
if ($prop['subscribed'] === 2)
$classes[] = 'partial';
if ($prop['class'])
$classes[] = $prop['class'];
$content = '';
if (!$activeonly || $prop['active']) {
$label_id = 'cl:' . $id;
$content = html::div(join(' ', $classes),
html::span(array('class' => 'calname', 'id' => $label_id, 'title' => $title), $prop['editname'] ? Q($prop['editname']) : $prop['listname']) .
($prop['virtual'] ? '' :
html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id), '') .
html::span('actions',
($prop['removable'] ? html::a(array('href' => '#', 'class' => 'remove', 'title' => $this->cal->gettext('removelist')), ' ') : '') .
html::a(array('href' => '#', 'class' => 'quickview', 'title' => $this->cal->gettext('quickview'), 'role' => 'checkbox', 'aria-checked' => 'false'), '') .
(isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->cal->gettext('calendarsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '')
) .
html::span(array('class' => 'handle', 'style' => "background-color: #" . ($prop['color'] ?: 'f00')), '&nbsp;')
)
);
}
return $content;
}
/**
*
*/
function angenda_options($attrib = array())
{
$attrib += array('id' => 'agendaoptions');
$attrib['style'] .= 'display:none';
$select_range = new html_select(array('name' => 'listrange', 'id' => 'agenda-listrange'));
$select_range->add(1 . ' ' . preg_replace('/\(.+\)/', '', $this->cal->lib->gettext('days')), $days);
foreach (array(2,5,7,14,30,60,90,180,365) as $days)
$select_range->add($days . ' ' . preg_replace('/\(|\)/', '', $this->cal->lib->gettext('days')), $days);
$html .= html::label('agenda-listrange', $this->cal->gettext('listrange'));
$html .= $select_range->show($this->rc->config->get('calendar_agenda_range', $this->cal->defaults['calendar_agenda_range']));
$select_sections = new html_select(array('name' => 'listsections', 'id' => 'agenda-listsections'));
$select_sections->add('---', '');
foreach (array('day' => 'libcalendaring.days', 'week' => 'libcalendaring.weeks', 'month' => 'libcalendaring.months', 'smart' => 'calendar.smartsections') as $val => $label)
$select_sections->add(preg_replace('/\(|\)/', '', ucfirst($this->rc->gettext($label))), $val);
$html .= html::span('spacer', '&nbsp;');
$html .= html::label('agenda-listsections', $this->cal->gettext('listsections'));
$html .= $select_sections->show($this->rc->config->get('calendar_agenda_sections', $this->cal->defaults['calendar_agenda_sections']));
return html::div($attrib, $html);
}
/**
* Render a HTML select box for calendar selection
*/
function calendar_select($attrib = array())
{
$attrib['name'] = 'calendar';
$attrib['is_escaped'] = true;
$select = new html_select($attrib);
foreach ((array)$this->cal->driver->list_calendars() as $id => $prop) {
if ($prop['editable'] || strpos($prop['rights'], 'i') !== false)
$select->add($prop['name'], $id);
}
return $select->show(null);
}
/**
* Render a HTML select box for user identity selection
*/
function identity_select($attrib = array())
{
$attrib['name'] = 'identity';
$select = new html_select($attrib);
$identities = $this->rc->user->list_emails();
foreach ($identities as $ident) {
$select->add(format_email_recipient($ident['email'], $ident['name']), $ident['identity_id']);
}
return $select->show(null);
}
/**
* Render a HTML select box to select an event category
*/
function category_select($attrib = array())
{
$attrib['name'] = 'categories';
$select = new html_select($attrib);
$select->add('---', '');
foreach (array_keys((array)$this->cal->driver->list_categories()) as $cat) {
$select->add($cat, $cat);
}
return $select->show(null);
}
/**
* Render a HTML select box for status property
*/
function status_select($attrib = array())
{
$attrib['name'] = 'status';
$select = new html_select($attrib);
$select->add('---', '');
$select->add($this->cal->gettext('status-confirmed'), 'CONFIRMED');
$select->add($this->cal->gettext('status-cancelled'), 'CANCELLED');
//$select->add($this->cal->gettext('tentative'), 'TENTATIVE');
return $select->show(null);
}
/**
* Render a HTML select box for free/busy/out-of-office property
*/
function freebusy_select($attrib = array())
{
$attrib['name'] = 'freebusy';
$select = new html_select($attrib);
$select->add($this->cal->gettext('free'), 'free');
$select->add($this->cal->gettext('busy'), 'busy');
// out-of-office is not supported by libkolabxml (#3220)
// $select->add($this->cal->gettext('outofoffice'), 'outofoffice');
$select->add($this->cal->gettext('tentative'), 'tentative');
return $select->show(null);
}
/**
* Render a HTML select for event priorities
*/
function priority_select($attrib = array())
{
$attrib['name'] = 'priority';
$select = new html_select($attrib);
$select->add('---', '0');
$select->add('1 '.$this->cal->gettext('highest'), '1');
$select->add('2 '.$this->cal->gettext('high'), '2');
$select->add('3 ', '3');
$select->add('4 ', '4');
$select->add('5 '.$this->cal->gettext('normal'), '5');
$select->add('6 ', '6');
$select->add('7 ', '7');
$select->add('8 '.$this->cal->gettext('low'), '8');
$select->add('9 '.$this->cal->gettext('lowest'), '9');
return $select->show(null);
}
/**
* Render HTML input for sensitivity selection
*/
function sensitivity_select($attrib = array())
{
$attrib['name'] = 'sensitivity';
$select = new html_select($attrib);
$select->add($this->cal->gettext('public'), 'public');
$select->add($this->cal->gettext('private'), 'private');
$select->add($this->cal->gettext('confidential'), 'confidential');
return $select->show(null);
}
/**
* Render HTML form for alarm configuration
*/
function alarm_select($attrib = array())
{
return $this->cal->lib->alarm_select($attrib, $this->cal->driver->alarm_types, $this->cal->driver->alarm_absolute);
}
/**
*
*/
function edit_attendees_notify($attrib = array())
{
$checkbox = new html_checkbox(array('name' => '_notify', 'id' => 'edit-attendees-donotify', 'value' => 1));
return html::div($attrib, html::label(null, $checkbox->show(1) . ' ' . $this->cal->gettext('sendnotifications')));
}
/**
* Generate the form for recurrence settings
*/
function recurring_event_warning($attrib = array())
{
$attrib['id'] = 'edit-recurring-warning';
$radio = new html_radiobutton(array('name' => '_savemode', 'class' => 'edit-recurring-savemode'));
$form = html::label(null, $radio->show('', array('value' => 'current')) . $this->cal->gettext('currentevent')) . ' ' .
html::label(null, $radio->show('', array('value' => 'future')) . $this->cal->gettext('futurevents')) . ' ' .
html::label(null, $radio->show('all', array('value' => 'all')) . $this->cal->gettext('allevents')) . ' ' .
html::label(null, $radio->show('', array('value' => 'new')) . $this->cal->gettext('saveasnew'));
return html::div($attrib, html::div('message', html::span('ui-icon ui-icon-alert', '') . $this->cal->gettext('changerecurringeventwarning')) . html::div('savemode', $form));
}
/**
* Form for uploading and importing events
*/
function events_import_form($attrib = array())
{
if (!$attrib['id'])
$attrib['id'] = 'rcmImportForm';
// Get max filesize, enable upload progress bar
$max_filesize = rcube_upload_init();
$accept = '.ics, text/calendar, text/x-vcalendar, application/ics';
if (class_exists('ZipArchive', false)) {
$accept .= ', .zip, application/zip';
}
$input = new html_inputfield(array(
'type' => 'file', 'name' => '_data', 'size' => $attrib['uploadfieldsize'],
'accept' => $accept));
$select = new html_select(array('name' => '_range', 'id' => 'event-import-range'));
$select->add(array(
$this->cal->gettext('onemonthback'),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>2))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>3))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>6))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>12))),
$this->cal->gettext('all'),
),
array('1','2','3','6','12',0));
$html .= html::div('form-section',
html::div(null, $input->show()) .
html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))))
);
$html .= html::div('form-section',
html::label('event-import-calendar', $this->cal->gettext('calendar')) .
$this->calendar_select(array('name' => 'calendar', 'id' => 'event-import-calendar'))
);
$html .= html::div('form-section',
html::label('event-import-range', $this->cal->gettext('importrange')) .
$select->show(1)
);
$this->rc->output->add_gui_object('importform', $attrib['id']);
$this->rc->output->add_label('import');
return html::tag('form', array('action' => $this->rc->url(array('task' => 'calendar', 'action' => 'import_events')),
'method' => "post", 'enctype' => 'multipart/form-data', 'id' => $attrib['id']),
$html
);
}
/**
* Form to select options for exporting events
*/
function events_export_form($attrib = array())
{
if (!$attrib['id'])
$attrib['id'] = 'rcmExportForm';
$html .= html::div('form-section',
html::label('event-export-calendar', $this->cal->gettext('calendar')) .
$this->calendar_select(array('name' => 'calendar', 'id' => 'event-export-calendar'))
);
$select = new html_select(array('name' => 'range', 'id' => 'event-export-range'));
$select->add(array(
$this->cal->gettext('all'),
$this->cal->gettext('onemonthback'),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>2))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>3))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>6))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>12))),
$this->cal->gettext('customdate'),
),
array(0,'1','2','3','6','12','custom'));
$startdate = new html_inputfield(array('name' => 'start', 'size' => 11, 'id' => 'event-export-startdate'));
$html .= html::div('form-section',
html::label('event-export-range', $this->cal->gettext('exportrange')) .
$select->show(0) .
html::span(array('style'=>'display:none'), $startdate->show())
);
$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')) .
$checkbox->show(1)
);
$this->rc->output->add_gui_object('exportform', $attrib['id']);
return html::tag('form', array('action' => $this->rc->url(array('task' => 'calendar', 'action' => 'export_events')),
'method' => "post", 'id' => $attrib['id']),
$html
);
}
/**
* Generate the form for event attachments upload
*/
function attachments_form($attrib = array())
{
// add ID if not given
if (!$attrib['id'])
$attrib['id'] = 'rcmUploadForm';
// Get max filesize, enable upload progress bar
$max_filesize = rcube_upload_init();
$button = new html_inputfield(array('type' => 'button'));
$input = new html_inputfield(array(
'type' => 'file', 'name' => '_attachments[]',
'multiple' => 'multiple', 'size' => $attrib['attachmentfieldsize']));
return html::div($attrib,
html::div(null, $input->show()) .
html::div('formbuttons', $button->show(rcube_label('upload'), array('class' => 'button mainaction',
'onclick' => JS_OBJECT_NAME . ".upload_file(this.form)"))) .
html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))))
);
}
/**
* Register UI object for HTML5 drag & drop file upload
*/
function file_drop_area($attrib = array())
{
if ($attrib['id']) {
$this->rc->output->add_gui_object('filedrop', $attrib['id']);
$this->rc->output->set_env('filedrop', array('action' => 'upload', 'fieldname' => '_attachments'));
}
}
/**
* Generate HTML element for attachments list
*/
function attachments_list($attrib = array())
{
if (!$attrib['id'])
$attrib['id'] = 'rcmAttachmentList';
$skin_path = $this->cal->local_skin_path();
if ($attrib['deleteicon']) {
$_SESSION[calendar::SESSION_KEY . '_deleteicon'] = $skin_path . $attrib['deleteicon'];
$this->rc->output->set_env('deleteicon', $skin_path . $attrib['deleteicon']);
}
if ($attrib['cancelicon'])
$this->rc->output->set_env('cancelicon', $skin_path . $attrib['cancelicon']);
if ($attrib['loadingicon'])
$this->rc->output->set_env('loadingicon', $skin_path . $attrib['loadingicon']);
$this->rc->output->add_gui_object('attachmentlist', $attrib['id']);
$this->attachmentlist_id = $attrib['id'];
return html::tag('ul', $attrib, '', html::$common_attrib);
}
/**
* Handler for calendar form template.
* The form content could be overriden by the driver
*/
function calendar_editform($action, $calendar = array())
{
// compose default calendar form fields
$input_name = new html_inputfield(array('name' => 'name', 'id' => 'calendar-name', 'size' => 20));
$input_color = new html_inputfield(array('name' => 'color', 'id' => 'calendar-color', 'size' => 6));
$formfields = array(
'name' => array(
'label' => $this->cal->gettext('name'),
'value' => $input_name->show($calendar['name']),
'id' => 'calendar-name',
),
'color' => array(
'label' => $this->cal->gettext('color'),
'value' => $input_color->show($calendar['color']),
'id' => 'calendar-color',
),
);
if ($this->cal->driver->alarms) {
$checkbox = new html_checkbox(array('name' => 'showalarms', 'id' => 'calendar-showalarms', 'value' => 1));
$formfields['showalarms'] = array(
'label' => $this->cal->gettext('showalarms'),
'value' => $checkbox->show($calendar['showalarms']?1:0),
'id' => 'calendar-showalarms',
);
}
// allow driver to extend or replace the form content
return html::tag('form', array('action' => "#", 'method' => "get", 'id' => 'calendarpropform'),
$this->cal->driver->calendar_form($action, $calendar, $formfields)
);
}
/**
*
*/
function attendees_list($attrib = array())
{
// add "noreply" checkbox to attendees table only
$invitations = strpos($attrib['id'], 'attend') !== false;
$invite = new html_checkbox(array('value' => 1, 'id' => 'edit-attendees-invite'));
$table = new html_table(array('cols' => 5 + intval($invitations), 'border' => 0, 'cellpadding' => 0, 'class' => 'rectable'));
$table->add_header('role', $this->cal->gettext('role'));
$table->add_header('name', $this->cal->gettext($attrib['coltitle'] ?: 'attendee'));
$table->add_header('availability', $this->cal->gettext('availability'));
$table->add_header('confirmstate', $this->cal->gettext('confirmstate'));
if ($invitations) {
$table->add_header(array('class' => 'invite', 'title' => $this->cal->gettext('sendinvitations')),
$invite->show(1) . html::label('edit-attendees-invite', $this->cal->gettext('sendinvitations')));
}
$table->add_header('options', '');
// hide invite column if disabled by config
$itip_notify = (int)$this->rc->config->get('calendar_itip_send_option', $this->cal->defaults['calendar_itip_send_option']);
if ($invitations && !($itip_notify & 2)) {
$css = sprintf('#%s td.invite, #%s th.invite { display:none !important }', $attrib['id'], $attrib['id']);
$this->rc->output->add_footer(html::tag('style', array('type' => 'text/css'), $css));
}
return $table->show($attrib);
}
/**
*
*/
function attendees_form($attrib = array())
{
$input = new html_inputfield(array('name' => 'participant', 'id' => 'edit-attendee-name', 'size' => 30));
$textarea = new html_textarea(array('name' => 'comment', 'id' => 'edit-attendees-comment',
'rows' => 4, 'cols' => 55, 'title' => $this->cal->gettext('itipcommenttitle')));
return html::div($attrib,
html::div(null, $input->show() . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-add', 'value' => $this->cal->gettext('addattendee'))) . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-schedule', 'value' => $this->cal->gettext('scheduletime').'...'))) .
html::p('attendees-commentbox', html::label(null, $this->cal->gettext('itipcomment') . $textarea->show()))
);
}
/**
*
*/
function resources_form($attrib = array())
{
$input = new html_inputfield(array('name' => 'resource', 'id' => 'edit-resource-name', 'size' => 30));
return html::div($attrib,
html::div(null, $input->show() . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-resource-add', 'value' => $this->cal->gettext('addresource'))) . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-resource-find', 'value' => $this->cal->gettext('findresources').'...')))
);
}
/**
*
*/
function resources_list($attrib = array())
{
$attrib += array('id' => 'calendar-resources-list');
$this->rc->output->add_gui_object('resourceslist', $attrib['id']);
return html::tag('ul', $attrib, '', html::$common_attrib);
}
/**
*
*/
public function resource_info($attrib = array())
{
$attrib += array('id' => 'calendar-resources-info');
$this->rc->output->add_gui_object('resourceinfo', $attrib['id']);
$this->rc->output->add_gui_object('resourceownerinfo', $attrib['id'] . '-owner');
// copy address book labels for owner details to client
$this->rc->output->add_label('name','firstname','surname','department','jobtitle','email','phone','address');
$table_attrib = array('id','class','style','width','summary','cellpadding','cellspacing','border');
return html::tag('table', $attrib,
html::tag('tbody', null, ''), $table_attrib) .
html::tag('table', array('id' => $attrib['id'] . '-owner', 'style' => 'display:none') + $attrib,
html::tag('thead', null,
html::tag('tr', null,
html::tag('td', array('colspan' => 2), Q($this->cal->gettext('resourceowner')))
)
) .
html::tag('tbody', null, ''),
$table_attrib);
}
/**
*
*/
public function resource_calendar($attrib = array())
{
$attrib += array('id' => 'calendar-resources-calendar');
$this->rc->output->add_gui_object('resourceinfocalendar', $attrib['id']);
return html::div($attrib, '');
}
/**
* GUI object 'searchform' for the resource finder dialog
*
* @param array Named parameters
* @return string HTML code for the gui object
*/
function resources_search_form($attrib)
{
$attrib += array('command' => 'search-resource', 'id' => 'rcmcalresqsearchbox', 'autocomplete' => 'off');
$attrib['name'] = '_q';
$input_q = new html_inputfield($attrib);
$out = $input_q->show();
// add form tag around text field
$out = $this->rc->output->form_tag(array(
'name' => "rcmcalresoursqsearchform",
'onsubmit' => rcmail_output::JS_OBJECT_NAME . ".command('" . $attrib['command'] . "'); return false",
'style' => "display:inline"),
$out);
return $out;
}
/**
*
*/
function attendees_freebusy_table($attrib = array())
{
$table = new html_table(array('cols' => 2, 'border' => 0, 'cellspacing' => 0));
$table->add('attendees',
html::tag('h3', 'boxtitle', $this->cal->gettext('tabattendees')) .
html::div('timesheader', '&nbsp;') .
html::div(array('id' => 'schedule-attendees-list', 'class' => 'attendees-list'), '')
);
$table->add('times',
html::div('scroll',
html::tag('table', array('id' => 'schedule-freebusy-times', 'border' => 0, 'cellspacing' => 0), html::tag('thead') . html::tag('tbody')) .
html::div(array('id' => 'schedule-event-time', 'style' => 'display:none'), '&nbsp;')
)
);
return $table->show($attrib);
}
- /**
- * Table oultine for event changelog display
- */
- function event_changelog_table($attrib = array())
- {
- $table = new html_table(array('cols' => 5, 'border' => 0, 'cellspacing' => 0));
- $table->add_header('diff', '');
- $table->add_header('revision', $this->cal->gettext('revision'));
- $table->add_header('date', $this->cal->gettext('date'));
- $table->add_header('user', $this->cal->gettext('user'));
- $table->add_header('operation', $this->cal->gettext('operation'));
- $table->add_header('actions', '&nbsp;');
-
- return $table->show($attrib);
- }
-
/**
*
*/
function event_invitebox($attrib = array())
{
if ($this->cal->event) {
return html::div($attrib,
$this->cal->itip->itip_object_details_table($this->cal->event, $this->cal->itip->gettext('itipinvitation')) .
$this->cal->invitestatus
);
}
return '';
}
function event_rsvp_buttons($attrib = array())
{
$actions = array('accepted','tentative','declined');
if ($attrib['delegate'] !== 'false')
$actions[] = 'delegated';
return $this->cal->itip->itip_rsvp_buttons($attrib, $actions);
}
}
diff --git a/plugins/calendar/localization/bg_BG.inc b/plugins/calendar/localization/bg_BG.inc
index 76d1d84f..afbdfe11 100644
--- a/plugins/calendar/localization/bg_BG.inc
+++ b/plugins/calendar/localization/bg_BG.inc
@@ -1,124 +1,122 @@
<?php
-
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
-
$labels['default_view'] = 'Изглед по подразбиране';
$labels['time_format'] = 'Формат на часовете';
$labels['first_day'] = 'Първи ден от седмицата';
$labels['first_hour'] = 'Първи час при показване';
$labels['workinghours'] = 'Работни часове';
$labels['add_category'] = 'Добавяне на категория';
$labels['remove_category'] = 'Премахване на категория';
$labels['defaultcalendar'] = 'Създаване на нови събития в ';
$labels['eventcoloring'] = 'Оцветяване на събитията';
$labels['coloringmode0'] = 'Според календара';
$labels['coloringmode1'] = 'Относно категорията';
$labels['coloringmode2'] = 'Календар за очертание, категория за съдържание';
$labels['coloringmode3'] = 'Категория за очертание, календар за съдържание';
$labels['calendar'] = 'Календар';
$labels['calendars'] = 'Календари';
$labels['category'] = 'Категория';
$labels['categories'] = 'Категории';
$labels['createcalendar'] = 'Създаване на нов календар';
$labels['editcalendar'] = 'Промяна на свойствата на календара';
$labels['name'] = 'Име';
$labels['color'] = 'Цвят';
$labels['day'] = 'Ден';
$labels['week'] = 'Седмица';
$labels['month'] = 'Месец';
$labels['agenda'] = 'Бележник';
$labels['new'] = 'Ново';
$labels['new_event'] = 'Добавяне на събитие';
$labels['edit_event'] = 'Промяна на събитие';
$labels['edit'] = 'Промяна';
$labels['save'] = 'Запис';
$labels['cancel'] = 'Отказ';
$labels['select'] = 'Избиране';
$labels['print'] = 'Печат';
$labels['printtitle'] = 'Печат на календарите';
$labels['title'] = 'Заглавие';
$labels['description'] = 'Описание';
$labels['all-day'] = 'цял ден';
$labels['export'] = 'Извличане';
$labels['exporttitle'] = 'Извличане към iCalendar';
$labels['exportrange'] = 'Събития от';
$labels['location'] = 'Местоположение';
$labels['date'] = 'Дата';
$labels['start'] = 'Начало';
$labels['end'] = 'Край';
$labels['selectdate'] = 'Избор на дата';
$labels['freebusy'] = 'Показване като';
$labels['free'] = 'Свободно';
$labels['busy'] = 'Заето';
$labels['outofoffice'] = 'Извън офиса';
$labels['tentative'] = 'Предварително';
$labels['status'] = 'Статус';
$labels['priority'] = 'Приоритет';
$labels['sensitivity'] = 'Частност';
$labels['public'] = 'публично';
$labels['private'] = 'частно';
$labels['confidential'] = 'конфиденциално';
$labels['alarms'] = 'Напомняне';
$labels['unknown'] = 'Неизвестно';
$labels['generated'] = 'генерирано в';
$labels['printdescriptions'] = 'Печат на описанията';
$labels['parentcalendar'] = 'Внасяне вътре';
$labels['searchearlierdates'] = '« Търсене за по- стари събития';
$labels['searchlaterdates'] = 'Търсене за по- нови събития »';
$labels['andnmore'] = '$nr повече...';
$labels['createfrommail'] = 'Запазване като събитие';
$labels['importevents'] = 'Внасяне на събития';
$labels['importrange'] = 'Събития от';
$labels['onemonthback'] = '1 месец назад';
$labels['nmonthsback'] = '$nr месеца назад';
$labels['showurl'] = 'Показване на URL на календара';
$labels['showurldescription'] = 'Използвайте следния адрес, за да достъпвате (само за четене) вашия календар от други приложения. Можете да копирате и поставяте това във всеки календарен софтуер, поддържащ форматът iCal';
$labels['listrange'] = 'Оразмеряване към екран:';
$labels['listsections'] = 'Разделяне на:';
$labels['smartsections'] = 'Интелигентни секции';
$labels['until'] = 'до';
$labels['today'] = 'Днес';
$labels['tomorrow'] = 'Утре';
$labels['thisweek'] = 'Тази седмица';
$labels['nextweek'] = 'Следващата седмица';
$labels['thismonth'] = 'Този месец';
$labels['nextmonth'] = 'Следващия месец';
$labels['weekofyear'] = 'Седмица';
$labels['pastevents'] = 'Минали';
$labels['futureevents'] = 'Бъдещи';
$labels['defaultalarmtype'] = 'Настройка за напомняне по подразбиране';
$labels['defaultalarmoffset'] = 'Време за напомняне по подразбиране';
$labels['attendee'] = 'Участник';
$labels['role'] = 'Роля';
$labels['confirmstate'] = 'Статус';
$labels['addattendee'] = 'Добавяне на участник';
$labels['roleorganizer'] = 'Организатор';
$labels['rolerequired'] = 'Задължителен';
$labels['roleoptional'] = 'По избор';
$labels['availfree'] = 'Свободно';
$labels['availbusy'] = 'Заето';
$labels['availunknown'] = 'Неизвестно';
$labels['availtentative'] = 'Предварително';
$labels['availoutofoffice'] = 'Извън офиса';
$labels['sendinvitations'] = 'Изпращане на покани';
$labels['sendnotifications'] = 'Известяване на участниците относно промените';
$labels['sendcancellation'] = 'Известяване на участниците относно отмяна на събития';
$labels['itipdeclineevent'] = 'Искате ли да отхвърлите поканата за това събитие?';
$labels['saveincalendar'] = 'запазване в';
$labels['tabsummary'] = 'Заглавие';
$labels['tabattendees'] = 'Участници';
$labels['tabattachments'] = 'Прикрепени файлове';
$labels['tabsharing'] = 'Споделяне';
$labels['deleteobjectconfirm'] = 'Наистина ли искате да премахнете това събитие?';
$labels['deleteventconfirm'] = 'Наистина ли искате да премахнете това събитие?';
$labels['deletecalendarconfirm'] = 'Наистина ли искате да премахнете този календар с всичките му събития?';
$labels['savingdata'] = 'Запазване на данни...';
$labels['errorsaving'] = 'Неуспешно записването на промените.';
-
+$labels['futurevents'] = 'Бъдещи';
?>
diff --git a/plugins/calendar/localization/ca_ES.inc b/plugins/calendar/localization/ca_ES.inc
index d3c5ff92..9226ef5c 100644
--- a/plugins/calendar/localization/ca_ES.inc
+++ b/plugins/calendar/localization/ca_ES.inc
@@ -1,266 +1,266 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Vista per defecte';
$labels['time_format'] = 'Format de l\'hora';
$labels['timeslots'] = 'Espais de temps per hora';
$labels['first_day'] = 'Primer dia de la setmana';
$labels['first_hour'] = 'Primera hora a mostrar';
$labels['workinghours'] = 'Hores de feina';
$labels['add_category'] = 'Afegeix categoria';
$labels['remove_category'] = 'Suprimeix categoria';
$labels['defaultcalendar'] = 'Crea nous esdeveniments a';
$labels['eventcoloring'] = 'Colors dels esdeveniments';
$labels['coloringmode0'] = 'Depenent del calendari';
$labels['coloringmode1'] = 'Depenent de la categoria';
$labels['coloringmode2'] = 'Calendari pel contorn, categoria pel contingut';
$labels['coloringmode3'] = 'Categoria pel contorn, calendari pel contingut\'';
$labels['afternothing'] = 'No facis res';
$labels['aftertrash'] = 'Mou a la Paperera';
$labels['afterdelete'] = 'Suprimeix el missatge';
$labels['afterflagdeleted'] = 'Marca\'l com a suprimit';
$labels['aftermoveto'] = 'Mou a...';
$labels['itipoptions'] = 'Invitacions a esdeveniments';
$labels['afteraction'] = 'S\'envia un missatge després d\'una invitació o una actualització';
$labels['calendar'] = 'Calendari';
$labels['calendars'] = 'Calendaris';
$labels['category'] = 'Categoria';
$labels['categories'] = 'Categories';
$labels['createcalendar'] = 'Crea un nou calendari';
$labels['editcalendar'] = 'Edita les propietats del calendari';
$labels['name'] = 'Nom';
$labels['color'] = 'Color';
$labels['day'] = 'Dia';
$labels['week'] = 'Setmana';
$labels['month'] = 'Mes';
$labels['agenda'] = 'Agenda';
$labels['new'] = 'Nou';
$labels['new_event'] = 'Nou esdeveniment';
$labels['edit_event'] = 'Edita esdeveniment';
$labels['edit'] = 'Edita';
$labels['save'] = 'Desa';
$labels['removelist'] = 'Remove from list';
$labels['cancel'] = 'Cancel·la';
$labels['select'] = 'Selecciona';
$labels['print'] = 'Imprimeix';
$labels['printtitle'] = 'Imprimeix calendaris';
$labels['title'] = 'Resum';
$labels['description'] = 'Descripció';
$labels['all-day'] = 'Tot el dia';
$labels['export'] = 'Exporta';
$labels['exporttitle'] = 'Exporta a iCalendari';
$labels['exportrange'] = 'Esdeveniments de';
$labels['exportattachments'] = 'Amb fitxers adjunts';
$labels['customdate'] = 'Personalitza la data';
$labels['location'] = 'Ubicació';
$labels['url'] = 'URL';
$labels['date'] = 'Data';
$labels['start'] = 'Inici';
$labels['starttime'] = 'Hora d\'inici';
$labels['end'] = 'Final';
$labels['endtime'] = 'Hora de finalització';
$labels['repeat'] = 'Repeteix';
$labels['selectdate'] = 'Tria la data';
$labels['freebusy'] = 'Mostra\'m com';
$labels['free'] = 'Lliure';
$labels['busy'] = 'Ocupat';
$labels['outofoffice'] = 'Fora de l\'oficina';
$labels['tentative'] = 'Provisional';
$labels['mystatus'] = 'El meu estat';
$labels['status'] = 'Estat';
$labels['status-confirmed'] = 'Confirmat';
$labels['status-cancelled'] = 'Cancel·lat';
$labels['priority'] = 'Prioritat';
$labels['sensitivity'] = 'Privadesa';
$labels['public'] = 'públic';
$labels['private'] = 'privat';
$labels['confidential'] = 'confidencial';
$labels['links'] = 'Reference';
$labels['alarms'] = 'Recordatori';
$labels['comment'] = 'Comentari';
$labels['created'] = 'Creat';
$labels['changed'] = 'Darrera modificació';
$labels['unknown'] = 'Desconegut';
$labels['eventoptions'] = 'Opcions';
$labels['generated'] = 'generat a';
$labels['eventhistory'] = 'Historial';
$labels['removelink'] = 'Remove email reference';
$labels['printdescriptions'] = 'Imprimeix descripcions';
$labels['parentcalendar'] = 'Insereix dins';
$labels['searchearlierdates'] = '« Cerca els esdeveniments d\'abans';
$labels['searchlaterdates'] = 'Cerca els esdeveniments de després »';
$labels['andnmore'] = '$nr més...';
$labels['togglerole'] = 'Feu clic per commutar el rol';
$labels['createfrommail'] = 'Desa com a esdeveniment';
$labels['importevents'] = 'Importa esdeveniments';
$labels['importrange'] = 'Esdeveniments de';
$labels['onemonthback'] = '1 mes abans';
$labels['nmonthsback'] = '$nr mesos abans';
$labels['showurl'] = 'Mostra la URL del calendari';
$labels['showurldescription'] = 'Podeu fer servir aquesta adreça per accedir (només lectura) el vostre calendari des d\'altres aplicacions. Copieu i enganxeu-la dins d\'un altre programari de calendari que suporti el format iCal.';
$labels['caldavurldescription'] = 'Copieu aquesta adreça a una aplicació client <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> (p.ex.: Evolution o Mozilla Thunderbird) per sincronitzar aquest calendari amb el vostre ordinador o dispositiu mòbil.';
$labels['findcalendars'] = 'Cerca calendaris...';
$labels['searchterms'] = 'Termes de cerca';
$labels['calsearchresults'] = 'Calendaris disponibles';
$labels['calendarsubscribe'] = 'Llista permanentment';
$labels['nocalendarsfound'] = 'No s\'ha trobat cap calendari';
$labels['nrcalendarsfound'] = 'S\'han trobat $nr calendaris';
$labels['quickview'] = 'Mostra només aquest calendari';
$labels['invitationspending'] = 'Invitacions pendents';
$labels['invitationsdeclined'] = 'Invitacions declinades';
$labels['changepartstat'] = 'Canvia l\'estat d\'un participant';
$labels['rsvpcomment'] = 'Text d\'invitació';
$labels['listrange'] = 'Rang per mostrar:';
$labels['listsections'] = 'Divideix en:';
$labels['smartsections'] = 'Seccions petites';
$labels['until'] = 'fins';
$labels['today'] = 'Avui';
$labels['tomorrow'] = 'Demà';
$labels['thisweek'] = 'Aquesta setmana';
$labels['nextweek'] = 'Setmana vinent';
$labels['prevweek'] = 'Setmana anterior';
$labels['thismonth'] = 'Aquest mes';
$labels['nextmonth'] = 'Mes vinent';
$labels['weekofyear'] = 'Setmana';
$labels['pastevents'] = 'Passat';
$labels['futureevents'] = 'Futur';
$labels['showalarms'] = 'Mostra els recordatoris';
$labels['defaultalarmtype'] = 'Recordatori per defecte';
$labels['defaultalarmoffset'] = 'Temps de recordatori per defecte';
$labels['attendee'] = 'Participant';
$labels['role'] = 'Rol';
$labels['availability'] = 'Disp.';
$labels['confirmstate'] = 'Estat';
$labels['addattendee'] = 'Afegeix participant';
$labels['roleorganizer'] = 'Organitzador';
$labels['rolerequired'] = 'Obligatori';
$labels['roleoptional'] = 'Opcional';
$labels['rolechair'] = 'President';
$labels['rolenonparticipant'] = 'Absent';
$labels['cutypeindividual'] = 'Individual';
$labels['cutypegroup'] = 'Grup';
$labels['cutyperesource'] = 'Recurs';
$labels['cutyperoom'] = 'Sala';
$labels['availfree'] = 'Lliure';
$labels['availbusy'] = 'Ocupat';
$labels['availunknown'] = 'Desconegut';
$labels['availtentative'] = 'Provisional';
$labels['availoutofoffice'] = 'Fora de l\'oficina';
$labels['delegatedto'] = 'Delegat a:';
$labels['delegatedfrom'] = 'Delegat de:';
$labels['scheduletime'] = 'Cerca disponibilitat';
$labels['sendinvitations'] = 'Envia invitacions';
$labels['sendnotifications'] = 'Notifica als participants quan hi hagi modificacions';
$labels['sendcancellation'] = 'Notifica als participants si es cancel·la l\'esdeveniment';
$labels['onlyworkinghours'] = 'Cerca disponibilitat dins de les hores de feina';
$labels['reqallattendees'] = 'Obligatori/tots els participants';
$labels['prevslot'] = 'Lloc anterior';
$labels['nextslot'] = 'Lloc següent';
$labels['suggestedslot'] = 'Lloc suggerit';
$labels['noslotfound'] = 'No s\'ha pogut trobar un espai de temps lliure';
$labels['invitationsubject'] = 'Heu estat convidats a "$title"';
$labels['invitationmailbody'] = "*\$title*\n\nQuan: \$date\n\nConvidats: \$attendees\n\nSi us plau cerqueu el fitxer iCalendar adjunt dins dels detalls de l'esdeveniment per poder-lo importar a la vostra aplicació de calendari.";
$labels['invitationattendlinks'] = "En cas que el vostre client de correu electrònic no suporti peticions de tipus iTip, podeu fer servir el següent enllaç per acceptar o declinar aquesta invitació:\n\$url";
$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";
$labels['itipmailbodytentative'] = "\$sender ha acceptat provisionalment la invitació al següent esdeveniment:\n\n*\$title*\n\nQuan: \$date\n\nConvidats: \$attendees";
$labels['itipmailbodydeclined'] = "\$sender ha declinat la invitació al següent esdeveniment:\n\n*\$title*\n\nQuan: \$date\n\nConvidats: \$attendees";
$labels['itipmailbodycancel'] = "\$sender ha rebutjat la vostra participació en el següent esdeveniment:\n\n*\$title*\n\nQuan: \$date";
$labels['itipdeclineevent'] = 'Voleu declinar la vostra invitació a aquest esdeveniment?';
$labels['declinedeleteconfirm'] = 'Voleu també suprimir aquest esdeveniment declinat del vostre calendari?';
$labels['itipcomment'] = 'Comentari de la invitació/notificació';
$labels['itipcommenttitle'] = 'Aquest comentari serà adjuntat al missatge d\'invitació/notificació que s\'envia als participants';
$labels['notanattendee'] = 'No sou a la llista d\'assistents d\'aquest esdeveniment';
$labels['eventcancelled'] = 'L\'esdeveniment s\'ha cancel·lat.';
$labels['saveincalendar'] = 'desa a';
$labels['updatemycopy'] = 'Actualitza en el meu calendari';
$labels['savetocalendar'] = 'Desa al calendari';
$labels['resource'] = 'Recurs';
$labels['addresource'] = 'Recurs de llibre';
$labels['findresources'] = 'Cerca recursos';
$labels['resourcedetails'] = 'Detalls';
$labels['resourceavailability'] = 'Disponibilitat';
$labels['resourceowner'] = 'Propietari';
$labels['resourceadded'] = 'El recurs ha estat afegit al vostre esdeveniment';
$labels['tabsummary'] = 'Resum';
$labels['tabrecurrence'] = 'Periodicitat';
$labels['tabattendees'] = 'Participants';
$labels['tabresources'] = 'Recursos';
$labels['tabattachments'] = 'Fitxers adjunts';
$labels['tabsharing'] = 'Compartit';
$labels['deleteobjectconfirm'] = 'Esteu segur de voler suprimir aquest esdeveniment?';
$labels['deleteventconfirm'] = 'Esteu segur de voler suprimir aquest esdeveniment?';
$labels['deletecalendarconfirm'] = 'Esteu segurs de voler suprimir aquest calendari amb tots els seus esdeveniments?';
$labels['deletecalendarconfirmrecursive'] = 'Esteu segurs de voler suprimir aquest calendari amb tots els seus esdeveniments i sub-calendaris?';
$labels['savingdata'] = 'S\'estan desant les dades...';
$labels['errorsaving'] = 'No s\'han pogut desar els canvis.';
$labels['operationfailed'] = 'L\'operació sol·licitada ha fallat.';
$labels['invalideventdates'] = 'Les dades entrades no són vàlides!. Si us plau verifiqueu l\'entrada.';
$labels['invalidcalendarproperties'] = 'Les propietats del calendari no són vàlides!. Si us plau introduïu un nom vàlid.';
$labels['searchnoresults'] = 'No s\'ha trobat cap esdeveniment en els calendaris seleccionats.';
$labels['successremoval'] = 'L\'esdeveniment ha estat suprimit correctament.';
$labels['successrestore'] = 'L\'esdeveniment ha estat recuperat correctament.';
$labels['errornotifying'] = 'No s\'ha pogut enviar les notificacions als participants de l\'esdeveniment';
$labels['errorimportingevent'] = 'No s\'ha pogut importar aquest esdeveniment';
$labels['importwarningexists'] = 'Ja existeix una còpia d\'aquest esdeveniment al vostre calendari.';
$labels['newerversionexists'] = 'Ja existeix una nova versió d\'aquest esdeveniment!. S\'ha avortat.';
$labels['nowritecalendarfound'] = 'No s\'ha trobat el calendari per desar l\'esdeveniment';
$labels['importedsuccessfully'] = 'L\'esdeveniment ha estat correctament afegit a \'$calendar\'';
$labels['updatedsuccessfully'] = 'L\'esdeveniment ha estat correctament actualitzat dins de \'$calendar\'';
$labels['attendeupdateesuccess'] = 'L\'estat del participant ha estat actualitzat correctament';
$labels['itipsendsuccess'] = 'La invitació ha estat enviada als participants.';
$labels['itipresponseerror'] = 'No s\'ha pogut enviar la resposta a la invitació d\'aquest esdeveniment';
$labels['itipinvalidrequest'] = 'Aquesta invitació ja no és vàlida';
$labels['sentresponseto'] = 'S\'ha enviat correctament la resposta de la invitació a $mailto';
$labels['localchangeswarning'] = 'Esteu a punt de fer canvis que només seran reflectits al vostre calendari i no seran enviats a l\'organitzador de l\'esdeveniment.';
$labels['importsuccess'] = 'S\'han importat correctament $nr esdeveniments';
$labels['importnone'] = 'No s\'ha trobat cap esdeveniment per importar';
$labels['importerror'] = 'Hi ha hagut un error mentre s\'importava';
$labels['aclnorights'] = 'No teniu drets d\'administrador en aquest calendari.';
$labels['changeeventconfirm'] = 'Canvia l\'esdeveniment';
$labels['changerecurringeventwarning'] = 'Aquest és un esdeveniment periòdic. Voleu editar només l\'esdeveniment actual, aquesta i totes les futures ocurrències, totes les ocurrències o desar-lo com un esdeveniment nou?';
$labels['currentevent'] = 'Actual';
$labels['futurevents'] = 'Futurs';
$labels['allevents'] = 'Tots';
$labels['saveasnew'] = 'Desa com a nou';
$labels['birthdays'] = 'Aniversaris';
$labels['birthdayscalendar'] = 'Calendari d\'aniversaris';
$labels['displaybirthdayscalendar'] = 'Mostra el calendari d\'aniversaris';
$labels['birthdayscalendarsources'] = 'D\'aquestes llibretes d\'adreces';
$labels['birthdayeventtitle'] = 'Aniversari de $name';
$labels['birthdayage'] = 'Edat $age';
-$labels['eventchangelog'] = 'Canvia historial';
+$labels['objectchangelog'] = 'Canvia historial';
$labels['revision'] = 'Revisió';
$labels['user'] = 'Usuari';
$labels['operation'] = 'Acció';
$labels['actionappend'] = 'Desat';
$labels['actionmove'] = 'Mogut';
$labels['actiondelete'] = 'Suprimit';
$labels['compare'] = 'Compara';
$labels['showrevision'] = 'Mostra aquesta versió';
$labels['restore'] = 'Restaura aquesta versió';
-$labels['eventnotfound'] = 'No s\'han pogut carregar les dades d\'aquest esdeveniment';
+$labels['objectnotfound'] = 'No s\'han pogut carregar les dades d\'aquest esdeveniment';
$labels['objectchangelognotavailable'] = 'No està disponible canviar l\'historial d\'aquest esdeveniment';
-$labels['eventdiffnotavailable'] = 'No és possible comparar les revisions seleccionades';
+$labels['objectdiffnotavailable'] = 'No és possible comparar les revisions seleccionades';
$labels['revisionrestoreconfirm'] = 'Esteu segurs de voler restaurar la revisió $rev d\'aquest esdeveniment? Això substituirà l\'actual esdeveniment per una versió antiga.';
$labels['arialabelminical'] = 'Selecció de la data del calendari';
$labels['arialabelcalendarview'] = 'Vista del calendari';
$labels['arialabelsearchform'] = 'Formulari per cercar esdeveniments';
$labels['arialabelquicksearchbox'] = 'Entrada de cerca d\'esdeveniments';
$labels['arialabelcalsearchform'] = 'Formulari de cerca de calendaris';
$labels['calendaractions'] = 'Accions del calendari';
$labels['arialabeleventattendees'] = 'Llista de participants de l\'esdeveniment';
$labels['arialabeleventresources'] = 'Llista de recursos de l\'esdeveniment';
$labels['arialabelresourcesearchform'] = 'Formulari de cerca de recursos';
$labels['arialabelresourceselection'] = 'Recursos disponibles';
?>
diff --git a/plugins/calendar/localization/cs_CZ.inc b/plugins/calendar/localization/cs_CZ.inc
index 1ed6cf38..8f475746 100644
--- a/plugins/calendar/localization/cs_CZ.inc
+++ b/plugins/calendar/localization/cs_CZ.inc
@@ -1,273 +1,273 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Výchozí pohled';
$labels['time_format'] = 'Formát data';
$labels['timeslots'] = 'Míst v rozvrhu na hodinu';
$labels['first_day'] = 'První den v týdnu';
$labels['first_hour'] = 'První hodina k zobrazení';
$labels['workinghours'] = 'Pracovní hodiny';
$labels['add_category'] = 'Přidat kategorii';
$labels['remove_category'] = 'Odstranit kategorii';
$labels['defaultcalendar'] = 'Vytvářet nové události v';
$labels['eventcoloring'] = 'Barvy událostí';
$labels['coloringmode0'] = 'Podle kalendáře';
$labels['coloringmode1'] = 'Podle kategorie';
$labels['coloringmode2'] = 'Kalendář pro orámování, kategorie pro obsah';
$labels['coloringmode3'] = 'Kategorie pro orámování, kalendář pro obsah';
$labels['afternothing'] = 'Nedělat nic';
$labels['aftertrash'] = 'Přesunout do koše';
$labels['afterdelete'] = 'Smazat zprávu';
$labels['afterflagdeleted'] = 'Označit jako smazané';
$labels['aftermoveto'] = 'Přesunout do...';
$labels['itipoptions'] = 'Pozvání na událost';
$labels['afteraction'] = 'Poté co jsou pozvání nebo aktualizace zprávy zpracovány';
$labels['calendar'] = 'Kalendář';
$labels['calendars'] = 'Kalendáře';
$labels['category'] = 'Kategorie';
$labels['categories'] = 'Kategorie';
$labels['createcalendar'] = 'Vytvořit nový kalendář';
$labels['editcalendar'] = 'Upravit vlastnosti kalendáře';
$labels['name'] = 'Název';
$labels['color'] = 'Barva';
$labels['day'] = 'Den';
$labels['week'] = 'Týden';
$labels['month'] = 'Měsíc';
$labels['agenda'] = 'Agenda';
$labels['new'] = 'Nová';
$labels['new_event'] = 'Nová událost';
$labels['edit_event'] = 'Upravit událost';
$labels['edit'] = 'Upravit';
$labels['save'] = 'Uložit';
$labels['removelist'] = 'Odstranit ze seznamu';
$labels['cancel'] = 'Storno';
$labels['select'] = 'Vybrat';
$labels['print'] = 'Tisk';
$labels['printtitle'] = 'Vytisknout kalendáře';
$labels['title'] = 'Souhrn';
$labels['description'] = 'Popis';
$labels['all-day'] = 'celý den';
$labels['export'] = 'Uložit jako ICS';
$labels['exporttitle'] = 'Uložit jako iCalendar';
$labels['exportrange'] = 'Události od';
$labels['exportattachments'] = 'S přílohami';
$labels['customdate'] = 'Vlastní datum';
$labels['location'] = 'Místo';
$labels['url'] = 'URL';
$labels['date'] = 'Datum';
$labels['start'] = 'Začátek';
$labels['starttime'] = 'Začáteční čas';
$labels['end'] = 'Konec';
$labels['endtime'] = 'Čas konce';
$labels['repeat'] = 'Opakování';
$labels['selectdate'] = 'Vyberte datum';
$labels['freebusy'] = 'Zobrazovat mě jako';
$labels['free'] = 'volno';
$labels['busy'] = 'obsazeno';
$labels['outofoffice'] = 'mimo kancelář';
$labels['tentative'] = 'nezávazně';
$labels['mystatus'] = 'Můj stav';
$labels['status'] = 'Stav';
$labels['status-confirmed'] = 'Potvrzeno';
$labels['status-cancelled'] = 'Zrušeno';
$labels['priority'] = 'Přednost';
$labels['sensitivity'] = 'Soukromí';
$labels['public'] = 'veřejné';
$labels['private'] = 'soukromé';
$labels['confidential'] = 'důvěrné';
$labels['links'] = 'Odkaz';
$labels['alarms'] = 'Připomenutí';
$labels['comment'] = 'Poznámka';
$labels['created'] = 'Vytvořeno';
$labels['changed'] = 'Naposledy změněno';
$labels['unknown'] = 'Neznámý';
$labels['eventoptions'] = 'Volby';
$labels['generated'] = 'vytvořeno';
$labels['eventhistory'] = 'Historie';
$labels['removelink'] = 'Odstranit odkaz na e-mail';
$labels['printdescriptions'] = 'Vytisknout popisy';
$labels['parentcalendar'] = 'Vložit dovnitř';
$labels['searchearlierdates'] = '« Hledat dřívější události';
$labels['searchlaterdates'] = 'Hledat pozdější události »';
$labels['andnmore'] = 'dalších $nr...';
$labels['togglerole'] = 'Klepněte k přepnutí role';
$labels['createfrommail'] = 'Uložit jako událost';
$labels['importevents'] = 'Zavést události';
$labels['importrange'] = 'Události od';
$labels['onemonthback'] = '1 měsíc nazpátek';
$labels['nmonthsback'] = '$nr měsíců nazpátek';
$labels['showurl'] = 'Ukázat adresu (URL) kalendáře';
$labels['showurldescription'] = 'Tuto adresu použijte pro přístup (jen ke čtení) ke kalendáři z jiných aplikací. Můžete ji zkopírovat a vložit do jakéhokoli kalendářového softwaru, který podporuje formát iCal.';
$labels['caldavurldescription'] = 'Zkopírujte tuto adresu do aplikace <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> klienta (např. Evolution nebo Mozilla Thunderbird) pro úplné synchronizování tohoto adresáře s vaším počítačem nebo mobilním zařízením.';
$labels['findcalendars'] = 'Najít kalendáře...';
$labels['searchterms'] = 'Hledané výrazy';
$labels['calsearchresults'] = 'Dostupné kalendáře';
$labels['calendarsubscribe'] = 'Ukazovat seznam trvale';
$labels['nocalendarsfound'] = 'Nenalezeny žádné kalendáře';
$labels['nrcalendarsfound'] = '$nr kalendářů nalezeno';
$labels['quickview'] = 'Zobrazit jen tento kalendář';
$labels['invitationspending'] = 'Pozvání čekající na vyřízení';
$labels['invitationsdeclined'] = 'Odmítnutá pozvání';
$labels['changepartstat'] = 'Změnit stav příjemce';
$labels['rsvpcomment'] = 'Text pozvánky';
$labels['listrange'] = 'Rozsah k zobrazení:';
$labels['listsections'] = 'Rozdělit na:';
$labels['smartsections'] = 'Chytré sekce';
$labels['until'] = 'do';
$labels['today'] = 'Dnes';
$labels['tomorrow'] = 'Zítra';
$labels['thisweek'] = 'Tento týden';
$labels['nextweek'] = 'Příští týden';
$labels['prevweek'] = 'Předchozí týden';
$labels['thismonth'] = 'Tento měsíc';
$labels['nextmonth'] = 'Příští měsíc';
$labels['weekofyear'] = 'Týden';
$labels['pastevents'] = 'Minulost';
$labels['futureevents'] = 'Budoucnost';
$labels['showalarms'] = 'Ukázat připomenutí';
$labels['defaultalarmtype'] = 'Výchozí nastavení připomenutí';
$labels['defaultalarmoffset'] = 'Výchozí čas připomenutí';
$labels['attendee'] = 'Účastník';
$labels['role'] = 'Role';
$labels['availability'] = 'Dost.';
$labels['confirmstate'] = 'Stav';
$labels['addattendee'] = 'Přidat účastníka';
$labels['roleorganizer'] = 'Organizátor';
$labels['rolerequired'] = 'Povinný';
$labels['roleoptional'] = 'Nepovinný';
$labels['rolechair'] = 'Předsednictví';
$labels['rolenonparticipant'] = 'Nepřítomný';
$labels['cutypeindividual'] = 'Jednotlivec';
$labels['cutypegroup'] = 'Skupina';
$labels['cutyperesource'] = 'Zdroj';
$labels['cutyperoom'] = 'Místnost';
$labels['availfree'] = 'Volno';
$labels['availbusy'] = 'Obsazeno';
$labels['availunknown'] = 'Neznámý';
$labels['availtentative'] = 'Nezávazně';
$labels['availoutofoffice'] = 'Mimo kancelář';
$labels['delegatedto'] = 'Pověřený:';
$labels['delegatedfrom'] = 'Pověřující:';
$labels['scheduletime'] = 'Najít dostupnost';
$labels['sendinvitations'] = 'Poslat pozvánky';
$labels['sendnotifications'] = 'Uvědomit účastníky o změnách';
$labels['sendcancellation'] = 'Uvědomit účastníky o zrušení události';
$labels['onlyworkinghours'] = 'Najít dostupnost v mé pracovní době';
$labels['reqallattendees'] = 'Povinní/všichni účastníci';
$labels['prevslot'] = 'Předchozí místo v rozvrhu';
$labels['nextslot'] = 'Další místo v rozvrhu';
$labels['suggestedslot'] = 'Navržené místo v rozvrhu';
$labels['noslotfound'] = 'Nelze najít volné místo v rozvrhu';
$labels['invitationsubject'] = 'Byl(a) jste pozván(a) na událost "$title"';
$labels['invitationmailbody'] = "*\$title*\n\nKdy: \$date\n\nPozváni: \$attendees\n\nPodrobnosti o události najdete v přiloženém souboru typu iCalendar. Můžete si ho zavést do kalendářového programu.";
$labels['invitationattendlinks'] = "Pokud váš poštovní klient nepodporuje pozvánky iTip, použijte prosím následující odkaz k potvrzení nebo odmítnutí pozvání:\n\$url";
$labels['eventupdatesubject'] = 'Událost "$title" byla aktualizována';
$labels['eventupdatesubjectempty'] = 'Událost, která se vás týká, byla aktualizována';
$labels['eventupdatemailbody'] = "*\$title*\n\nKdy: \$date\n\nPozváni: \$attendees\n\nPodrobnosti o aktualizované události najdete v přiloženém souboru typu iCalendar. Můžete si ho zavést do kalendářového programu.";
$labels['eventcancelsubject'] = 'Událost "$title" byla zrušena';
$labels['eventcancelmailbody'] = "*\$title*\n\nKdy: \$date\n\nPozváni: \$attendees\n\nUdálost byla zrušena organizátorem (\$organizer).\n\nPodrobnosti najdete v přiloženém souboru ve formátu iCalendar.";
$labels['itipobjectnotfound'] = 'Událost, na který tato zpráva odkazuje, nebyl nalezen ve vašem kalendáři.';
$labels['itipmailbodyaccepted'] = "\$sender přijal(a) pozvání na tuto událost:\n\n*\$title*\n\nKdy: \$date\n\nPozváni: \$attendees";
$labels['itipmailbodytentative'] = "\$sender nezávazně přijal(a) pozvání na tuto událost:\n\n*\$title*\n\nKdy: \$date\n\nPozváni: \$attendees";
$labels['itipmailbodydeclined'] = "\$sender odmítl(a) pozvání na tuto událost:\n\n*\$title*\n\nKdy: \$date\n\nPozváni: \$attendees";
$labels['itipmailbodycancel'] = "\$sender odmítl vaši účast na následující události:\n\n*\$title*\n\nTermín: \$date";
$labels['itipmailbodydelegated'] = "\$sender delegoval účast na následující události:\n\n*\$title*\n\nTermín: \$date";
$labels['itipmailbodydelegatedto'] = "\$sender delegoval účast na následující události na vás:\n\n*\$title*\n\nTermín: \$date";
$labels['itipdeclineevent'] = 'Opravdu chcete odmítnout pozvání na tuto událost?';
$labels['declinedeleteconfirm'] = 'Chcete také ze svého kalendáře smazat tuto odmítnutou událost?';
$labels['itipcomment'] = 'Poznámka k pozvání/oznámení';
$labels['itipcommenttitle'] = 'Tato poznámka bude připojena ke zprávě s pozváním/oznámením poslané účastníkům';
$labels['notanattendee'] = 'Nejste na seznamu účastníků této události';
$labels['eventcancelled'] = 'Tato událost byla zrušena';
$labels['saveincalendar'] = 'uložit do';
$labels['updatemycopy'] = 'Aktualizovat v mém kalendáři';
$labels['savetocalendar'] = 'Uložit do kalenáře';
$labels['openpreview'] = 'Ověřit kalendář';
$labels['noearlierevents'] = 'Žádné dřívější události';
$labels['nolaterevents'] = 'Žádné pozdější události';
$labels['resource'] = 'Zdroj';
$labels['addresource'] = 'Zapsat zdroj';
$labels['findresources'] = 'Najít zdroje';
$labels['resourcedetails'] = 'Podrobnosti';
$labels['resourceavailability'] = 'Dostupnost';
$labels['resourceowner'] = 'Vlastník';
$labels['resourceadded'] = 'Zdroj byl přidán do vaší události';
$labels['tabsummary'] = 'Souhrn';
$labels['tabrecurrence'] = 'Opakování';
$labels['tabattendees'] = 'Účastníci';
$labels['tabresources'] = 'Zdroje';
$labels['tabattachments'] = 'Přílohy';
$labels['tabsharing'] = 'Sdílení';
$labels['deleteobjectconfirm'] = 'Opravdu chcete smazat tuto událost?';
$labels['deleteventconfirm'] = 'Opravdu chcete smazat tuto událost?';
$labels['deletecalendarconfirm'] = 'Opravdu chcete smazat tento kalendář se všemi událostmi?';
$labels['deletecalendarconfirmrecursive'] = 'Do you really want to delete this calendar with all its events and sub-calendars?';
$labels['savingdata'] = 'Ukládají se data...';
$labels['errorsaving'] = 'Nelze uložit změny.';
$labels['operationfailed'] = 'Požavovaná operace selhala.';
$labels['invalideventdates'] = 'Vložená data nejsou platná! Zkontrolujte prosím zadávané údaje.';
$labels['invalidcalendarproperties'] = 'Neplatné vlastnosti kalendáře! Vložte prosím platné jméno.';
$labels['searchnoresults'] = 'Ve vybraných kalendářích nebyly nalezeny žádné události.';
$labels['successremoval'] = 'Událost byla úspěšně smazána.';
$labels['successrestore'] = 'Událost byla úspěšně obnovena.';
$labels['errornotifying'] = 'Nelze odeslat notifikace účastníkům události';
$labels['errorimportingevent'] = 'Událost se nepodařilo zavést';
$labels['importwarningexists'] = 'Kopie této události již ve vašem kalendáři existuje.';
$labels['newerversionexists'] = 'Existuje již novější verze této události! Operace byla zrušena.';
$labels['nowritecalendarfound'] = 'Nebyl nalezen žádný kalendář, do kterého by šlo uložit tuto událost.';
$labels['importedsuccessfully'] = 'Událost byla úspěšně přidána do kalendáře \'$calendar\'';
$labels['updatedsuccessfully'] = 'Událost byla úspěšně aktualizována v \'$calendar\'';
$labels['attendeupdateesuccess'] = 'Stav účastníka byl úspěšně aktualizován';
$labels['itipsendsuccess'] = 'Pozvánky byly rozeslány účastníkům.';
$labels['itipresponseerror'] = 'Nelze odeslat odpověď na tuto pozvánku';
$labels['itipinvalidrequest'] = 'Tato pozvánka již není platná';
$labels['sentresponseto'] = 'Odpověď na pozvánku byla úspěšně odeslána na adresu $mailto';
$labels['localchangeswarning'] = 'Chystáte se provést změny, které se projeví jen ve vašem vlastním kalendáři a nebudou poslány organizátorovi události.';
$labels['importsuccess'] = 'Úspěšně zavedeno $nr událostí';
$labels['importnone'] = 'Nebyly nalezeny žádné události k zavedení';
$labels['importerror'] = 'Při zavádění došlo k chybě';
$labels['aclnorights'] = 'Nemáte administrátorská práva k tomuto kalendáři.';
$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['currentevent'] = 'Nynější';
$labels['futurevents'] = 'Budoucí';
$labels['allevents'] = 'Vše';
$labels['saveasnew'] = 'Uložit jako novou';
$labels['birthdays'] = 'Narozeniny';
$labels['birthdayscalendar'] = 'Kalendář narozenin';
$labels['displaybirthdayscalendar'] = 'Zobrazit kalendář narozenin';
$labels['birthdayscalendarsources'] = 'Z těchto adresářů';
$labels['birthdayeventtitle'] = 'Narozeniny $name';
$labels['birthdayage'] = 'Věk $age';
-$labels['eventchangelog'] = 'Historie změn';
+$labels['objectchangelog'] = 'Historie změn';
$labels['revision'] = 'Verze';
$labels['user'] = 'Uživatel';
$labels['operation'] = 'Činnost';
$labels['actionappend'] = 'Uloženo';
$labels['actionmove'] = 'Přesunuto';
$labels['actiondelete'] = 'Smazáno';
$labels['compare'] = 'Porovnat';
$labels['showrevision'] = 'Ukázat tuto verzi';
$labels['restore'] = 'Obnovit tuto verzi';
-$labels['eventnotfound'] = 'Nepodařilo se nahrát data události';
+$labels['objectnotfound'] = 'Nepodařilo se nahrát data události';
$labels['objectchangelognotavailable'] = 'Historie změn není pro tuto událost dostupná';
-$labels['eventdiffnotavailable'] = 'Pro vybrané verze není žádné srovnání možné';
+$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['arialabelminical'] = 'Výběr data v kalendáři';
$labels['arialabelcalendarview'] = 'Pohled na kalendář';
$labels['arialabelsearchform'] = 'Hledání události';
$labels['arialabelquicksearchbox'] = 'Zadání hledání události';
$labels['arialabelcalsearchform'] = 'Hledání kalendářů';
$labels['calendaractions'] = 'Činnosti v kalendáři';
$labels['arialabeleventattendees'] = 'Seznam účastníků události';
$labels['arialabeleventresources'] = 'Seznam zdrojů události';
$labels['arialabelresourcesearchform'] = 'Hledání zdrojů';
$labels['arialabelresourceselection'] = 'Dostupné zdroje';
?>
diff --git a/plugins/calendar/localization/da_DK.inc b/plugins/calendar/localization/da_DK.inc
index 05c9b71f..e44851e0 100644
--- a/plugins/calendar/localization/da_DK.inc
+++ b/plugins/calendar/localization/da_DK.inc
@@ -1,274 +1,274 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Standardvisning';
$labels['time_format'] = 'Tidsformat';
$labels['timeslots'] = 'Tidsblokke per time';
$labels['first_day'] = 'Første ugedag';
$labels['first_hour'] = 'Første time som vises';
$labels['workinghours'] = 'Arbejdstider';
$labels['add_category'] = 'Tilføj kategori';
$labels['remove_category'] = 'Fjern kategori';
$labels['defaultcalendar'] = 'Opret nye arragementer i';
$labels['eventcoloring'] = 'Farver for arrangementer';
$labels['coloringmode0'] = 'Ifølge kalender';
$labels['coloringmode1'] = 'Ifølge kategori';
$labels['coloringmode2'] = 'Kalender til oversigt, kategori til indhold';
$labels['coloringmode3'] = 'Kategori til oversigt, kalender til indhold';
$labels['afternothing'] = 'Undlad at gøre noget';
$labels['aftertrash'] = 'Flyt til papirkurv';
$labels['afterdelete'] = 'Slet beskeden';
$labels['afterflagdeleted'] = 'Markér som slettet';
$labels['aftermoveto'] = 'Flyt til ...';
$labels['itipoptions'] = 'Begivenhedsinvitationer';
$labels['afteraction'] = 'Efter en invitation eller opdateringsbesked er behandlet';
$labels['calendar'] = 'Kalender';
$labels['calendars'] = 'Kalendere';
$labels['category'] = 'Kategori';
$labels['categories'] = 'Kategorier';
$labels['createcalendar'] = 'Opret ny kalender';
$labels['editcalendar'] = 'Redigér kalenderegenskaber';
$labels['name'] = 'Navn';
$labels['color'] = 'Farve';
$labels['day'] = 'Dag';
$labels['week'] = 'Uge';
$labels['month'] = 'Måned';
$labels['agenda'] = 'Dagsorden';
$labels['new'] = 'Ny';
$labels['new_event'] = 'Nyt arrangement';
$labels['edit_event'] = 'Redigér arrangement';
$labels['edit'] = 'Redigér';
$labels['save'] = 'Gem';
$labels['removelist'] = 'Remove from list';
$labels['cancel'] = 'Annullér';
$labels['select'] = 'Vælg';
$labels['print'] = 'Udskriv';
$labels['printtitle'] = 'Udskriv kalendere';
$labels['title'] = 'Resumé';
$labels['description'] = 'Beskrivelse';
$labels['all-day'] = 'hele-dagen';
$labels['export'] = 'Eksport';
$labels['exporttitle'] = 'Eksportér til iCalendar';
$labels['exportrange'] = 'Arrangementer fra';
$labels['exportattachments'] = 'Med vedhæftninger';
$labels['customdate'] = 'Brugerdefineret dato';
$labels['location'] = 'Placering';
$labels['url'] = 'URL';
$labels['date'] = 'Dato';
$labels['start'] = 'Start';
$labels['starttime'] = 'Start time';
$labels['end'] = 'Slut';
$labels['endtime'] = 'Sluttidspunkt';
$labels['repeat'] = 'Gentag';
$labels['selectdate'] = 'Vælg dato';
$labels['freebusy'] = 'Vis mig som';
$labels['free'] = 'Ledig';
$labels['busy'] = 'Optaget';
$labels['outofoffice'] = 'Ikke på kontoret';
$labels['tentative'] = 'Forsøgsvis';
$labels['mystatus'] = 'Min status';
$labels['status'] = 'Status';
$labels['status-confirmed'] = 'Bekræftet';
$labels['status-cancelled'] = 'Annulleret';
$labels['priority'] = 'Prioritet';
$labels['sensitivity'] = 'Privatliv';
$labels['public'] = 'offentlig';
$labels['private'] = 'privat';
$labels['confidential'] = 'fortrolig';
$labels['links'] = 'Reference';
$labels['alarms'] = 'Påmindelse';
$labels['comment'] = 'Comment';
$labels['created'] = 'Created';
$labels['changed'] = 'Last Modified';
$labels['unknown'] = 'Ukendt';
$labels['eventoptions'] = 'Tilvalg';
$labels['generated'] = 'oprettet per';
$labels['eventhistory'] = 'Historik';
$labels['removelink'] = 'Remove email reference';
$labels['printdescriptions'] = 'Udskriv beskrivelser';
$labels['parentcalendar'] = 'Indsæt indeni';
$labels['searchearlierdates'] = '« Søg efter tidligere arrangementer';
$labels['searchlaterdates'] = 'Søg efter senere arrangementer »';
$labels['andnmore'] = '$nr flere...';
$labels['togglerole'] = 'Klik for at vise eller skjule rolle';
$labels['createfrommail'] = 'Gem som arrangement';
$labels['importevents'] = 'Importér arrangement';
$labels['importrange'] = 'Arrangementer fra';
$labels['onemonthback'] = '1 måned tilbage';
$labels['nmonthsback'] = '$nr måneder tilbage';
$labels['showurl'] = 'Vis kalenderens URL';
$labels['showurldescription'] = 'Brug følgende adresse for at tilgå din kalender (skrivebeskyttet) fra andre programmer. Du kan kopiere og indsætet denne i ethvert kalenderprogram, der understøtter iCal-formatet.';
$labels['caldavurldescription'] = 'Kopiér denne adresse til en <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a>-klientprogram (eks. Evolution eller Mozilla Thunderbird) for at synkronisere denne kalender komplet med din computer eller mobilenhed.';
$labels['findcalendars'] = 'Find kalendere ...';
$labels['searchterms'] = 'Search terms';
$labels['calsearchresults'] = 'Tilgængelige kalendere';
$labels['calendarsubscribe'] = 'List permanently';
$labels['nocalendarsfound'] = 'Der blev ikke fundet nogen kalender';
$labels['nrcalendarsfound'] = '$nr kalendere blev fundet';
$labels['quickview'] = 'Vis kun denne kalender';
$labels['invitationspending'] = 'Afventende invitationer';
$labels['invitationsdeclined'] = 'Afviste invitationer';
$labels['changepartstat'] = 'Skift deltagerstatus';
$labels['rsvpcomment'] = 'Invitationstekst';
$labels['listrange'] = 'Interval som skal vises:';
$labels['listsections'] = 'Del op i:';
$labels['smartsections'] = 'Smarte sektioner';
$labels['until'] = 'indtil';
$labels['today'] = 'I dag';
$labels['tomorrow'] = 'I morgen';
$labels['thisweek'] = 'Denne uge';
$labels['nextweek'] = 'Næste uge';
$labels['prevweek'] = 'Forrige uge';
$labels['thismonth'] = 'Denne måned';
$labels['nextmonth'] = 'Næste måned';
$labels['weekofyear'] = 'Uge';
$labels['pastevents'] = 'Tidligere';
$labels['futureevents'] = 'Fremtid';
$labels['showalarms'] = 'Show reminders';
$labels['defaultalarmtype'] = 'Standardindstilling for påmindelse';
$labels['defaultalarmoffset'] = 'Standardtidspunkt for påmindelse';
$labels['attendee'] = 'Deltager';
$labels['role'] = 'Rolle';
$labels['availability'] = 'Tilg.';
$labels['confirmstate'] = 'Status';
$labels['addattendee'] = 'Tilføj deltager';
$labels['roleorganizer'] = 'Organisator';
$labels['rolerequired'] = 'Påkrævet';
$labels['roleoptional'] = 'Valgfri';
$labels['rolechair'] = 'Formand';
$labels['rolenonparticipant'] = 'Fraværende';
$labels['cutypeindividual'] = 'Individuel';
$labels['cutypegroup'] = 'Gruppe';
$labels['cutyperesource'] = 'Ressource';
$labels['cutyperoom'] = 'Lokale';
$labels['availfree'] = 'Ledig';
$labels['availbusy'] = 'Optaget';
$labels['availunknown'] = 'Ukendt';
$labels['availtentative'] = 'Forsøgsvis';
$labels['availoutofoffice'] = 'Ikke på kontoret';
$labels['delegatedto'] = 'Delegated to: ';
$labels['delegatedfrom'] = 'Delegated from: ';
$labels['scheduletime'] = 'Find ledigt tidspunkt';
$labels['sendinvitations'] = 'Send invitationer';
$labels['sendnotifications'] = 'Gør deltagere opmærksom på ændringer';
$labels['sendcancellation'] = 'Giv deltagere besked om aflysning af arrangementer';
$labels['onlyworkinghours'] = 'Find ledigt tidspunkt inden for mine arbejdstider';
$labels['reqallattendees'] = 'Påkrævet/alle deltagere';
$labels['prevslot'] = 'Forrige blok';
$labels['nextslot'] = 'Næste blok';
$labels['suggestedslot'] = 'Foreslået blok';
$labels['noslotfound'] = 'Kunne ikke finde en ledig tidsblok';
$labels['invitationsubject'] = 'Du er blevet inviteret til "$title"';
$labels['invitationmailbody'] = "*\$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['invitationattendlinks'] = "Hvis dit e-postprogram ikke understøtter iTip-forespørgsler, så kan du benytte følgende henvisning til enten at acceptere eller afvise denne invitation:\n\$url";
$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";
$labels['itipmailbodytentative'] = "\$sender har forsøgsvist accepteret invitationen til det følgende arrangement:\n\n*\$title*\n\nTidspunkt: \$date\n\nInviterede: \$attendees";
$labels['itipmailbodydeclined'] = "\$sender har afvist invitationen til det følgende arrangement:\n\n*\$title*\n\nTidspunkt: \$date\n\nInviterede: \$attendees";
$labels['itipmailbodycancel'] = "\$sender har afvist din deltagelse i følgende begivenhed:\n\n*\$title*\n\nTidspunkt: \$date";
$labels['itipmailbodydelegated'] = "\$sender har delegeret deltagelsen i følgende begivenhed:\n\n*\$title*\n\nTidspunkt: \$date";
$labels['itipmailbodydelegatedto'] = "\$sender har delegeret deltagelsen i følgende begivenhed til dig:\n\n*\$title*\n\nTidspunkt: \$date";
$labels['itipdeclineevent'] = 'Sikker på at du vil afvise dette arrangement?';
$labels['declinedeleteconfirm'] = 'Vil du også slette dette afviste arrangement fra din kalender?';
$labels['itipcomment'] = 'Invitation/notification comment';
$labels['itipcommenttitle'] = 'Denne kommentar vil blive føjet til den besked med invitation/notifikation, der sendes til deltagerne';
$labels['notanattendee'] = 'Du er ikke opført som deltager for dette arrangement';
$labels['eventcancelled'] = 'Arrangementet er blevet aflyst';
$labels['saveincalendar'] = 'gem i';
$labels['updatemycopy'] = 'Opdatér i min kalender';
$labels['savetocalendar'] = 'Gem til kalender';
$labels['openpreview'] = 'Tjek kalender';
$labels['noearlierevents'] = 'Ingen tidligere begivenheder';
$labels['nolaterevents'] = 'Ingen senere begivenheder';
$labels['resource'] = 'Ressource';
$labels['addresource'] = 'Booking af ressource';
$labels['findresources'] = 'Find ressourcer';
$labels['resourcedetails'] = 'Detaljer';
$labels['resourceavailability'] = 'Tilgængelighed';
$labels['resourceowner'] = 'Ejer';
$labels['resourceadded'] = 'Ressourcen til føjet til din begivenhed';
$labels['tabsummary'] = 'Resumé';
$labels['tabrecurrence'] = 'Gentagelse';
$labels['tabattendees'] = 'Deltagere';
$labels['tabresources'] = 'Ressourcer';
$labels['tabattachments'] = 'Vedhæftninger';
$labels['tabsharing'] = 'Deling';
$labels['deleteobjectconfirm'] = 'Sikker på at du vil slette dette arrangement?';
$labels['deleteventconfirm'] = 'Sikker på at du vil slette dette arrangement?';
$labels['deletecalendarconfirm'] = 'Sikker på at du vil slette denne kalender med alle dets arrangementer?';
$labels['deletecalendarconfirmrecursive'] = 'Sikker på du vil slette denne kalender med alle dens arrangementer og delkalendere?';
$labels['savingdata'] = 'Gemmer data...';
$labels['errorsaving'] = 'Kunne ikke gemme ændringer.';
$labels['operationfailed'] = 'Den forespurgte handling mislykkedes.';
$labels['invalideventdates'] = 'Ugyldig dato indtastet! Tjek venligst dit input.';
$labels['invalidcalendarproperties'] = 'Ugyldige kalenderegenskaber! Angiv venligst et gyldigt navn.';
$labels['searchnoresults'] = 'Der blev ikke fundet arrangementer i de valgte kalendere.';
$labels['successremoval'] = 'Sletning af arrangementet blev gennemført.';
$labels['successrestore'] = 'Gendannelse af arrangementet blev gennemført.';
$labels['errornotifying'] = 'Kunne ikke sende notifikation til arrangementets deltagere';
$labels['errorimportingevent'] = 'Kunne ikke importere arrangementet';
$labels['importwarningexists'] = 'En kopi af denne begivenhed findes allerede i din kalender.';
$labels['newerversionexists'] = 'Der findes allerede en nyere version af arrangementet! Afbrød.';
$labels['nowritecalendarfound'] = 'Ingen funden kalender til lagring af arrangementet';
$labels['importedsuccessfully'] = 'Arrangementet blev tilføjet til \'$calendar\'';
$labels['updatedsuccessfully'] = 'Opdatering af begivenheden blev gennemført i "$calendar"';
$labels['attendeupdateesuccess'] = 'Opdatering af deltagernes status blev gennemført';
$labels['itipsendsuccess'] = 'Invitation blev sendt til deltagerne.';
$labels['itipresponseerror'] = 'Kunne ikke sende svar til denne arrangementsinvitation';
$labels['itipinvalidrequest'] = 'Denne invitation er ikke længere gyldig';
$labels['sentresponseto'] = 'Gennemførte afsendelse af invitationssvar til $mailto';
$labels['localchangeswarning'] = 'Du er i færd med at foretage ændringer, der vil påvirke din kalender og som ikke vil blive sendt til afholderen af arrangementet.';
$labels['importsuccess'] = 'Gennemførte import af $nr arrangementer';
$labels['importnone'] = 'Fandt ingen arrangementer som kunne importeres';
$labels['importerror'] = 'Der opstod en fejl under import';
$labels['aclnorights'] = 'Du har ikke administratorrettigheder for denne kalender.';
$labels['changeeventconfirm'] = 'Tilpas arrangement';
$labels['removeeventconfirm'] = 'Slet begivenhed';
$labels['changerecurringeventwarning'] = 'Dette er et tilbagevendende arrangement. Ønsker du kun at redige det aktuelle arrangement, dette og alle fremtidige forekomster, alle forekomster eller gemme det som et nyt arrangement?';
$labels['removerecurringeventwarning'] = 'Dette er en tilbagevendende begivenhed. Ønsker du kun at fjerne den aktuelle begivenhed, denne og alle fremtidige forekomster for denne begivenhed?';
$labels['removerecurringallonly'] = 'Dette er en tilbagevendende begivenhed. Som deltager kan du slette kun slette hele begivenheden med alle dens forekomster.';
$labels['currentevent'] = 'Nuværende';
$labels['futurevents'] = 'Fremtid';
$labels['allevents'] = 'Alle';
$labels['saveasnew'] = 'Gem som ny';
$labels['birthdays'] = 'Fødselsdage';
$labels['birthdayscalendar'] = 'Fødselsdagskalender';
$labels['displaybirthdayscalendar'] = 'Vis fødselsdagskalender';
$labels['birthdayscalendarsources'] = 'Fra disse adressebøger';
$labels['birthdayeventtitle'] = '$name har fødselsdag';
$labels['birthdayage'] = '$age år';
-$labels['eventchangelog'] = 'Ændringshistorik';
+$labels['objectchangelog'] = 'Ændringshistorik';
$labels['revision'] = 'Revision';
$labels['user'] = 'Bruger';
$labels['operation'] = 'Handling';
$labels['actionappend'] = 'Gemt';
$labels['actionmove'] = 'Flyttet';
$labels['actiondelete'] = 'Slettet';
$labels['compare'] = 'Sammenlign';
$labels['showrevision'] = 'Vis denne version';
$labels['restore'] = 'Genskab denne version';
-$labels['eventnotfound'] = 'Kunne ikke indlæse begivenhedsdata';
+$labels['objectnotfound'] = 'Kunne ikke indlæse begivenhedsdata';
$labels['objectchangelognotavailable'] = 'Ændringshistorikken er ikke tilgængelig for denne begivenhed';
-$labels['eventdiffnotavailable'] = 'Det er ikke muligt at sammenligne de valgte revisioner';
+$labels['objectdiffnotavailable'] = 'Det er ikke muligt at sammenligne de valgte revisioner';
$labels['revisionrestoreconfirm'] = 'Sikker på at du vil genskabe revision $rev af denne begivenhed? Dette vil erstatte den nuværende begivenhed med den tidligere version.';
$labels['arialabelminical'] = 'Valg af kalenderdato';
$labels['arialabelcalendarview'] = 'Kalendervisning';
$labels['arialabelsearchform'] = 'Søgeformular for begivenheder';
$labels['arialabelquicksearchbox'] = 'Søgeinput for begivenhed';
$labels['arialabelcalsearchform'] = 'Søgeformular for kalendere';
$labels['calendaractions'] = 'Kalenderhandlinger';
$labels['arialabeleventattendees'] = 'Deltagerliste for begivenhed';
$labels['arialabeleventresources'] = 'Ressourceliste for begivenhed';
$labels['arialabelresourcesearchform'] = 'Søgeformular for ressourcer';
$labels['arialabelresourceselection'] = 'Tilgængelige ressourcer';
?>
diff --git a/plugins/calendar/localization/de_CH.inc b/plugins/calendar/localization/de_CH.inc
index 1bbf4645..91726cac 100644
--- a/plugins/calendar/localization/de_CH.inc
+++ b/plugins/calendar/localization/de_CH.inc
@@ -1,186 +1,184 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Ansicht';
$labels['time_format'] = 'Zeitformatierung';
$labels['first_day'] = 'Erster Wochentag';
$labels['first_hour'] = 'Erste angezeigte Stunde';
$labels['workinghours'] = 'Arbeitszeiten';
$labels['add_category'] = 'Kategorie hinzufügen';
$labels['remove_category'] = 'Kategorie entfernen';
$labels['defaultcalendar'] = 'Neue Termine erstellen in';
$labels['eventcoloring'] = 'Färbung der Termine';
$labels['coloringmode0'] = 'Farbe des Kalenders';
$labels['coloringmode1'] = 'Farbe der Kategorie';
$labels['coloringmode2'] = 'Kalenderfarbe aussen, Kategoriefarbe innen';
$labels['coloringmode3'] = 'Kategoriefarbe aussen, Kalenderfarbe innen';
$labels['calendar'] = 'Kalender';
$labels['calendars'] = 'Kalender';
$labels['category'] = 'Kategorie';
$labels['categories'] = 'Kategorien';
$labels['createcalendar'] = 'Neuen Kalender erstellen';
$labels['editcalendar'] = 'Kalendereigenschaften bearbeiten';
$labels['name'] = 'Name';
$labels['color'] = 'Farbe';
$labels['day'] = 'Tag';
$labels['week'] = 'Woche';
$labels['month'] = 'Monat';
$labels['agenda'] = 'Agenda';
$labels['new'] = 'Neu';
$labels['new_event'] = 'Neuer Termin';
$labels['edit_event'] = 'Termin bearbeiten';
$labels['edit'] = 'Bearbeiten';
$labels['save'] = 'Speichern';
-$labels['removelist'] = 'Remove from list';
$labels['cancel'] = 'Abbrechen';
$labels['select'] = 'Auswählen';
$labels['print'] = 'Drucken';
$labels['printtitle'] = 'Kalender drucken';
$labels['title'] = 'Titel';
$labels['description'] = 'Beschrieb';
$labels['all-day'] = 'ganztägig';
$labels['export'] = 'Exportieren';
$labels['exporttitle'] = 'Kalender als iCalendar exportieren';
$labels['exportrange'] = 'Termine ab';
$labels['location'] = 'Ort';
$labels['url'] = 'URL';
$labels['date'] = 'Datum';
$labels['start'] = 'Beginn';
$labels['end'] = 'Ende';
$labels['repeat'] = 'Wiederholung';
$labels['selectdate'] = 'Datum auswählen';
$labels['freebusy'] = 'Zeige mich als';
$labels['free'] = 'Frei';
$labels['busy'] = 'Gebucht';
$labels['outofoffice'] = 'Abwesend';
$labels['tentative'] = 'Mit Vorbehalt';
$labels['status'] = 'Status';
$labels['status-confirmed'] = 'Bestätigt';
$labels['status-cancelled'] = 'Gekündigt';
$labels['priority'] = 'Priorität';
$labels['sensitivity'] = 'Sichtbarkeit';
$labels['public'] = 'öffentlich';
$labels['private'] = 'privat';
$labels['confidential'] = 'vertraulich';
$labels['alarms'] = 'Erinnerung';
$labels['comment'] = 'Kommentar';
$labels['unknown'] = 'Unbekannt';
$labels['generated'] = 'erstellt am';
$labels['printdescriptions'] = 'Beschrieb drucken';
$labels['parentcalendar'] = 'Erstellen in';
$labels['searchearlierdates'] = '« Frühere Termine suchen';
$labels['searchlaterdates'] = 'Spätere Termine suchen »';
$labels['andnmore'] = '$nr weitere...';
$labels['togglerole'] = 'Zum Ändern der Rolle klicken';
$labels['createfrommail'] = 'Als Termin speichern';
$labels['importevents'] = 'Termine importieren';
$labels['importrange'] = 'Termine ab';
$labels['onemonthback'] = '1 Monat zurück';
$labels['nmonthsback'] = '$nr Monate zurück';
$labels['showurl'] = 'URL anzeigen';
$labels['showurldescription'] = 'Über die folgende Adresse können Sie mit einem beliebigen Kalenderprogramm Ihren Kalender abrufen (nur lesend), sofern dieses das iCal-Format unterstützt.';
$labels['listrange'] = 'Angezeigter Bereich:';
$labels['listsections'] = 'Unterteilung:';
$labels['smartsections'] = 'Intelligent';
$labels['until'] = 'bis';
$labels['today'] = 'Heute';
$labels['tomorrow'] = 'Morgen';
$labels['thisweek'] = 'Diese Woche';
$labels['nextweek'] = 'Nächste Woche';
$labels['thismonth'] = 'Diesen Monat';
$labels['nextmonth'] = 'Nächsten Monat';
$labels['weekofyear'] = 'KW';
$labels['pastevents'] = 'Vergangene';
$labels['futureevents'] = 'Zukünftige';
$labels['defaultalarmtype'] = 'Standard-Erinnerungseinstellung';
$labels['defaultalarmoffset'] = 'Standard-Erinnerungszeit';
$labels['attendee'] = 'Teilnehmer';
$labels['role'] = 'Rolle';
$labels['availability'] = 'Verfüg.';
$labels['confirmstate'] = 'Status';
$labels['addattendee'] = 'Hinzufügen';
$labels['roleorganizer'] = 'Organisator';
$labels['rolerequired'] = 'Erforderlich';
$labels['roleoptional'] = 'Optional';
$labels['availfree'] = 'Frei';
$labels['availbusy'] = 'Gebucht';
$labels['availunknown'] = 'Unbekannt';
$labels['availtentative'] = 'Mit Vorbehalt';
$labels['availoutofoffice'] = 'Abwesend';
$labels['scheduletime'] = 'Verfügbarkeit anzeigen';
$labels['sendinvitations'] = 'Einladungen versenden';
$labels['sendnotifications'] = 'Teilnehmer über die Änderungen informieren';
$labels['sendcancellation'] = 'Teilnehmer über die Terminabsage informieren';
$labels['onlyworkinghours'] = 'Verfügbarkeit innerhalb meiner Arbeitszeiten suchen';
$labels['reqallattendees'] = 'Erforderliche/alle Teilnehmer';
$labels['prevslot'] = 'Vorheriger Vorschlag';
$labels['nextslot'] = 'Nächster Vorschlag';
$labels['noslotfound'] = 'Es konnten keine freien Zeiten gefunden werden';
$labels['invitationsubject'] = 'Sie wurden zu "$title" eingeladen';
$labels['invitationmailbody'] = "*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees\n\nIm Anhang finden Sie eine iCalendar-Datei mit allen Details des Termins. Diese können Sie in Ihre Kalenderanwendung importieren.";
$labels['invitationattendlinks'] = "Falls Ihr E-Mail-Programm keine iTip-Anfragen unterstützt, können Sie den folgenden Link verwenden, um den Termin zu bestätigen oder abzulehnen:\n\$url";
$labels['eventupdatesubject'] = '"$title" wurde aktualisiert';
$labels['eventupdatesubjectempty'] = 'Termin wurde aktualisiert';
$labels['eventupdatemailbody'] = "*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees\n\nIm Anhang finden Sie eine iCalendar-Datei mit den aktualisiereten Termindaten. Diese können Sie in Ihre Kalenderanwendung importieren.";
$labels['eventcancelsubject'] = '"$title" wurde abgesagt';
$labels['eventcancelmailbody'] = "*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees\n\nDer Termin wurde von \$organizer abgesagt.\n\nIm Anhang finden Sie eine iCalendar-Datei mit den Termindaten.";
$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['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['notanattendee'] = 'Sie sind nicht in der Liste der Teilnehmer aufgeführt';
$labels['eventcancelled'] = 'Der Termin wurde vom Organisator abgesagt';
$labels['saveincalendar'] = 'speichern in';
$labels['resource'] = 'Ressource';
$labels['resourcedetails'] = 'Details';
$labels['tabsummary'] = 'Übersicht';
$labels['tabrecurrence'] = 'Wiederholung';
$labels['tabattendees'] = 'Teilnehmer';
$labels['tabattachments'] = 'Anhänge';
$labels['tabsharing'] = 'Freigabe';
$labels['deleteobjectconfirm'] = 'Möchten Sie diesen Termin wirklich löschen?';
$labels['deleteventconfirm'] = 'Möchten Sie diesen Termin wirklich löschen?';
$labels['deletecalendarconfirm'] = 'Möchten Sie diesen Kalender mit allen Terminen wirklich löschen?';
$labels['savingdata'] = 'Speichere Daten...';
$labels['errorsaving'] = 'Fehler beim Speichern.';
$labels['operationfailed'] = 'Die Aktion ist fehlgeschlagen.';
$labels['invalideventdates'] = 'Ungültige Daten eingegeben! Bitte überprüfen Sie die Eingaben.';
$labels['invalidcalendarproperties'] = 'Ungültige Kalenderinformationen! Bitte geben Sie einen Namen ein.';
$labels['searchnoresults'] = 'Keine Termine in den gewählten Kalendern gefunden.';
$labels['successremoval'] = 'Der Termin wurde erfolgreich gelöscht.';
$labels['successrestore'] = 'Der Termin wurde erfolgreich wieder hergestellt.';
$labels['errornotifying'] = 'Benachrichtigung an die Teilnehmer konnten nicht gesendet werden';
$labels['errorimportingevent'] = 'Fehler beim Importieren';
$labels['newerversionexists'] = 'Eine neuere Version dieses Termins exisitert bereits! Import abgebrochen.';
$labels['nowritecalendarfound'] = 'Kein Kalender zum Speichern gefunden';
$labels['importedsuccessfully'] = 'Der Termin wurde erfolgreich in \'$calendar\' gespeichert';
$labels['attendeupdateesuccess'] = 'Teilnehmerstatus erfolgreich aktualisiert';
$labels['itipsendsuccess'] = 'Einladung an Teilnehmer versendet.';
$labels['itipresponseerror'] = 'Die Antwort auf diese Einladung konnte nicht versendet werden';
$labels['itipinvalidrequest'] = 'Diese Einladung ist nicht mehr gültig';
$labels['sentresponseto'] = 'Antwort auf diese Einladung erfolgreich an $mailto gesendet';
-$labels['localchangeswarning'] = 'You are about to make changes that will only be reflected on your calendar and not be sent to the organizer of the event.';
$labels['importsuccess'] = 'Es wurden $nr Termine erfolgreich importiert';
$labels['importnone'] = 'Keine Termine zum Importieren gefunden';
$labels['importerror'] = 'Fehler beim Importieren';
$labels['aclnorights'] = 'Sie haben keine Administrator-Rechte für diesen Kalender.';
$labels['changeeventconfirm'] = 'Termin ändern';
$labels['changerecurringeventwarning'] = 'Dies ist eine Terminreihe. Möchten Sie nur den aktuellen, diesen und alle zukünftigen oder alle Termine bearbeiten oder die Änderungen als neuen Termin speichern?';
$labels['currentevent'] = 'Aktuellen';
$labels['futurevents'] = 'Zukünftige';
$labels['allevents'] = 'Alle';
$labels['saveasnew'] = 'Als neu speichern';
$labels['birthdays'] = 'Geburtstage';
$labels['birthdayscalendar'] = 'Geburtstags-Kalender';
$labels['displaybirthdayscalendar'] = 'Geburtstags-Kalender anzeigen';
$labels['birthdayscalendarsources'] = 'Für diese Adressbücher';
$labels['birthdayeventtitle'] = '$names Geburtstag';
$labels['birthdayage'] = 'Alter $age';
$labels['actiondelete'] = 'Gelöscht';
?>
diff --git a/plugins/calendar/localization/de_DE.inc b/plugins/calendar/localization/de_DE.inc
index ab5a5af9..8d729855 100644
--- a/plugins/calendar/localization/de_DE.inc
+++ b/plugins/calendar/localization/de_DE.inc
@@ -1,277 +1,277 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Standardansicht';
$labels['time_format'] = 'Zeitformatierung';
$labels['timeslots'] = 'Time slots per hour';
$labels['first_day'] = 'Erster Wochentag';
$labels['first_hour'] = 'Erste angezeigte Stunde';
$labels['workinghours'] = 'Arbeitszeiten';
$labels['add_category'] = 'Kategorie hinzufügen';
$labels['remove_category'] = 'Kategorie entfernen';
$labels['defaultcalendar'] = 'Neue Termine erstellen in';
$labels['eventcoloring'] = 'Färbung der Termine';
$labels['coloringmode0'] = 'Farbe des Kalenders';
$labels['coloringmode1'] = 'Farbe der Kategorie';
$labels['coloringmode2'] = 'Kalenderfarbe außen, Kategoriefarbe innen';
$labels['coloringmode3'] = 'Kategoriefarbe außen, Kalenderfarbe innen';
$labels['afternothing'] = 'nichts unternehmen';
$labels['aftertrash'] = 'In den Papierkorb verschieben';
$labels['afterdelete'] = 'Nachricht löschen';
$labels['afterflagdeleted'] = 'Als gelöscht markieren';
$labels['aftermoveto'] = 'Verschiebe nach...';
$labels['itipoptions'] = 'Veranstaltungseinladungen';
$labels['afteraction'] = 'Nachdem eine Einladungs- oder Update-Nachricht verarbetet wurde';
$labels['calendar'] = 'Kalender';
$labels['calendars'] = 'Kalender';
$labels['category'] = 'Kategorie';
$labels['categories'] = 'Kategorien';
$labels['createcalendar'] = 'Neuen Kalender erstellen';
$labels['editcalendar'] = 'Kalendereigenschaften bearbeiten';
$labels['name'] = 'Name';
$labels['color'] = 'Farbe';
$labels['day'] = 'Tag';
$labels['week'] = 'Woche';
$labels['month'] = 'Monat';
$labels['agenda'] = 'Agenda';
$labels['new'] = 'Neu';
$labels['new_event'] = 'Neuer Termin';
$labels['edit_event'] = 'Termin bearbeiten';
$labels['edit'] = 'Bearbeiten';
$labels['save'] = 'Speichern';
$labels['removelist'] = 'Von der Liste entfernen';
$labels['cancel'] = 'Abbrechen';
$labels['select'] = 'Auswählen';
$labels['print'] = 'Drucken';
$labels['printtitle'] = 'Kalender drucken';
$labels['title'] = 'Titel';
$labels['description'] = 'Beschreibung';
$labels['all-day'] = 'ganztägig';
$labels['export'] = 'Exportieren';
$labels['exporttitle'] = 'Kalender als iCalendar exportieren';
$labels['exportrange'] = 'Termine ab';
$labels['exportattachments'] = 'Mit Anhängen';
$labels['customdate'] = 'Benutzerdefiniertes Datum';
$labels['location'] = 'Ort';
$labels['url'] = 'URL';
$labels['date'] = 'Datum';
$labels['start'] = 'Beginn';
$labels['starttime'] = 'Startzeit';
$labels['end'] = 'Ende';
$labels['endtime'] = 'Endzeit';
$labels['repeat'] = 'Wiederholung';
$labels['selectdate'] = 'Datum auswählen';
$labels['freebusy'] = 'Zeige mich als';
$labels['free'] = 'Frei';
$labels['busy'] = 'Gebucht';
$labels['outofoffice'] = 'Abwesend';
$labels['tentative'] = 'Mit Vorbehalt';
$labels['mystatus'] = 'Mein Status';
$labels['status'] = 'Status';
$labels['status-confirmed'] = 'Bestätigt';
$labels['status-cancelled'] = 'Abgesagt';
$labels['priority'] = 'Priorität';
$labels['sensitivity'] = 'Sichtbarkeit';
$labels['public'] = 'öffentlich';
$labels['private'] = 'privat';
$labels['confidential'] = 'vertraulich';
$labels['links'] = 'Referenz';
$labels['alarms'] = 'Erinnerung';
$labels['comment'] = 'Kommentar';
$labels['created'] = 'Erstellt';
$labels['changed'] = 'Geändert';
$labels['unknown'] = 'Unbekannt';
$labels['eventoptions'] = 'Optionen';
$labels['generated'] = 'erstellt am';
$labels['eventhistory'] = 'Historie';
$labels['removelink'] = 'E-Mail-Referenz entfernen';
$labels['printdescriptions'] = 'Beschreibung drucken';
$labels['parentcalendar'] = 'Erstellen in';
$labels['searchearlierdates'] = '« Frühere Termine suchen';
$labels['searchlaterdates'] = 'Spätere Termine suchen »';
$labels['andnmore'] = '$nr weitere...';
$labels['togglerole'] = 'Zum Ändern der Rolle klicken';
$labels['createfrommail'] = 'Als Termin speichern';
$labels['importevents'] = 'Termine importieren';
$labels['importrange'] = 'Termine ab';
$labels['onemonthback'] = '1 Monat zurück';
$labels['nmonthsback'] = '$nr Monate zurück';
$labels['showurl'] = 'URL anzeigen';
$labels['showurldescription'] = 'Über die folgende Adresse können Sie mit einem beliebigen Kalenderprogramm Ihren Kalender abrufen (nur lesend), sofern dieses das iCal-Format unterstützt.';
$labels['caldavurldescription'] = 'Diese Adresse in einen <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a>-Klienten (z.B. Evolution oder Mozilla Thunderbird) kopieren, um den Kalender in Gänze mit einem mobilen Gerät zu synchronisieren.';
$labels['findcalendars'] = 'Kalender finden...';
$labels['searchterms'] = 'Suchbegriffe';
$labels['calsearchresults'] = 'Verfügbare Kalender';
$labels['calendarsubscribe'] = 'Permanent anzeigen';
$labels['nocalendarsfound'] = 'Keine Kalender gefunden';
$labels['nrcalendarsfound'] = '$nr Kalender gefunden';
$labels['quickview'] = 'Nur diesen Kalender anzeigen';
$labels['invitationspending'] = 'Ausstehende Einladungen';
$labels['invitationsdeclined'] = 'Abgelehnte Einladungen';
$labels['changepartstat'] = 'Teilnehmerstatus ändern';
$labels['rsvpcomment'] = 'Einladungstext';
$labels['listrange'] = 'Angezeigter Bereich:';
$labels['listsections'] = 'Unterteilung:';
$labels['smartsections'] = 'Intelligent';
$labels['until'] = 'bis';
$labels['today'] = 'Heute';
$labels['tomorrow'] = 'Morgen';
$labels['thisweek'] = 'Diese Woche';
$labels['nextweek'] = 'Nächste Woche';
$labels['prevweek'] = 'Vorige Woche';
$labels['thismonth'] = 'Diesen Monat';
$labels['nextmonth'] = 'Nächsten Monat';
$labels['weekofyear'] = 'Woche';
$labels['pastevents'] = 'Vergangene';
$labels['futureevents'] = 'Zukünftige';
$labels['showalarms'] = 'Show reminders';
$labels['defaultalarmtype'] = 'Standard-Erinnerungseinstellung';
$labels['defaultalarmoffset'] = 'Standard-Erinnerungszeit';
$labels['attendee'] = 'Teilnehmer';
$labels['role'] = 'Rolle';
$labels['availability'] = 'Verfüg.';
$labels['confirmstate'] = 'Status';
$labels['addattendee'] = 'Hinzufügen';
$labels['roleorganizer'] = 'Organisator';
$labels['rolerequired'] = 'Erforderlich';
$labels['roleoptional'] = 'Optional';
$labels['rolechair'] = 'Vorsitz';
$labels['rolenonparticipant'] = 'Absent';
$labels['cutypeindividual'] = 'Person';
$labels['cutypegroup'] = 'Gruppe';
$labels['cutyperesource'] = 'Ressource';
$labels['cutyperoom'] = 'Raum';
$labels['availfree'] = 'Frei';
$labels['availbusy'] = 'Gebucht';
$labels['availunknown'] = 'Unbekannt';
$labels['availtentative'] = 'Mit Vorbehalt';
$labels['availoutofoffice'] = 'Abwesend';
$labels['delegatedto'] = 'Delegiert an:';
$labels['delegatedfrom'] = 'Delegiert von:';
$labels['scheduletime'] = 'Verfügbarkeit anzeigen';
$labels['sendinvitations'] = 'Einladungen versenden';
$labels['sendnotifications'] = 'Teilnehmer über die Änderungen informieren';
$labels['sendcancellation'] = 'Teilnehmer über die Terminabsage informieren';
$labels['onlyworkinghours'] = 'Verfügbarkeit innerhalb meiner Arbeitszeiten suchen';
$labels['reqallattendees'] = 'Erforderliche/alle Teilnehmer';
$labels['prevslot'] = 'Vorheriger Vorschlag';
$labels['nextslot'] = 'Nächster Vorschlag';
$labels['suggestedslot'] = 'Empfohlener Slot';
$labels['noslotfound'] = 'Es konnten keine freien Zeiten gefunden werden';
$labels['invitationsubject'] = 'Sie wurden zu "$title" eingeladen';
$labels['invitationmailbody'] = "*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees\n\nIm Anhang finden Sie eine iCalendar-Datei mit allen Details des Termins. Diese können Sie in Ihre Kalenderanwendung importieren.";
$labels['invitationattendlinks'] = "Falls Ihr E-Mail-Programm keine iTip-Anfragen unterstützt, können Sie den folgenden Link verwenden, um den Termin zu bestätigen oder abzulehnen:\n\$url";
$labels['eventupdatesubject'] = '"$title" wurde aktualisiert';
$labels['eventupdatesubjectempty'] = 'Termin wurde aktualisiert';
$labels['eventupdatemailbody'] = "*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees\n\nIm Anhang finden Sie eine iCalendar-Datei mit den aktualisiereten Termindaten. Diese können Sie in Ihre Kalenderanwendung importieren.";
$labels['eventcancelsubject'] = '"$title" wurde abgesagt';
$labels['eventcancelmailbody'] = "*\$title*\n\nWann: \$date\n\nTeilnehmer: \$attendees\n\nDer Termin wurde von \$organizer abgesagt.\n\nIm Anhang finden Sie eine iCalendar-Datei mit den Termindaten.";
$labels['itipobjectnotfound'] = 'Der Termin auf den sich diese Nachricht bezieht, wurde in Deinem Kalnder nicht gefunden.';
$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 Deine 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['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';
$labels['itipcommenttitle'] = 'Dieser Kommentar wird an die Einladungs-/Benachrichtigungsnachricht angehängt, die an die Teilnehmer verschickt wird';
$labels['notanattendee'] = 'Sie sind nicht in der Liste der Teilnehmer aufgeführt';
$labels['eventcancelled'] = 'Der Termin wurde vom Organisator abgesagt';
$labels['saveincalendar'] = 'speichern in';
$labels['updatemycopy'] = 'In meinen Kalender updaten';
$labels['savetocalendar'] = 'In Kalender übernehmen';
$labels['openpreview'] = 'Kalender überprüfen';
$labels['noearlierevents'] = 'Keine früheren Ereignisse';
$labels['nolaterevents'] = 'Keine späteren Ereignisse';
$labels['resource'] = 'Ressource';
$labels['addresource'] = 'Ressource buchen';
$labels['findresources'] = 'Ressourcen finden';
$labels['resourcedetails'] = 'Details';
$labels['resourceavailability'] = 'Verfügbarkeit';
$labels['resourceowner'] = 'Eigentümer';
$labels['resourceadded'] = 'Diese Ressource wurde Deinem Ereignis hinzugefügt';
$labels['tabsummary'] = 'Übersicht';
$labels['tabrecurrence'] = 'Wiederholung';
$labels['tabattendees'] = 'Teilnehmer';
$labels['tabresources'] = 'Ressourcen';
$labels['tabattachments'] = 'Anhänge';
$labels['tabsharing'] = 'Freigabe';
$labels['deleteobjectconfirm'] = 'Möchten Sie diesen Termin wirklich löschen?';
$labels['deleteventconfirm'] = 'Möchten Sie diesen Termin wirklich löschen?';
$labels['deletecalendarconfirm'] = 'Möchten Sie diesen Kalender mit allen Terminen wirklich löschen?';
$labels['deletecalendarconfirmrecursive'] = 'Soll dieser Kalender wirklich mit allen Terminen und Unterkalendern gelöscht werden?';
$labels['savingdata'] = 'Speichere Daten...';
$labels['errorsaving'] = 'Fehler beim Speichern.';
$labels['operationfailed'] = 'Die Aktion ist fehlgeschlagen.';
$labels['invalideventdates'] = 'Ungültige Daten eingegeben! Bitte überprüfen Sie die Eingaben.';
$labels['invalidcalendarproperties'] = 'Ungültige Kalenderinformationen! Bitte geben Sie einen Namen ein.';
$labels['searchnoresults'] = 'Keine Termine in den gewählten Kalendern gefunden.';
$labels['successremoval'] = 'Der Termin wurde erfolgreich gelöscht.';
$labels['successrestore'] = 'Der Termin wurde erfolgreich wieder hergestellt.';
$labels['errornotifying'] = 'Benachrichtigung an die Teilnehmer konnten nicht gesendet werden';
$labels['errorimportingevent'] = 'Fehler beim Importieren';
$labels['importwarningexists'] = 'Eine Kopie dieses Termins exisitert bereits in Deinem Kalender.';
$labels['newerversionexists'] = 'Eine neuere Version dieses Termins exisitert bereits! Import abgebrochen.';
$labels['nowritecalendarfound'] = 'Kein Kalender zum Speichern gefunden';
$labels['importedsuccessfully'] = 'Der Termin wurde erfolgreich in \'$calendar\' gespeichert';
$labels['updatedsuccessfully'] = 'Der Termin wurde erfolgreich in \'$calendar\' geändert';
$labels['attendeupdateesuccess'] = 'Teilnehmerstatus erfolgreich aktualisiert';
$labels['itipsendsuccess'] = 'Einladung an Teilnehmer versendet.';
$labels['itipresponseerror'] = 'Die Antwort auf diese Einladung konnte nicht versendet werden';
$labels['itipinvalidrequest'] = 'Diese Einladung ist nicht mehr gültig.';
$labels['sentresponseto'] = 'Antwort auf diese Einladung erfolgreich an $mailto gesendet';
$labels['localchangeswarning'] = 'Die auszuführenden Änderungen werden sich nur auf den persönlichen Kalender auswirken und nicht an den Organisator des Termins weitergeleitet.';
$labels['importsuccess'] = 'Es wurden $nr Termine erfolgreich importiert';
$labels['importnone'] = 'Keine Termine zum Importieren gefunden';
$labels['importerror'] = 'Fehler beim Importieren';
$labels['aclnorights'] = 'Der Zugriff auf diesen Kalender erfordert Administrator-Rechte.';
$labels['changeeventconfirm'] = 'Termin ändern';
$labels['removeeventconfirm'] = 'Ereignis löschen';
$labels['changerecurringeventwarning'] = 'Dies ist eine Terminreihe. Möchten Sie nur den aktuellen, diesen und alle zukünftigen oder alle Termine bearbeiten oder die Änderungen als neuen Termin speichern?';
$labels['removerecurringeventwarning'] = 'Dies ist ein wiederkehrender Termin. Wollen Sie nur diesen Termin bearbeiten oder alle zukünftigen Vorkommen? Alternativ können auch alle Vorkommen bearbeitet werden.';
$labels['removerecurringallonly'] = 'Dieses ist ein wiederkehrender Termin. Als ein Teilnehmer können Sie nur den gesamten Termin inklusive aller Wiederholungen löschen.';
$labels['currentevent'] = 'Aktuellen';
$labels['futurevents'] = 'Zukünftige';
$labels['allevents'] = 'Alle';
$labels['saveasnew'] = 'Als neu speichern';
$labels['birthdays'] = 'Geburtstage';
$labels['birthdayscalendar'] = 'Geburtstags-Kalender';
$labels['displaybirthdayscalendar'] = 'Geburtstags-Kalender anzeigen';
$labels['birthdayscalendarsources'] = 'Für diese Adressbücher';
$labels['birthdayeventtitle'] = '$names Geburtstag';
$labels['birthdayage'] = 'Alter $age';
-$labels['eventchangelog'] = 'Änderungshistorie';
-$labels['eventdiff'] = 'Änderungen aus $rev1 nach $rev2';
+$labels['objectchangelog'] = 'Änderungshistorie';
+$labels['objectdiff'] = 'Änderungen aus $rev1 nach $rev2';
$labels['revision'] = 'Version';
$labels['user'] = 'Benutzer';
$labels['operation'] = 'Aktion';
$labels['actionappend'] = 'Gespeichert';
$labels['actionmove'] = 'Verschoben';
$labels['actiondelete'] = 'Gelöscht';
$labels['compare'] = 'Vergleichen';
$labels['showrevision'] = 'Diese Version anzeigen';
$labels['restore'] = 'Diese Version wiederherstellen';
-$labels['eventnotfound'] = 'Termindaten sind leider nicht vergübar';
+$labels['objectnotfound'] = 'Termindaten sind leider nicht vergübar';
$labels['objectchangelognotavailable'] = 'Änderungshistorie ist nicht verfügbar für diesen Termin';
-$labels['eventdiffnotavailable'] = 'Vergleich für die gewählten Versionen nicht möglich';
+$labels['objectdiffnotavailable'] = 'Vergleich für die gewählten Versionen nicht möglich';
$labels['revisionrestoreconfirm'] = 'Wollen Sie wirklich die Version $rev dieses Termins wiederherstellen? Diese Aktion wird die aktuelle Kopie mit der älteren Version ersetzen.';
-$labels['eventrestoresuccess'] = 'Revision $rev erfolgreich wiederhergestellt';
-$labels['eventrestoreerror'] = 'Fehler beim Wiederherstellen der alten Revision';
+$labels['objectrestoresuccess'] = 'Revision $rev erfolgreich wiederhergestellt';
+$labels['objectrestoreerror'] = 'Fehler beim Wiederherstellen der alten Revision';
$labels['arialabelminical'] = 'Kalender Datumswahl';
$labels['arialabelcalendarview'] = 'Kalender Ansicht';
$labels['arialabelsearchform'] = 'Suchformular für Termine';
$labels['arialabelquicksearchbox'] = 'Sucheingabe für Termine';
$labels['arialabelcalsearchform'] = 'Suchformular für Kalender';
$labels['calendaractions'] = 'Kalenderaktionen';
$labels['arialabeleventattendees'] = 'Teilehmerliste';
$labels['arialabeleventresources'] = 'Liste der Terminressourcen';
$labels['arialabelresourcesearchform'] = 'Suchformular für Ressourcen';
$labels['arialabelresourceselection'] = 'Verfügbare Ressourcen';
?>
diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc
index 3a15b6f3..d967fc72 100644
--- a/plugins/calendar/localization/en_US.inc
+++ b/plugins/calendar/localization/en_US.inc
@@ -1,310 +1,310 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels = array();
// preferences
$labels['default_view'] = 'Default view';
$labels['time_format'] = 'Time format';
$labels['timeslots'] = 'Time slots per hour';
$labels['first_day'] = 'First weekday';
$labels['first_hour'] = 'First hour to show';
$labels['workinghours'] = 'Working hours';
$labels['add_category'] = 'Add category';
$labels['remove_category'] = 'Remove category';
$labels['defaultcalendar'] = 'Create new events in';
$labels['eventcoloring'] = 'Event coloring';
$labels['coloringmode0'] = 'According to calendar';
$labels['coloringmode1'] = 'According to category';
$labels['coloringmode2'] = 'Calendar for outline, category for content';
$labels['coloringmode3'] = 'Category for outline, calendar for content';
$labels['afternothing'] = 'Do nothing';
$labels['aftertrash'] = 'Move to Trash';
$labels['afterdelete'] = 'Delete the message';
$labels['afterflagdeleted'] = 'Flag as deleted';
$labels['aftermoveto'] = 'Move to...';
$labels['itipoptions'] = 'Event Invitations';
$labels['afteraction'] = 'After an invitation or update message is processed';
// calendar
$labels['calendar'] = 'Calendar';
$labels['calendars'] = 'Calendars';
$labels['category'] = 'Category';
$labels['categories'] = 'Categories';
$labels['createcalendar'] = 'Create new calendar';
$labels['editcalendar'] = 'Edit calendar properties';
$labels['name'] = 'Name';
$labels['color'] = 'Color';
$labels['day'] = 'Day';
$labels['week'] = 'Week';
$labels['month'] = 'Month';
$labels['agenda'] = 'Agenda';
$labels['new'] = 'New';
$labels['new_event'] = 'New event';
$labels['edit_event'] = 'Edit event';
$labels['edit'] = 'Edit';
$labels['save'] = 'Save';
$labels['removelist'] = 'Remove from list';
$labels['cancel'] = 'Cancel';
$labels['select'] = 'Select';
$labels['print'] = 'Print';
$labels['printtitle'] = 'Print calendars';
$labels['title'] = 'Summary';
$labels['description'] = 'Description';
$labels['all-day'] = 'all-day';
$labels['export'] = 'Export';
$labels['exporttitle'] = 'Export to iCalendar';
$labels['exportrange'] = 'Events from';
$labels['exportattachments'] = 'With attachments';
$labels['customdate'] = 'Custom date';
$labels['location'] = 'Location';
$labels['url'] = 'URL';
$labels['date'] = 'Date';
$labels['start'] = 'Start';
$labels['starttime'] = 'Start time';
$labels['end'] = 'End';
$labels['endtime'] = 'End time';
$labels['repeat'] = 'Repeat';
$labels['selectdate'] = 'Choose date';
$labels['freebusy'] = 'Show me as';
$labels['free'] = 'Free';
$labels['busy'] = 'Busy';
$labels['outofoffice'] = 'Out of Office';
$labels['tentative'] = 'Tentative';
$labels['mystatus'] = 'My status';
$labels['status'] = 'Status';
$labels['status-confirmed'] = 'Confirmed';
$labels['status-cancelled'] = 'Cancelled';
$labels['priority'] = 'Priority';
$labels['sensitivity'] = 'Privacy';
$labels['public'] = 'public';
$labels['private'] = 'private';
$labels['confidential'] = 'confidential';
$labels['links'] = 'Reference';
$labels['alarms'] = 'Reminder';
$labels['comment'] = 'Comment';
$labels['created'] = 'Created';
$labels['changed'] = 'Last Modified';
$labels['unknown'] = 'Unknown';
$labels['eventoptions'] = 'Options';
$labels['generated'] = 'generated at';
$labels['eventhistory'] = 'History';
$labels['removelink'] = 'Remove email reference';
$labels['printdescriptions'] = 'Print descriptions';
$labels['parentcalendar'] = 'Insert inside';
$labels['searchearlierdates'] = '« Search for earlier events';
$labels['searchlaterdates'] = 'Search for later events »';
$labels['andnmore'] = '$nr more...';
$labels['togglerole'] = 'Click to toggle role';
$labels['createfrommail'] = 'Save as event';
$labels['importevents'] = 'Import events';
$labels['importrange'] = 'Events from';
$labels['onemonthback'] = '1 month back';
$labels['nmonthsback'] = '$nr months back';
$labels['showurl'] = 'Show calendar URL';
$labels['showurldescription'] = 'Use the following address to access (read only) your calendar from other applications. You can copy and paste this into any calendar software that supports the iCal format.';
$labels['caldavurldescription'] = 'Copy this address to a <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> client application (e.g. Evolution or Mozilla Thunderbird) to fully synchronize this specific calendar with your computer or mobile device.';
$labels['findcalendars'] = 'Find calendars...';
$labels['searchterms'] = 'Search terms';
$labels['calsearchresults'] = 'Available Calendars';
$labels['calendarsubscribe'] = 'List permanently';
$labels['nocalendarsfound'] = 'No calendars found';
$labels['nrcalendarsfound'] = '$nr calendars found';
$labels['quickview'] = 'View only this calendar';
$labels['invitationspending'] = 'Pending invitations';
$labels['invitationsdeclined'] = 'Declined invitations';
$labels['changepartstat'] = 'Change participant status';
$labels['rsvpcomment'] = 'Invitation text';
// agenda view
$labels['listrange'] = 'Range to display:';
$labels['listsections'] = 'Divide into:';
$labels['smartsections'] = 'Smart sections';
$labels['until'] = 'until';
$labels['today'] = 'Today';
$labels['tomorrow'] = 'Tomorrow';
$labels['thisweek'] = 'This week';
$labels['nextweek'] = 'Next week';
$labels['prevweek'] = 'Previous week';
$labels['thismonth'] = 'This month';
$labels['nextmonth'] = 'Next month';
$labels['weekofyear'] = 'Week';
$labels['pastevents'] = 'Past';
$labels['futureevents'] = 'Future';
// alarm/reminder settings
$labels['showalarms'] = 'Show reminders';
$labels['defaultalarmtype'] = 'Default reminder setting';
$labels['defaultalarmoffset'] = 'Default reminder time';
// attendees
$labels['attendee'] = 'Participant';
$labels['role'] = 'Role';
$labels['availability'] = 'Avail.';
$labels['confirmstate'] = 'Status';
$labels['addattendee'] = 'Add participant';
$labels['roleorganizer'] = 'Organizer';
$labels['rolerequired'] = 'Required';
$labels['roleoptional'] = 'Optional';
$labels['rolechair'] = 'Chair';
$labels['rolenonparticipant'] = 'Absent';
$labels['cutypeindividual'] = 'Individual';
$labels['cutypegroup'] = 'Group';
$labels['cutyperesource'] = 'Resource';
$labels['cutyperoom'] = 'Room';
$labels['availfree'] = 'Free';
$labels['availbusy'] = 'Busy';
$labels['availunknown'] = 'Unknown';
$labels['availtentative'] = 'Tentative';
$labels['availoutofoffice'] = 'Out of Office';
$labels['delegatedto'] = 'Delegated to: ';
$labels['delegatedfrom'] = 'Delegated from: ';
$labels['scheduletime'] = 'Find availability';
$labels['sendinvitations'] = 'Send invitations';
$labels['sendnotifications'] = 'Notify participants about modifications';
$labels['sendcancellation'] = 'Notify participants about event cancellation';
$labels['onlyworkinghours'] = 'Find availability within my working hours';
$labels['reqallattendees'] = 'Required/all participants';
$labels['prevslot'] = 'Previous Slot';
$labels['nextslot'] = 'Next Slot';
$labels['suggestedslot'] = 'Suggested Slot';
$labels['noslotfound'] = 'Unable to find a free time slot';
$labels['invitationsubject'] = 'You\'ve been invited to "$title"';
$labels['invitationmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nPlease find attached an iCalendar file with all the event details which you can import to your calendar application.";
$labels['invitationattendlinks'] = "In case your email client doesn't support iTip requests you can use the following link to either accept or decline this invitation:\n\$url";
$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['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)
$labels['itipobjectnotfound'] = 'The event referred by this message was not found in your calendar.';
$labels['itipmailbodyaccepted'] = "\$sender has accepted the invitation to the following event:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
$labels['itipmailbodytentative'] = "\$sender has tentatively accepted the invitation to the following event:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
$labels['itipmailbodydeclined'] = "\$sender has declined the invitation to the following event:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
$labels['itipmailbodycancel'] = "\$sender has rejected your participation in the following event:\n\n*\$title*\n\nWhen: \$date";
$labels['itipmailbodydelegated'] = "\$sender has delegated the participation in the following event:\n\n*\$title*\n\nWhen: \$date";
$labels['itipmailbodydelegatedto'] = "\$sender has delegated the participation in the following event to you:\n\n*\$title*\n\nWhen: \$date";
$labels['itipdeclineevent'] = 'Do you want to decline your invitation to this event?';
$labels['declinedeleteconfirm'] = 'Do you also want to delete this declined event from your calendar?';
$labels['itipcomment'] = 'Invitation/notification comment';
$labels['itipcommenttitle'] = 'This comment will be attached to the invitation/notification message sent to participants';
$labels['notanattendee'] = 'You\'re not listed as an attendee of this event';
$labels['eventcancelled'] = 'The event has been cancelled';
$labels['saveincalendar'] = 'save in';
$labels['updatemycopy'] = 'Update in my calendar';
$labels['savetocalendar'] = 'Save to calendar';
$labels['openpreview'] = 'Check Calendar';
$labels['noearlierevents'] = 'No earlier events';
$labels['nolaterevents'] = 'No later events';
// resources
$labels['resource'] = 'Resource';
$labels['addresource'] = 'Book resource';
$labels['findresources'] = 'Find resources';
$labels['resourcedetails'] = 'Details';
$labels['resourceavailability'] = 'Availability';
$labels['resourceowner'] = 'Owner';
$labels['resourceadded'] = 'The resource was added to your event';
// event dialog tabs
$labels['tabsummary'] = 'Summary';
$labels['tabrecurrence'] = 'Recurrence';
$labels['tabattendees'] = 'Participants';
$labels['tabresources'] = 'Resources';
$labels['tabattachments'] = 'Attachments';
$labels['tabsharing'] = 'Sharing';
// messages
$labels['deleteobjectconfirm'] = 'Do you really want to delete this event?';
$labels['deleteventconfirm'] = 'Do you really want to delete this event?';
$labels['deletecalendarconfirm'] = 'Do you really want to delete this calendar with all its events?';
$labels['deletecalendarconfirmrecursive'] = 'Do you really want to delete this calendar with all its events and sub-calendars?';
$labels['savingdata'] = 'Saving data...';
$labels['errorsaving'] = 'Failed to save changes.';
$labels['operationfailed'] = 'The requested operation failed.';
$labels['invalideventdates'] = 'Invalid dates entered! Please check your input.';
$labels['invalidcalendarproperties'] = 'Invalid calendar properties! Please set a valid name.';
$labels['searchnoresults'] = 'No events found in the selected calendars.';
$labels['successremoval'] = 'The event has been deleted successfully.';
$labels['successrestore'] = 'The event has been restored successfully.';
$labels['errornotifying'] = 'Failed to send notifications to event participants';
$labels['errorimportingevent'] = 'Failed to import the event';
$labels['importwarningexists'] = 'A copy of this event already exists in your calendar.';
$labels['newerversionexists'] = 'A newer version of this event already exists! Aborted.';
$labels['nowritecalendarfound'] = 'No calendar found to save the event';
$labels['importedsuccessfully'] = 'The event was successfully added to \'$calendar\'';
$labels['updatedsuccessfully'] = 'The event was successfully updated in \'$calendar\'';
$labels['attendeupdateesuccess'] = 'Successfully updated the participant\'s status';
$labels['itipsendsuccess'] = 'Invitation sent to participants.';
$labels['itipresponseerror'] = 'Failed to send the response to this event invitation';
$labels['itipinvalidrequest'] = 'This invitation is no longer valid';
$labels['sentresponseto'] = 'Successfully sent invitation response to $mailto';
$labels['localchangeswarning'] = 'You are about to make changes that will only be reflected on your calendar and not be sent to the organizer of the event.';
$labels['importsuccess'] = 'Successfully imported $nr events';
$labels['importnone'] = 'No events found to be imported';
$labels['importerror'] = 'An error occured while importing';
$labels['aclnorights'] = 'You do not have administrator rights on this calendar.';
$labels['changeeventconfirm'] = 'Change event';
$labels['removeeventconfirm'] = 'Delete event';
$labels['changerecurringeventwarning'] = 'This is a recurring event. Would you like to edit the current event only, this and all future occurences, all occurences or save it as a new event?';
$labels['removerecurringeventwarning'] = 'This is a recurring event. Would you like to delete the current event only, this and all future occurences or all occurences of this event?';
$labels['removerecurringallonly'] = 'This is a recurring event. As a participant, you can only delete the entire event with all occurences.';
$labels['currentevent'] = 'Current';
$labels['futurevents'] = 'Future';
$labels['allevents'] = 'All';
$labels['saveasnew'] = 'Save as new';
// birthdays calendar
$labels['birthdays'] = 'Birthdays';
$labels['birthdayscalendar'] = 'Birthdays Calendar';
$labels['displaybirthdayscalendar'] = 'Display birthdays calendar';
$labels['birthdayscalendarsources'] = 'From these address books';
$labels['birthdayeventtitle'] = '$name\'s Birthday';
$labels['birthdayage'] = 'Age $age';
// history dialog
-$labels['eventchangelog'] = 'Change History';
-$labels['eventdiff'] = 'Changes from $rev1 to $rev2';
+$labels['objectchangelog'] = 'Change History';
+$labels['objectdiff'] = 'Changes from $rev1 to $rev2';
$labels['revision'] = 'Revision';
$labels['user'] = 'User';
$labels['operation'] = 'Action';
$labels['actionappend'] = 'Saved';
$labels['actionmove'] = 'Moved';
$labels['actiondelete'] = 'Deleted';
$labels['compare'] = 'Compare';
$labels['showrevision'] = 'Show this version';
$labels['restore'] = 'Restore this version';
-$labels['eventnotfound'] = 'Failed to load event data';
+$labels['objectnotfound'] = 'Failed to load event data';
$labels['objectchangelognotavailable'] = 'Change history is not available for this event';
-$labels['eventdiffnotavailable'] = 'No comparison possible for the selected revisions';
+$labels['objectdiffnotavailable'] = 'No comparison possible for the selected revisions';
$labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev of this event? This will replace the current event with the old version.';
-$labels['eventrestoresuccess'] = 'Revision $rev successfully restored';
-$labels['eventrestoreerror'] = 'Failed to restore the old revision';
+$labels['objectrestoresuccess'] = 'Revision $rev successfully restored';
+$labels['objectrestoreerror'] = 'Failed to restore the old revision';
// (hidden) titles and labels for accessibility annotations
$labels['arialabelminical'] = 'Calendar date selection';
$labels['arialabelcalendarview'] = 'Calendar view';
$labels['arialabelsearchform'] = 'Event search form';
$labels['arialabelquicksearchbox'] = 'Event search input';
$labels['arialabelcalsearchform'] = 'Calendars search form';
$labels['calendaractions'] = 'Calendar actions';
$labels['arialabeleventattendees'] = 'Event participants list';
$labels['arialabeleventresources'] = 'Event resources list';
$labels['arialabelresourcesearchform'] = 'Resources search form';
$labels['arialabelresourceselection'] = 'Available resources';
?>
diff --git a/plugins/calendar/localization/es_AR.inc b/plugins/calendar/localization/es_AR.inc
index 1bb9b516..2a66a0f3 100644
--- a/plugins/calendar/localization/es_AR.inc
+++ b/plugins/calendar/localization/es_AR.inc
@@ -1,269 +1,269 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Vista predeterminada';
$labels['time_format'] = 'Formato de hora';
$labels['timeslots'] = 'Espacios por hora';
$labels['first_day'] = 'Primer día de semana';
$labels['first_hour'] = 'Primer hora a mostrar';
$labels['workinghours'] = 'Horario laboral';
$labels['add_category'] = 'Agregar categoría';
$labels['remove_category'] = 'Eliminar categoría';
$labels['defaultcalendar'] = 'Crear nuevos eventos en';
$labels['eventcoloring'] = 'Colores de eventos';
$labels['coloringmode0'] = 'De acuerdo al calendario';
$labels['coloringmode1'] = 'De acuerdo a la categoría';
$labels['coloringmode2'] = 'Calendario para borde, categoría para contenido';
$labels['coloringmode3'] = 'Categoría para borde, calendario para contenido';
$labels['afternothing'] = '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 del evento';
$labels['afteraction'] = 'Luego que una invitación o actualización de mensaje es procesado';
$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'] = 'Eliminar de la lista';
$labels['cancel'] = 'Cancelar';
$labels['select'] = 'Seleccionar';
$labels['print'] = 'Imprimir';
$labels['printtitle'] = 'Imprimir calendarios';
$labels['title'] = 'Sumario';
$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 adjunto';
$labels['customdate'] = 'Fecha personalizada';
$labels['location'] = 'Localización';
$labels['url'] = 'URL';
$labels['date'] = 'Fecha';
$labels['start'] = 'Inicio';
$labels['starttime'] = 'Hora de inicio';
$labels['end'] = 'Fin';
$labels['endtime'] = 'Hora de finalización';
$labels['repeat'] = 'Repetir';
$labels['selectdate'] = 'Elegir fecha';
$labels['freebusy'] = 'Mostrarme como';
$labels['free'] = 'Libre';
$labels['busy'] = 'Ocupado';
$labels['outofoffice'] = 'Fuera de la oficina';
$labels['tentative'] = 'Tentativo';
$labels['mystatus'] = 'Mi estado';
$labels['status'] = 'Estado';
$labels['status-confirmed'] = 'Confirmado';
$labels['status-cancelled'] = 'Cancelado';
$labels['priority'] = 'Prioridad';
$labels['sensitivity'] = 'Privacidad';
$labels['public'] = 'público';
$labels['private'] = 'privado';
$labels['confidential'] = 'confidencial';
$labels['alarms'] = 'Recordatorio';
$labels['comment'] = 'Comentario';
$labels['created'] = 'Creado';
$labels['changed'] = 'Última modificación';
$labels['unknown'] = 'Desconocido';
$labels['eventoptions'] = 'Opciones';
$labels['generated'] = 'generado en';
$labels['eventhistory'] = 'Historial';
$labels['printdescriptions'] = 'Imprimir descripciones';
$labels['parentcalendar'] = 'Insertar dentro';
$labels['searchearlierdates'] = '« Buscar eventos anteriores';
$labels['searchlaterdates'] = 'Buscar eventos posteriores »';
$labels['andnmore'] = '$nr más...';
$labels['togglerole'] = 'Click para cambiar 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'] = 'Use la siguiente direccion para acceder (sólo lectura) a su calendario desde otras aplicaciones. Puede copiar y pegar esto dentro de cualquier software de calendario que soporte el formato iCal.';
$labels['caldavurldescription'] = 'Copie esta direccion a su aplicación cliente <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> (por ejemplo, Evolution o Mozilla Thunderbird) para sincronizar completamente este calendario específico con su ordenador o dispositivo móvil.';
$labels['findcalendars'] = 'Encontrar calendarios...';
$labels['searchterms'] = 'Buscar términos';
$labels['calsearchresults'] = 'Calendarios disponibles';
$labels['calendarsubscribe'] = 'Listar permanentemente';
$labels['nocalendarsfound'] = 'No se encontraron calendarios';
$labels['nrcalendarsfound'] = '$nr calendarios encontrados';
$labels['quickview'] = 'Ver sólo este calendario';
$labels['invitationspending'] = 'Invitaciones pendientes';
$labels['invitationsdeclined'] = 'Invitaciones rechazadas';
$labels['changepartstat'] = 'Cambiar el estado del participante';
$labels['rsvpcomment'] = 'Texto de invitación';
$labels['listrange'] = 'Rango a mostrar:';
$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 anterior';
$labels['thismonth'] = 'Este mes';
$labels['nextmonth'] = 'Próximo mes';
$labels['weekofyear'] = 'Semana';
$labels['pastevents'] = 'Pasado';
$labels['futureevents'] = 'Futuro';
$labels['showalarms'] = 'Mostrar alarmas';
$labels['defaultalarmtype'] = 'Configuración predeterminada de recordatorio';
$labels['defaultalarmoffset'] = 'Tiempo predeterminado de recordatorio';
$labels['attendee'] = 'Participante';
$labels['role'] = 'Rol';
$labels['availability'] = 'Disp.';
$labels['confirmstate'] = 'Estado';
$labels['addattendee'] = 'Agregar participante';
$labels['roleorganizer'] = 'Organizador';
$labels['rolerequired'] = 'Requerido';
$labels['roleoptional'] = 'Opcional';
$labels['rolechair'] = 'Jefe';
$labels['rolenonparticipant'] = 'Ausente';
$labels['cutypeindividual'] = 'Individual';
$labels['cutypegroup'] = 'Grupo';
$labels['cutyperesource'] = 'Recurso';
$labels['cutyperoom'] = 'Habitación';
$labels['availfree'] = 'Libre';
$labels['availbusy'] = 'Ocupado';
$labels['availunknown'] = 'Desconocido';
$labels['availtentative'] = 'Tentativo';
$labels['availoutofoffice'] = 'Fuera de la oficina';
$labels['delegatedto'] = 'Delegado a:';
$labels['delegatedfrom'] = 'Delegado de:';
$labels['scheduletime'] = 'Buscar disponibilidad';
$labels['sendinvitations'] = 'Enviar invitaciones';
$labels['sendnotifications'] = 'Notificar a los participantes sobre las modificaciones';
$labels['sendcancellation'] = 'Notificar a los participantes sobre la cancelación del evento';
$labels['onlyworkinghours'] = 'Buscar disponibilidad dentro de mi horario laboral';
$labels['reqallattendees'] = 'Requerido/todos los participantes';
$labels['prevslot'] = 'Espacio anterior';
$labels['nextslot'] = 'Espacio siguiente';
$labels['suggestedslot'] = 'Espacio sugerido';
$labels['noslotfound'] = 'Imposible encontrar un espacio libre';
$labels['invitationsubject'] = 'Ha sido invitado a "$title"';
$labels['invitationmailbody'] = "*\$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['invitationattendlinks'] = "En caso que su cliente de correo electrónico no soporte peticiones iTip puede usar el siguiente link para aceptar o declinar esta invitación:\n\$url";
$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['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['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';
$labels['itipcommenttitle'] = 'Este comentario será adjuntado al mensaje de invitación/notificación enviado a los participantes';
$labels['notanattendee'] = 'No esta incluído en la lista de invitados a este evento';
$labels['eventcancelled'] = 'El evento ha sido cancelado';
$labels['saveincalendar'] = 'guardar en';
$labels['updatemycopy'] = 'Actualizar mi calendario';
$labels['savetocalendar'] = 'Guardar en el calendario';
$labels['openpreview'] = 'Comprobar Calendario';
$labels['noearlierevents'] = 'No hay eventos anteriores';
$labels['nolaterevents'] = 'No hay eventos posteriores';
$labels['resource'] = 'Recurso';
$labels['addresource'] = 'Agendar recurso';
$labels['findresources'] = 'Encontrar recursos';
$labels['resourcedetails'] = 'Detalles';
$labels['resourceavailability'] = 'Disponibilidad';
$labels['resourceowner'] = 'Propietario';
$labels['resourceadded'] = 'El recurso fue agregado a su evento';
$labels['tabsummary'] = 'Sumario';
$labels['tabrecurrence'] = 'Recurrencia';
$labels['tabattendees'] = 'Participantes';
$labels['tabresources'] = 'Recursos';
$labels['tabattachments'] = 'Adjuntos';
$labels['tabsharing'] = 'Compartir';
$labels['deleteobjectconfirm'] = 'Confirme que desea eliminar este evento';
$labels['deleteventconfirm'] = 'Confirme que desea eliminar este evento';
$labels['deletecalendarconfirm'] = 'Confirme que desea eliminar este calendario con todos sus eventos';
$labels['deletecalendarconfirmrecursive'] = 'Confirme que desea eliminar este calendario con todos sus eventos y sub-calendarios';
$labels['savingdata'] = 'Guardando...';
$labels['errorsaving'] = 'Falló guardando los cambios.';
$labels['operationfailed'] = 'La operación falló.';
$labels['invalideventdates'] = 'Ingresó fechas erroneas. Por favor compruebe los datos.';
$labels['invalidcalendarproperties'] = 'Propiedades del calendario erroneas. Por favor ingrese un nombre válido.';
$labels['searchnoresults'] = 'No hay eventos en los calendarios seleccionados.';
$labels['successremoval'] = 'El evento ha sido eliminado exitosamente.';
$labels['successrestore'] = 'El evento ha sido recuperado exitosamente.';
$labels['errornotifying'] = 'Fallo al enviar las notificaciones del evento a los participantes';
$labels['errorimportingevent'] = 'Fallo al importar el evento';
$labels['importwarningexists'] = 'Una copia de este evento ya existe en su calendario.';
$labels['newerversionexists'] = 'Ya existe una versión actualizada de este evento. Cancelado.';
$labels['nowritecalendarfound'] = 'No hay calendarios para guardar el evento.';
$labels['importedsuccessfully'] = 'El evento fue guardado en \'$calendar\' exitosamente';
$labels['updatedsuccessfully'] = 'El evento fue actualizado exitosamente en \'$calendar\'';
$labels['attendeupdateesuccess'] = 'Se actualizaron los estados de los participantes exitosamente';
$labels['itipsendsuccess'] = 'Invitaciones enviadas a los participantes.';
$labels['itipresponseerror'] = 'Fallo enviando la respuesta a la invitación de este evento';
$labels['itipinvalidrequest'] = 'Esta invitación no es válida';
$labels['sentresponseto'] = 'Se envió la respuesta a la invitación $mailto exitosamente';
$labels['localchangeswarning'] = 'Se realizarán cambios que sólo serán reflejadas en su calendario y no serán enviadas al organizador del evento';
$labels['importsuccess'] = 'Importados $nr eventos exitosamente';
$labels['importnone'] = 'No se importaron eventos';
$labels['importerror'] = 'Fallo al importar';
$labels['aclnorights'] = 'No tiene permisos de administrador en este calendario.';
$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['currentevent'] = 'Actual';
$labels['futurevents'] = 'Futuro';
$labels['allevents'] = 'Todos';
$labels['saveasnew'] = 'Guardar como nuevo';
$labels['birthdays'] = 'Cumpleaños';
$labels['birthdayscalendar'] = 'Calendario de cumpleaños';
$labels['displaybirthdayscalendar'] = 'Mostrar calendario de cumpleaños';
$labels['birthdayscalendarsources'] = 'De estas libretas de direcciones';
$labels['birthdayeventtitle'] = 'Cumpleaños de $name';
$labels['birthdayage'] = 'Edad $age';
-$labels['eventchangelog'] = 'Cambiar Historial';
+$labels['objectchangelog'] = 'Cambiar Historial';
$labels['revision'] = 'Revisión';
$labels['user'] = 'Usuario';
$labels['operation'] = 'Acción';
$labels['actionappend'] = 'Guardado';
$labels['actionmove'] = 'Movido';
$labels['actiondelete'] = 'Eliminado';
$labels['compare'] = 'Comparar';
$labels['showrevision'] = 'Mostrar esta versión';
$labels['restore'] = 'Recuperar esta versión';
-$labels['eventnotfound'] = 'Fallo al cargar datos del evento';
+$labels['objectnotfound'] = 'Fallo al cargar datos del evento';
$labels['objectchangelognotavailable'] = 'Cambiar historial no esta disponible para este evento';
-$labels['eventdiffnotavailable'] = 'No es posible comparar las revisiones seleccionadas';
+$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['arialabelminical'] = 'Selección de fecha del calendario';
$labels['arialabelcalendarview'] = 'Vista del calendario';
$labels['arialabelsearchform'] = 'Formulario de búsqueda de evento';
$labels['arialabelquicksearchbox'] = 'Entrada de búsqueda de evento';
$labels['arialabelcalsearchform'] = 'Formulario de búsqueda de calendario';
$labels['calendaractions'] = 'Acciones del calendario';
$labels['arialabeleventattendees'] = 'Lista de participantes del evento';
$labels['arialabeleventresources'] = 'Lista de recursos del evento';
$labels['arialabelresourcesearchform'] = 'Formulario de búsqueda de recursos';
$labels['arialabelresourceselection'] = 'Recursos disponibles';
?>
diff --git a/plugins/calendar/localization/es_ES.inc b/plugins/calendar/localization/es_ES.inc
index 6dc876b4..1b025fb3 100644
--- a/plugins/calendar/localization/es_ES.inc
+++ b/plugins/calendar/localization/es_ES.inc
@@ -1,28 +1,26 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['calendars'] = 'Calendarios';
$labels['name'] = 'Nombre';
$labels['edit'] = 'Editar';
$labels['save'] = 'Guardar';
$labels['cancel'] = 'Cancelar';
-$labels['description'] = 'Descripción';
-$labels['confidential'] = 'confidential';
$labels['comment'] = 'Comentario';
$labels['eventoptions'] = 'Opciones';
$labels['rolerequired'] = 'Requerido';
$labels['roleoptional'] = 'Opcional';
$labels['cutypegroup'] = 'Grupo';
$labels['cutyperesource'] = 'Recurso';
$labels['resource'] = 'Recurso';
$labels['resourcedetails'] = 'Detalles';
$labels['tabresources'] = 'Recursos';
$labels['savingdata'] = 'Guardando datos...';
$labels['user'] = 'Usuario';
$labels['operation'] = 'Acción';
?>
diff --git a/plugins/calendar/localization/et_EE.inc b/plugins/calendar/localization/et_EE.inc
deleted file mode 100644
index 55b92a0a..00000000
--- a/plugins/calendar/localization/et_EE.inc
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-/**
- * Localizations for Kolab Calendar plugin
- *
- * Copyright (C) 2014, Kolab Systems AG
- *
- * For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
- */
-$labels['name'] = 'Nimi';
-$labels['save'] = 'Salvesta';
-$labels['confidential'] = 'confidential';
-$labels['rolerequired'] = 'Kohustuslik';
-$labels['operation'] = 'Toiming';
-?>
diff --git a/plugins/calendar/localization/fi_FI.inc b/plugins/calendar/localization/fi_FI.inc
index 35d1065b..2d67e4ee 100644
--- a/plugins/calendar/localization/fi_FI.inc
+++ b/plugins/calendar/localization/fi_FI.inc
@@ -1,273 +1,274 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Oletusnäkymä';
$labels['time_format'] = 'Aikamuoto';
$labels['timeslots'] = 'Ajankohdat per tunti';
$labels['first_day'] = 'Viikon ensimmäinen päivä';
$labels['first_hour'] = 'Ensimmäinen näytettävä tunti';
$labels['workinghours'] = 'Työaika';
$labels['add_category'] = 'Lisää luokka';
$labels['remove_category'] = 'Poista luokka';
$labels['defaultcalendar'] = 'Luo uudet tapahtumat kohteeseen';
$labels['eventcoloring'] = 'Tapahtuman väritys';
$labels['coloringmode0'] = 'Kalenterin mukaan';
$labels['coloringmode1'] = 'Luokan mukaan';
$labels['afternothing'] = 'Älä tee mitään';
$labels['aftertrash'] = 'Siirrä roskakoriin';
$labels['afterdelete'] = 'Poista viesti';
$labels['afterflagdeleted'] = 'Merkitse poistettavaksi';
$labels['aftermoveto'] = 'Siirrä...';
$labels['itipoptions'] = 'Tapahtuman kutsut';
$labels['afteraction'] = 'Kun kutsu tai päivitysviesti on käsitelty';
$labels['calendar'] = 'Kalenteri';
$labels['calendars'] = 'Kalenterit';
$labels['category'] = 'Luokka';
$labels['categories'] = 'Luokat';
$labels['createcalendar'] = 'Luo uusi kalenteri';
$labels['editcalendar'] = 'Muokkaa kalenterin ominaisuuksia';
$labels['name'] = 'Nimi';
$labels['color'] = 'Väri';
$labels['day'] = 'Päivä';
$labels['week'] = 'Viikko';
$labels['month'] = 'Kuukausi';
$labels['agenda'] = 'Asialista';
$labels['new'] = 'Uusi';
$labels['new_event'] = 'Uusi tapahtuma';
$labels['edit_event'] = 'Muokkaa tapahtumaa';
$labels['edit'] = 'Muokkaa';
$labels['save'] = 'Tallenna';
$labels['removelist'] = 'Poista listasta';
$labels['cancel'] = 'Peru';
$labels['select'] = 'Valitse';
$labels['print'] = 'Tulosta';
$labels['printtitle'] = 'Tulosta kalenterit';
$labels['title'] = 'Yhteenveto';
$labels['description'] = 'Kuvaus';
$labels['all-day'] = 'koko päivä';
$labels['export'] = 'Vie';
$labels['exporttitle'] = 'Vie iCalendar-muotoon';
$labels['exportrange'] = 'Tapahtumat';
$labels['exportattachments'] = 'Liitteiden kanssa';
$labels['customdate'] = 'Kustomoitu aika';
$labels['location'] = 'Sijainti';
$labels['url'] = 'Osoite';
$labels['date'] = 'Päiväys';
$labels['start'] = 'Alkaa';
$labels['starttime'] = 'Aloitusaika';
$labels['end'] = 'Päättyy';
$labels['endtime'] = 'Päättymisaika';
$labels['repeat'] = 'Toista';
$labels['selectdate'] = 'Valitse päiväys';
$labels['freebusy'] = 'Aseta tilakseni';
$labels['free'] = 'Vapaa';
$labels['busy'] = 'Varattu';
$labels['outofoffice'] = 'Ei toimistolla';
$labels['tentative'] = 'Alustava';
$labels['mystatus'] = 'Tilani';
$labels['status'] = 'Tila';
$labels['status-confirmed'] = 'Vahvistettu';
$labels['status-cancelled'] = 'Peruttu';
$labels['priority'] = 'Tärkeys';
$labels['sensitivity'] = 'Yksityisyys';
$labels['public'] = 'julkinen';
$labels['private'] = 'yksityinen';
$labels['confidential'] = 'luottamuksellinen';
$labels['links'] = 'Viittaus';
$labels['alarms'] = 'Muistutus';
$labels['comment'] = 'Kommentti';
$labels['created'] = 'Luotu';
$labels['changed'] = 'Viimeksi muokattu';
$labels['unknown'] = 'Tuntematon';
$labels['eventoptions'] = 'Valinnat';
$labels['generated'] = 'generoitu';
$labels['eventhistory'] = 'Historia';
$labels['removelink'] = 'Poista sähköpostiviittaus';
$labels['printdescriptions'] = 'Tulosta kuvaukset';
+$labels['parentcalendar'] = 'Aseta sisään';
$labels['searchearlierdates'] = '« Etsi aiempia tapahtumia';
$labels['searchlaterdates'] = 'Etsi myöhempiä tapahtumia »';
$labels['andnmore'] = '$nr lisää...';
$labels['togglerole'] = 'Klikkaa vaihtaaksesi rooli';
$labels['createfrommail'] = 'Tallenna tapahtumana';
$labels['importevents'] = 'Tuo tapahtumat';
$labels['importrange'] = 'Tapahtumat';
$labels['onemonthback'] = '1 kuukauden ajalta';
$labels['nmonthsback'] = '$nr kuukauden ajalta';
$labels['showurl'] = 'Näytä kalenterin osoite';
$labels['showurldescription'] = 'Käytä seuraavia osoitteita avataksesi kalenterisi pelkässä lukumuodossa muissa sovelluksissa. Voit kopioida ja liittää osoitteen mihin tahansa iCal-muotoa tukevaan kalenterisovellukseen.';
$labels['caldavurldescription'] = 'Kopioi tämä osoite <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a-asiakassovellukseen (esim. Evolution tai Mozilla Thunderbird) synkronoidaksesi tämän kalenterin tietokoneesi tai mobiililaitteesi kanssa.';
$labels['findcalendars'] = 'Etsi kalentereita...';
$labels['searchterms'] = 'Hakuehdot';
$labels['calsearchresults'] = 'Saatavilla olevat kalenterit';
$labels['calendarsubscribe'] = 'Luetteloi pysyvästi';
$labels['nocalendarsfound'] = 'Kalentereita ei löytynyt';
$labels['nrcalendarsfound'] = '$nr kalenteria löytynyt';
$labels['quickview'] = 'Näytä vain tämä kalenteri';
$labels['invitationspending'] = 'Odottavat kutsut';
$labels['invitationsdeclined'] = 'Torjutut kutsut';
$labels['changepartstat'] = 'Muuta osallistujan tilaa';
$labels['rsvpcomment'] = 'Kutsuteksti';
$labels['listrange'] = 'Näytettävä aikaväli';
$labels['listsections'] = 'Jaa osiin:';
$labels['smartsections'] = 'Älykkäät osiot';
$labels['until'] = 'kunnes';
$labels['today'] = 'Tänään';
$labels['tomorrow'] = 'Huomenna';
$labels['thisweek'] = 'Tällä viikolla';
$labels['nextweek'] = 'Ensi viikolla';
$labels['prevweek'] = 'Edellinen viikko';
$labels['thismonth'] = 'Tässä kuussa';
$labels['nextmonth'] = 'Ensi kuussa';
$labels['weekofyear'] = 'Viikko';
$labels['pastevents'] = 'Menneet';
$labels['futureevents'] = 'Tulevat';
$labels['showalarms'] = 'Näytä muistutukset';
$labels['defaultalarmtype'] = 'Muistutuksen oletusasetus';
$labels['defaultalarmoffset'] = 'Muistutuksen oletusaika';
$labels['attendee'] = 'Osallistujat';
$labels['role'] = 'Rooli';
$labels['availability'] = 'Saatavilla';
$labels['confirmstate'] = 'Tila';
$labels['addattendee'] = 'Lisää osallistuja';
$labels['roleorganizer'] = 'Järjestäjä';
$labels['rolerequired'] = 'Vaadittu';
$labels['roleoptional'] = 'Valinnainen';
$labels['rolechair'] = 'Kutsuja';
$labels['rolenonparticipant'] = 'Poissaoleva';
$labels['cutypeindividual'] = 'Yksityishenkilö';
$labels['cutypegroup'] = 'Ryhmä';
$labels['cutyperesource'] = 'Resurssi';
$labels['cutyperoom'] = 'Huone';
$labels['availfree'] = 'Vapaa';
$labels['availbusy'] = 'Varattu';
$labels['availunknown'] = 'Tuntematon';
$labels['availtentative'] = 'Alustava';
$labels['availoutofoffice'] = 'Ei toimistolla';
$labels['delegatedto'] = 'Delegoitu henkilölle:';
$labels['delegatedfrom'] = 'Delegoitus henkilöltä:';
$labels['scheduletime'] = 'Etsi saatavuus';
$labels['sendinvitations'] = 'Lähetä kutsut';
$labels['sendnotifications'] = 'Ilmoita osallistujille muutoksista';
$labels['sendcancellation'] = 'Ilmoita osallistujille tapahtuman perumisesta';
$labels['onlyworkinghours'] = 'Etsi saatavuutta työajan sisältä';
$labels['reqallattendees'] = 'Vaadittu/kaikki osallistujat';
$labels['prevslot'] = 'Edellinen ajankohta';
$labels['nextslot'] = 'Seuraava ajankohta';
$labels['suggestedslot'] = 'Ehdotettu ajankohta';
$labels['noslotfound'] = 'Vapaata ajankohtaa ei löytynyt';
$labels['invitationsubject'] = 'Sinut on kutsuttu tapahtumaan "$title"';
$labels['invitationmailbody'] = "*\$title*\n\nMilloin: \$date\n\nKutsutut: \$attendees\n\nOhessa iCalendar -tiedosto mistä löytyvät kaikki tapahtuman yksityistiedot. Voit tuoda tämän tiedoston kalenteriohjelmaasi.";
$labels['invitationattendlinks'] = "Mikäli sähköpostiohjelmasi ei tue iTip pyyntöjä, voit aina käyttää ao. osoitetta kutsun hyväksymiseen / hylkäämiseen:\n\$url";
$labels['eventupdatesubject'] = '"$title" on päivitetty';
$labels['eventupdatesubjectempty'] = 'Sinua koskeva tapahtuma on päivitetty';
$labels['eventupdatemailbody'] = "*\$title*\n\nMilloin: \$date\n\nKutsutut: \$attendees\n\nOhessa iCalendar -tiedosto mistä löytyvät kaikki päivitetyn tapahtuman yksityistiedot. Voit tuoda tämän tiedoston kalenteriohjelmaasi.";
$labels['eventcancelsubject'] = '"$title" on peruttu';
$labels['eventcancelmailbody'] = "*\$title*\n\nMilloin: \$date\n\nKutsutut: \$attendees\n\nTämä tapahtuma on peruttu \$organizer toimesta.\n\nLöydät liitteenä iCalendar -tiedoston tapahtuman päivitetyin tiedoin.";
$labels['itipobjectnotfound'] = 'Viestissä mainittua tapahtumaa ei löydy kalenteristasi.';
$labels['itipmailbodyaccepted'] = "\$sender on hyväksynyt kutsun seuraavaan tapahtumaan:\n\n*\$title*\n\nMilloin: \$date\n\nKutsutut: \$attendees";
$labels['itipmailbodytentative'] = "\$sender on alustavasti hyväksynyt kutsun seuraavaan tapahtumaan:\n\n*\$title*\n\nMilloin: \$date\n\nKutsutut: \$attendees";
$labels['itipmailbodydeclined'] = "\$sender on hylännyt kutsun seuraavaan tapahtumaan:\n\n*\$title*\n\nMilloin: \$date\n\nKutsutut: \$attendees";
$labels['itipmailbodycancel'] = "\$sender on hylännyt osallistumisesi tapahtumaan:\n\n*\$title*\n\nMilloin: \$date";
$labels['itipmailbodydelegated'] = "\$sender on delegoinut osallistumisensa seuraavaan tapahtumaan:\n\n*\$title*\n\nAjankohta: \$date";
$labels['itipmailbodydelegatedto'] = "\$sender on delegoinut osallistumisensa sinulle seuraavaan tapahtumaan:\n\n*\$title*\n\nAjankohta: \$date";
$labels['itipdeclineevent'] = 'Haluatko perua kutsun tähän tapahtumaan?';
$labels['declinedeleteconfirm'] = 'Haluatko poistaa tämän hylätyn tapahtuman kalenteristasi?';
$labels['itipcomment'] = 'Kutsun/herätteen kommentit';
$labels['itipcommenttitle'] = 'Tämä kommentti liitetään osallistujille lähetettävään kutsuun/heräteviestiin';
$labels['notanattendee'] = 'Sinua ei ole määritetty tapahtuman osanottajaksi';
$labels['eventcancelled'] = 'Tapahtuma on peruttu';
$labels['updatemycopy'] = 'Päivitä kalenterini';
$labels['savetocalendar'] = 'Tallenna kalenteriin';
$labels['openpreview'] = 'Tarkista kalenteri';
$labels['noearlierevents'] = 'Ei aiempia tapahtumia';
$labels['nolaterevents'] = 'Ei myöhempiä tapahtumia';
$labels['resource'] = 'Resurssi';
$labels['addresource'] = 'Varaa resurssi';
$labels['findresources'] = 'Etsi resursseja';
$labels['resourcedetails'] = 'Tiedot';
$labels['resourceavailability'] = 'Saatavuus';
$labels['resourceowner'] = 'Omistaja';
$labels['resourceadded'] = 'Resurssi on liitetty tapahtumaasi';
$labels['tabsummary'] = 'Yhteenveto';
$labels['tabrecurrence'] = 'Toistuminen';
$labels['tabattendees'] = 'Osallistujat';
$labels['tabresources'] = 'Resurssit';
$labels['tabattachments'] = 'Liitteet';
$labels['tabsharing'] = 'Jakaminen';
$labels['deleteobjectconfirm'] = 'Haluatko varmasti poistaa tämän tapahtuman?';
$labels['deleteventconfirm'] = 'Haluatko varmasti poistaa tämän tapahtuman?';
$labels['deletecalendarconfirm'] = 'Haluatko varmasti poistaa tämän kalenterin ja kaikki sen tapahtumat?';
$labels['deletecalendarconfirmrecursive'] = 'Haluatko varmasti poistaa tämän kalenterin ja kaikki sen tapahtumat sekä alikalenterit?';
$labels['savingdata'] = 'Tallennetaan tietoja...';
$labels['errorsaving'] = 'Muutosten tallentaminen epäonnistui.';
$labels['operationfailed'] = 'Pyydetty toiminto epäonnistui.';
$labels['invalideventdates'] = 'Annettu virheellisiä päivämääriä! Tarkista syöte.';
$labels['invalidcalendarproperties'] = 'Kalenterin ominaisuudet ovat virheelliset. Aseta kelvollinen nimi.';
$labels['searchnoresults'] = 'Valituista kalentereista ei löytynyt tapahtumia.';
$labels['successremoval'] = 'Tapahtuma on poistettu onnistuneesti.';
$labels['successrestore'] = 'Tapahtuma on palautettu onnistuneesti.';
$labels['errornotifying'] = 'Herätteen lähetys osallistujille epäonnistui';
$labels['errorimportingevent'] = 'Tapahtuman tuonti epäonnistui';
$labels['importwarningexists'] = 'Tämän tapahtuman kopio löytyy jo kalenteristasi';
$labels['newerversionexists'] = 'Uudempi versio tästä tapahtumasta on jo olemassa! Keskeytetty.';
$labels['nowritecalendarfound'] = 'Tapahtuman tallentamiseksi ei löytynyt kalenteria';
$labels['importedsuccessfully'] = 'Tapahtuma lisättiin onnistuneesti kalenteriin \'$calendar\'';
$labels['updatedsuccessfully'] = 'Tapahtuma on onnistuneesti päivitetty kalenterissa \'$calendar\'';
$labels['attendeupdateesuccess'] = 'Osallistujan tila päivitetty onnistuneesti';
$labels['itipsendsuccess'] = 'Kutsu lähetetty osallistujille.';
$labels['itipresponseerror'] = 'Vastauksen lähettäminen tapahtumakutsuun epäonnistui';
$labels['itipinvalidrequest'] = 'Kutsu ei ole enää kelvollinen';
$labels['sentresponseto'] = 'Vastaus kutsuun lähetetty onnistuneesti sähköpostiin $mailto';
$labels['localchangeswarning'] = 'Olet tekemässä muutoksia, jotka vaikuttavat ainoastaan omaan kalenteriisi. Muutoksia ei lähetetä tapahtuman järjestäjälle.';
$labels['importsuccess'] = '$nr tapahtumaa tuotiin onnistuneesti';
$labels['importnone'] = 'Tuotavaksi tarkoitettuja tapahtumia ei löytynyt';
$labels['importerror'] = 'Tuotaessa tapahtui virhe';
$labels['aclnorights'] = 'Sinulla ei ole ylläpitäjän oikeuksia tähän kalenteriin.';
$labels['changeeventconfirm'] = 'Vaihda tapahtuma';
$labels['removeeventconfirm'] = 'Poista tapahtuma';
$labels['changerecurringeventwarning'] = 'Tämä on tuistuva tapahtuma. Haluatko muokata vain tätä ajankohtaa, tätä ja tulevia tapahtuman ajankohtia, kaikkia tapahtuman ajankohtia vai tallentaa kokonaan uutena tapahtumana? ';
$labels['removerecurringeventwarning'] = 'Tämä on toistuva tapahtuma. Haluatko poistaa vain nykyisen tapahtuman, nykyisen tapahtuman ja tulevaisuuden tapahtumat vai kaikki tapahtumaan liittyvät merkinnät?';
$labels['removerecurringallonly'] = 'Tämä on toistuva tapahtuma. Osallistujana voit poistaa vain koko tapahtuman kaikkine toistumiskertoineen.';
$labels['currentevent'] = 'Nykyinen';
$labels['futurevents'] = 'Tulevat';
$labels['allevents'] = 'Kaikki';
$labels['saveasnew'] = 'Tallenna uutena';
$labels['birthdays'] = 'Syntymäpäivät';
$labels['birthdayscalendar'] = 'Syntymäpäivät kalenteri';
$labels['displaybirthdayscalendar'] = 'Näytä syntymäpäivät kalenterissa';
$labels['birthdayscalendarsources'] = 'Näistä osoitekirjoista';
$labels['birthdayeventtitle'] = 'Syntymäpäivä: $name';
$labels['birthdayage'] = 'Ikä $age';
-$labels['eventchangelog'] = 'Muuta historiaa';
-$labels['eventdiff'] = 'Muutokset versiosta $rev1 versioon $rev2';
+$labels['objectchangelog'] = 'Muuta historiaa';
+$labels['objectdiff'] = 'Muutokset versiosta $rev1 versioon $rev2';
$labels['revision'] = 'Versio';
$labels['user'] = 'Käyttäjä';
$labels['operation'] = 'Toiminto';
$labels['actionappend'] = 'Tallennettu';
$labels['actionmove'] = 'Siirretty';
$labels['actiondelete'] = 'Poistettu';
$labels['compare'] = 'Vertaa';
$labels['showrevision'] = 'Näytä tämä versio';
$labels['restore'] = 'Palauta tämä versio';
-$labels['eventnotfound'] = 'Tapahtumadatan lataus epäonnistui';
+$labels['objectnotfound'] = 'Tapahtumadatan lataus epäonnistui';
$labels['objectchangelognotavailable'] = 'Tapahtuman muutoshistoria ei ole saatavilla';
-$labels['eventdiffnotavailable'] = 'Vertailu ei ole saatavilla valittujen versioiden välillä';
+$labels['objectdiffnotavailable'] = 'Vertailu ei ole saatavilla valittujen versioiden välillä';
$labels['revisionrestoreconfirm'] = 'Haluatko varmasti palauttaa tämän tapahtuman version $rev? Nykyinen tapahtuma korvataan vanhalla versiolla.';
-$labels['eventrestoresuccess'] = 'Versio $rev palautettiin onnistuneesti';
-$labels['eventrestoreerror'] = 'Vanhan version palauttaminen epäonnistui';
+$labels['objectrestoresuccess'] = 'Versio $rev palautettiin onnistuneesti';
+$labels['objectrestoreerror'] = 'Vanhan version palauttaminen epäonnistui';
$labels['arialabelminical'] = 'Kalenterin ajankohdan valinta';
$labels['arialabelcalendarview'] = 'Kalenterinäkymä';
$labels['arialabelsearchform'] = 'Tapahtumahaun lomake';
$labels['arialabelquicksearchbox'] = 'Tapatumahaun syöte';
$labels['arialabelcalsearchform'] = 'Kalenterihakujen lomake';
$labels['calendaractions'] = 'Kalenterin toiminnot';
$labels['arialabeleventattendees'] = 'Tapahtuman osallistujalista';
$labels['arialabeleventresources'] = 'Tapahtuman resurssilista';
$labels['arialabelresourcesearchform'] = 'Resurssien hakulomake';
$labels['arialabelresourceselection'] = 'Saatavilla olevat resurssit';
?>
diff --git a/plugins/calendar/localization/fr_FR.inc b/plugins/calendar/localization/fr_FR.inc
index 076a7d6e..1c897219 100644
--- a/plugins/calendar/localization/fr_FR.inc
+++ b/plugins/calendar/localization/fr_FR.inc
@@ -1,271 +1,271 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Vue par défaut';
$labels['time_format'] = 'Format de l\'heure';
$labels['timeslots'] = 'Créneau horaire';
$labels['first_day'] = 'Premier jour de la semaine';
$labels['first_hour'] = 'Première heure à afficher';
$labels['workinghours'] = 'Heures de travail';
$labels['add_category'] = 'Ajouter une catégorie';
$labels['remove_category'] = 'Supprimer une catégorie';
$labels['defaultcalendar'] = 'Ajouter un nouvel évènement';
$labels['eventcoloring'] = 'Couleurs des évènements';
$labels['coloringmode0'] = 'Selon l\'agenda';
$labels['coloringmode1'] = 'Selon la catégorie';
$labels['coloringmode2'] = 'Calendrier en contour, catégorie en contenu';
$labels['coloringmode3'] = 'Catégorie en contour, calendrier en contenu';
$labels['afternothing'] = 'Ne rien faire';
$labels['aftertrash'] = 'Déplacer dans la corbeille';
$labels['afterdelete'] = 'Supprimer ce message';
$labels['afterflagdeleted'] = 'Marquer comme supprimer';
$labels['aftermoveto'] = 'Déplacer vers...';
$labels['itipoptions'] = 'Invitations à l\'évenement';
$labels['afteraction'] = 'Après une invitation ou une modification, le message est traité';
$labels['calendar'] = 'Agenda';
$labels['calendars'] = 'Agendas';
$labels['category'] = 'Catégorie';
$labels['categories'] = 'Catégories';
$labels['createcalendar'] = 'Créer un nouvel agenda';
$labels['editcalendar'] = 'Modifier les propriétés de l\'agenda';
$labels['name'] = 'Nom';
$labels['color'] = 'Couleur';
$labels['day'] = 'Jour';
$labels['week'] = 'Semaine';
$labels['month'] = 'Mois';
$labels['agenda'] = 'Ordre du jour';
$labels['new'] = 'Nouveau';
$labels['new_event'] = 'Nouvel évènement';
$labels['edit_event'] = 'Modifier l\'évènement';
$labels['edit'] = 'Modifier';
$labels['save'] = 'Enregistrer';
$labels['removelist'] = 'supprimer de la liste';
$labels['cancel'] = 'Annuler';
$labels['select'] = 'Sélectionner';
$labels['print'] = 'Imprimer';
$labels['printtitle'] = 'Imprimer les agendas';
$labels['title'] = 'Résumé';
$labels['description'] = 'Description';
$labels['all-day'] = 'Toute la journée';
$labels['export'] = 'Exporter';
$labels['exporttitle'] = 'Exporter vers iCalendar';
$labels['exportrange'] = 'Évènements depuis';
$labels['exportattachments'] = 'With attachments';
$labels['customdate'] = 'Date personnalisée';
$labels['location'] = 'Lieu';
$labels['url'] = 'URL';
$labels['date'] = 'Date';
$labels['start'] = 'Début';
$labels['starttime'] = 'Début';
$labels['end'] = 'Fin';
$labels['endtime'] = 'Fin';
$labels['repeat'] = 'Répéter';
$labels['selectdate'] = 'Sélectionner une date';
$labels['freebusy'] = 'Montrez moi comme';
$labels['free'] = 'Libre';
$labels['busy'] = 'Occupé';
$labels['outofoffice'] = 'Absent';
$labels['tentative'] = 'Provisoire';
$labels['mystatus'] = 'Mon status';
$labels['status'] = 'Statut';
$labels['status-confirmed'] = 'Confirmé';
$labels['status-cancelled'] = 'Annulée';
$labels['priority'] = 'Priorité';
$labels['sensitivity'] = 'Diffusion';
$labels['public'] = 'publique';
$labels['private'] = 'privée';
$labels['confidential'] = 'Confidentiel';
$labels['links'] = 'Référence';
$labels['alarms'] = 'Rappel';
$labels['comment'] = 'Commentaire';
$labels['created'] = 'Créée';
$labels['changed'] = 'Dernière modification';
$labels['unknown'] = 'Inconnu';
$labels['eventoptions'] = 'Options';
$labels['generated'] = 'généré à';
$labels['eventhistory'] = 'Historique';
$labels['removelink'] = 'Enlever référence d\'e-mail';
$labels['printdescriptions'] = 'Imprimer les descriptions';
$labels['parentcalendar'] = 'Ajouter à l\'intérieur';
$labels['searchearlierdates'] = '« Chercher des évènements plus ancien';
$labels['searchlaterdates'] = 'Chercher des évènement plus récent »';
$labels['andnmore'] = '$nr de plus...';
$labels['togglerole'] = 'Cliquez pour changer de rôle';
$labels['createfrommail'] = 'Enregistrer comme un évènement';
$labels['importevents'] = 'Importer des évènements';
$labels['importrange'] = 'Évènements depuis';
$labels['onemonthback'] = '1 mois précédent';
$labels['nmonthsback'] = '$nr mois précédents';
$labels['showurl'] = 'Afficher l\'URL de l\'agenda';
$labels['showurldescription'] = 'Utilisez l\'adresse suivante pour accéder(lecture seule) à votre agenda depuis une autre application. Vous pouvez copier/coller celle-ci dans n\'importe quel agenda électronique gérant le format iCal.';
$labels['caldavurldescription'] = 'Copiez cette adresse vers une application client (comme Evolution ou Mozilla Thunderbird) compatible <a href="http://fr.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> pour synchroniser ce calendrier avec votre ordinateur ou votre smartphone.';
$labels['findcalendars'] = 'Recherche de calendriers...';
$labels['searchterms'] = 'Critères de recherche';
$labels['calsearchresults'] = 'Calendriers disponibles';
$labels['calendarsubscribe'] = 'Lister définitivement';
$labels['nocalendarsfound'] = 'Aucun calendriers trouvés';
$labels['nrcalendarsfound'] = '$nr calendriers trouvés';
$labels['quickview'] = 'Voir uniquement ce calendrier';
$labels['invitationspending'] = 'Invitations en attente';
$labels['invitationsdeclined'] = 'Invitations refusées';
$labels['changepartstat'] = 'Changer le statut du participent';
$labels['rsvpcomment'] = 'Texte d\'invitation';
$labels['listrange'] = 'Intervalle à afficher :';
$labels['listsections'] = 'Diviser en :';
$labels['smartsections'] = 'Section intelligente';
$labels['until'] = 'jusqu\'à';
$labels['today'] = 'Aujourd\'hui';
$labels['tomorrow'] = 'Demain';
$labels['thisweek'] = 'Cette semaine';
$labels['nextweek'] = 'Semaine prochaine';
$labels['prevweek'] = 'Semaine précédente';
$labels['thismonth'] = 'Ce mois';
$labels['nextmonth'] = 'Mois prochain';
$labels['weekofyear'] = 'Semaine';
$labels['pastevents'] = 'Passé';
$labels['futureevents'] = 'Futur';
$labels['showalarms'] = 'Afficher les rappels';
$labels['defaultalarmtype'] = 'Paramètre de rappel par défaut';
$labels['defaultalarmoffset'] = 'Durée de rappel par défaut';
$labels['attendee'] = 'Participant';
$labels['role'] = 'Rôle';
$labels['availability'] = 'Dispo.';
$labels['confirmstate'] = 'Statut';
$labels['addattendee'] = 'Ajouter participant';
$labels['roleorganizer'] = 'Organisateur';
$labels['rolerequired'] = 'Requis';
$labels['roleoptional'] = 'Optionel';
$labels['rolechair'] = 'Chair';
$labels['rolenonparticipant'] = 'Absent';
$labels['cutypeindividual'] = 'Individual';
$labels['cutypegroup'] = 'Groupe';
$labels['cutyperesource'] = 'Ressource';
$labels['cutyperoom'] = 'Salle';
$labels['availfree'] = 'Disponible';
$labels['availbusy'] = 'Occupé';
$labels['availunknown'] = 'Inconnu';
$labels['availtentative'] = 'Provisoire';
$labels['availoutofoffice'] = 'Absent';
$labels['delegatedto'] = 'Délégué à :';
$labels['delegatedfrom'] = 'Délégué de :';
$labels['scheduletime'] = 'Trouver les disponibilités';
$labels['sendinvitations'] = 'Envoyer les invitations';
$labels['sendnotifications'] = 'Informer les participants des modifications';
$labels['sendcancellation'] = 'Informer les participants de l\'annulation';
$labels['onlyworkinghours'] = 'Trouver des disponibilités en fonction de mes heures de travail';
$labels['reqallattendees'] = 'Demandé/tous';
$labels['prevslot'] = 'Créneau précédent';
$labels['nextslot'] = 'Créneau suivant';
$labels['suggestedslot'] = 'Emplacement suggéré';
$labels['noslotfound'] = 'Impossible de trouver un créneau disponible';
$labels['invitationsubject'] = 'Vous avez été invité à "$title"';
$labels['invitationmailbody'] = "*\$title*\n\nQuand: \$date\n\nParticipants: \$attendees\n\nVous trouverez ci-joint un fichier iCalendar avec tous les détails de l'évènement que vous pourrez importer dans votre agenda électronique.";
$labels['invitationattendlinks'] = "Dans le cas où votre application de messagerie ne gère pas les demandes \"iTip\". Vous pouvez utiliser ce lien pour accepter ou refuser l'invitation : \n\$url";
$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['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';
$labels['itipcommenttitle'] = 'Ce commentaire sera inséré dans le message d\'invitation ou de notification envoyé aux participants';
$labels['notanattendee'] = 'Vous n\'êtes pas dans la liste des participants à cet évènement';
$labels['eventcancelled'] = 'L\'évènement a été annulé';
$labels['saveincalendar'] = 'Enregistrer sous';
$labels['updatemycopy'] = 'Mise à jour dans mon calendrier';
$labels['savetocalendar'] = 'Sauvegarde dans le calendrier';
$labels['openpreview'] = 'Test calendrier';
$labels['noearlierevents'] = 'Aucun évènements passé';
$labels['nolaterevents'] = 'Aucun évènement futur';
$labels['resource'] = 'Ressource';
$labels['addresource'] = 'Carnet de ressources';
$labels['findresources'] = 'Recherche des ressources';
$labels['resourcedetails'] = 'Détails';
$labels['resourceavailability'] = 'Disponibilité';
$labels['resourceowner'] = 'Propriétaire';
$labels['resourceadded'] = 'Cette ressource a été ajouté à l\'évènement';
$labels['tabsummary'] = 'Résumé';
$labels['tabrecurrence'] = 'Récurrence';
$labels['tabattendees'] = 'Participants';
$labels['tabresources'] = 'Ressources';
$labels['tabattachments'] = 'Pièces jointes';
$labels['tabsharing'] = 'Partage';
$labels['deleteobjectconfirm'] = 'Voulez-vous vraiment supprimer cet évènement?';
$labels['deleteventconfirm'] = 'Voulez-vous vraiment supprimer cet évènement?';
$labels['deletecalendarconfirm'] = 'Voulez-vous vraiment supprimer cet agenda et tous ses évènements?';
$labels['deletecalendarconfirmrecursive'] = 'Voulez-vous vraiment supprimer ce calendrier avec tous ces évènements et ces sous calendriers ?';
$labels['savingdata'] = 'Enregistrer...';
$labels['errorsaving'] = 'Échec lors de l\'enregistrement des changements';
$labels['operationfailed'] = 'L\'opération demandée a échoué';
$labels['invalideventdates'] = 'Dates invalides! Veuillez vérifier votre saisie.';
$labels['invalidcalendarproperties'] = 'Propriétés d\'agenda invalides! Veuillez saisir un nom valide.';
$labels['searchnoresults'] = 'Pas d\'évènement trouvé dans les agendas sélectionnés.';
$labels['successremoval'] = 'L\'évènement a été supprimé.';
$labels['successrestore'] = 'L\'évènement a été restauré.';
$labels['errornotifying'] = 'Échec de l\'envoi de notification aux participants ';
$labels['errorimportingevent'] = 'Échec de l\'import de l\'évènement';
$labels['importwarningexists'] = 'Une copie de cet évènement existe déjà dans votre calendrier.';
$labels['newerversionexists'] = 'Une nouvelle version de cet évènement existe! Abandon.';
$labels['nowritecalendarfound'] = 'Pas d\'agenda trouvé pour enregistrer l\'évènement';
$labels['importedsuccessfully'] = 'L\'évènement a été ajouté à l\'agenda \'$calendar\'';
$labels['updatedsuccessfully'] = 'Cet évènement a été modifié avec succès dans \'$calendar\'';
$labels['attendeupdateesuccess'] = 'Le statut des participants a été modifié';
$labels['itipsendsuccess'] = 'Invitation envoyé aux participants.';
$labels['itipresponseerror'] = 'Échec de l\'envoi d\'une réponse à cette invitation.';
$labels['itipinvalidrequest'] = 'C\'est invitation n\'est plus valide.';
$labels['sentresponseto'] = 'La réponse à l\'invitation a été envoyé à $mailto';
$labels['localchangeswarning'] = 'Vous êtes sur le point d\'effectuer des modifications qui seront effectifs sur votre calendrier mais qui ne seront pas envoyés à l\'organisateur de l’évènement.';
$labels['importsuccess'] = '$nr évènements importés.';
$labels['importnone'] = 'Pas d\'évènements à importer';
$labels['importerror'] = 'Une erreur est arrivée lors de l\'import';
$labels['aclnorights'] = 'Vous n\'avez pas les droits d\'administration sur cet agenda.';
$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['currentevent'] = 'Cette occurrence';
$labels['futurevents'] = 'Cette occurrence et toutes les suivantes';
$labels['allevents'] = 'Toutes les occurrences';
$labels['saveasnew'] = 'Enregistrer comme un nouvel évènement';
$labels['birthdays'] = 'Anniversaires';
$labels['birthdayscalendar'] = 'Calendrier des anniversaires';
$labels['displaybirthdayscalendar'] = 'Afficher le calendrier des anniversaires';
$labels['birthdayscalendarsources'] = 'Depuis ces carnets d\'adresses';
$labels['birthdayeventtitle'] = 'Anniversaire de $name';
$labels['birthdayage'] = 'Age $age';
-$labels['eventchangelog'] = 'Historique des modifications';
+$labels['objectchangelog'] = 'Historique des modifications';
$labels['revision'] = 'Version';
$labels['user'] = 'Utilisateur';
$labels['operation'] = 'Action';
$labels['actionappend'] = 'Sauvegardé';
$labels['actionmove'] = 'Déplacé';
$labels['actiondelete'] = 'Supprimé';
$labels['compare'] = 'Comparer';
$labels['showrevision'] = 'Afficher cette version';
$labels['restore'] = 'Restaurer cette version';
-$labels['eventnotfound'] = 'Impossible de charger les données de l’évènement';
+$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['eventdiffnotavailable'] = 'La comparaison des versions sélectionnées est impossible';
+$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['arialabelminical'] = 'Sélection de la date du calendrier';
$labels['arialabelcalendarview'] = 'Vue du calendrier';
$labels['arialabelsearchform'] = 'Recherche d\'évènements depuis';
$labels['arialabelquicksearchbox'] = 'Saisie de le recherche d\'évènements';
$labels['arialabelcalsearchform'] = 'Recherche de calendriers';
$labels['calendaractions'] = 'Actions calendrier';
$labels['arialabeleventattendees'] = 'Liste des participants à l\'évènement';
$labels['arialabeleventresources'] = 'Liste des ressources de l\'évènement';
$labels['arialabelresourcesearchform'] = 'Recherche des ressources';
$labels['arialabelresourceselection'] = 'Ressources disponibles';
?>
diff --git a/plugins/calendar/localization/it_IT.inc b/plugins/calendar/localization/it_IT.inc
index 78b6a053..2cc3ce71 100644
--- a/plugins/calendar/localization/it_IT.inc
+++ b/plugins/calendar/localization/it_IT.inc
@@ -1,273 +1,273 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Visualizzazione predefinita';
$labels['time_format'] = 'Formato ora';
$labels['timeslots'] = 'Timeslots per ora';
$labels['first_day'] = 'Inizio settimana';
$labels['first_hour'] = 'Prima ora da mostrare';
$labels['workinghours'] = 'Orario lavorativo';
$labels['add_category'] = 'Aggiungi categoria';
$labels['remove_category'] = 'Rimuovi categoria';
$labels['defaultcalendar'] = 'Crea nuovi eventi in';
$labels['eventcoloring'] = 'Colorazione evento';
$labels['coloringmode0'] = 'Secondo il calendario';
$labels['coloringmode1'] = 'Secondo la categoria';
$labels['coloringmode2'] = 'Calendar for outline, category for content';
$labels['coloringmode3'] = 'Category for outline, calendar for content';
$labels['afternothing'] = 'Nessuna azione';
$labels['aftertrash'] = 'Sposta nel cestino';
$labels['afterdelete'] = 'Cancella il messaggio';
$labels['afterflagdeleted'] = 'Segna come cancellato';
$labels['aftermoveto'] = 'Sposta in...';
$labels['itipoptions'] = 'Inviti all\'evento';
$labels['afteraction'] = 'Dopo un invito o un aggiornamento il messaggio è processato';
$labels['calendar'] = 'Calendario';
$labels['calendars'] = 'Calendari';
$labels['category'] = 'Categoria';
$labels['categories'] = 'Categorie';
$labels['createcalendar'] = 'Crea nuovo calendario';
$labels['editcalendar'] = 'Modifica proprietà calendario';
$labels['name'] = 'Nome';
$labels['color'] = 'Colore';
$labels['day'] = 'Giorno';
$labels['week'] = 'Settimana';
$labels['month'] = 'Mese';
$labels['agenda'] = 'Agenda';
$labels['new'] = 'Nuovo';
$labels['new_event'] = 'Nuovo evento';
$labels['edit_event'] = 'Modifica evento';
$labels['edit'] = 'Modifica';
$labels['save'] = 'Salva';
$labels['removelist'] = 'Rimuovi dalla lista';
$labels['cancel'] = 'Annulla';
$labels['select'] = 'Seleziona';
$labels['print'] = 'Stampa';
$labels['printtitle'] = 'Stampa calendari';
$labels['title'] = 'Oggetto';
$labels['description'] = 'Descrizione';
$labels['all-day'] = 'Tutto il giorno';
$labels['export'] = 'Esporta';
$labels['exporttitle'] = 'Esporta come iCalendar';
$labels['exportrange'] = 'Eventi di';
$labels['exportattachments'] = 'Con allegati';
$labels['customdate'] = 'Data personalizzata';
$labels['location'] = 'Luogo';
$labels['url'] = 'URL';
$labels['date'] = 'Data';
$labels['start'] = 'Inizio';
$labels['starttime'] = 'Ora di inizio';
$labels['end'] = 'Fine';
$labels['endtime'] = 'Ora di fine';
$labels['repeat'] = 'Ricorrenza';
$labels['selectdate'] = 'Scegliere la data';
$labels['freebusy'] = 'Mostrami come';
$labels['free'] = 'Libero';
$labels['busy'] = 'Occupato';
$labels['outofoffice'] = 'Fuori Ufficio';
$labels['tentative'] = 'Provvisorio';
$labels['mystatus'] = 'Il mio stato';
$labels['status'] = 'Stato';
$labels['status-confirmed'] = 'Confermato';
$labels['status-cancelled'] = 'Cancellato';
$labels['priority'] = 'Priorità';
$labels['sensitivity'] = 'Privacy';
$labels['public'] = 'pubblico';
$labels['private'] = 'privato';
$labels['confidential'] = 'confidenziale';
$labels['links'] = 'Riferimento';
$labels['alarms'] = 'Promemoria';
$labels['comment'] = 'Commento';
$labels['created'] = 'Creato';
$labels['changed'] = 'Ultima modifica';
$labels['unknown'] = 'Sconosciuto';
$labels['eventoptions'] = 'Opzioni';
$labels['generated'] = 'generato il';
$labels['eventhistory'] = 'Storico';
$labels['removelink'] = 'Rimuovi riferimento email';
$labels['printdescriptions'] = 'Stampa descrizioni';
$labels['parentcalendar'] = 'Inserisci dentro';
$labels['searchearlierdates'] = '« Cerca eventi precedenti';
$labels['searchlaterdates'] = 'Cerca eventi successivi »';
$labels['andnmore'] = 'Altri $nr...';
$labels['togglerole'] = 'Fare clic per cambiare il ruolo';
$labels['createfrommail'] = 'Salva come evento';
$labels['importevents'] = 'Importa eventi';
$labels['importrange'] = 'Eventi di';
$labels['onemonthback'] = '1 mese prima';
$labels['nmonthsback'] = '$nr mesi prima';
$labels['showurl'] = 'Mostra URL calendario';
$labels['showurldescription'] = 'Usare il seguente indirizzo per accedere (in sola lettura) al calendario da altre applicazioni. È possibile copiarlo e incollarlo in qualsiasi software che supporta il formato iCal.';
$labels['caldavurldescription'] = 'Copiare questo indirizzo in un\'applicazione client <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> (es. Evolution o Mozilla Thunderbird) per sincronizzare completamente questo specifico calendario con il proprio computer o dispositivo mobile.';
$labels['findcalendars'] = 'Trova calendari...';
$labels['searchterms'] = 'Cerca elemento';
$labels['calsearchresults'] = 'Calendari disponibili';
$labels['calendarsubscribe'] = 'Elenca sempre';
$labels['nocalendarsfound'] = 'Nessun calendario trovato';
$labels['nrcalendarsfound'] = '$nr calendari trovati';
$labels['quickview'] = 'Visualizza solo questo calendario';
$labels['invitationspending'] = 'Inviti in sospeso';
$labels['invitationsdeclined'] = 'Inviti scartati';
$labels['changepartstat'] = 'Cambia lo stato del partecipante';
$labels['rsvpcomment'] = 'Testo dell\'invito';
$labels['listrange'] = 'Intervallo da visualizzare:';
$labels['listsections'] = 'Dividi in:';
$labels['smartsections'] = 'Sezioni intelligenti';
$labels['until'] = 'fino a';
$labels['today'] = 'Oggi';
$labels['tomorrow'] = 'Domani';
$labels['thisweek'] = 'Questa settimana';
$labels['nextweek'] = 'Prossima settimana';
$labels['prevweek'] = 'Settimana precedente';
$labels['thismonth'] = 'Questo mese';
$labels['nextmonth'] = 'Prossimo mese';
$labels['weekofyear'] = 'Settimana';
$labels['pastevents'] = 'Passato';
$labels['futureevents'] = 'Futuro';
$labels['showalarms'] = 'Mostra promemoria';
$labels['defaultalarmtype'] = 'Impostazioni predefinite dei promemoria';
$labels['defaultalarmoffset'] = 'Tempo predefinito per i promemoria';
$labels['attendee'] = 'Partecipante';
$labels['role'] = 'Ruolo';
$labels['availability'] = 'Dispon.';
$labels['confirmstate'] = 'Stato';
$labels['addattendee'] = 'Aggiungi partecipante';
$labels['roleorganizer'] = 'Organizzatore';
$labels['rolerequired'] = 'Necessario';
$labels['roleoptional'] = 'Facoltativo';
$labels['rolechair'] = 'Presidente';
$labels['rolenonparticipant'] = 'Assente';
$labels['cutypeindividual'] = 'Individual';
$labels['cutypegroup'] = 'Gruppo';
$labels['cutyperesource'] = 'Risorsa';
$labels['cutyperoom'] = 'Stanza';
$labels['availfree'] = 'Libero';
$labels['availbusy'] = 'Occupato';
$labels['availunknown'] = 'Sconosciuto';
$labels['availtentative'] = 'Provvisorio';
$labels['availoutofoffice'] = 'Fuori sede';
$labels['delegatedto'] = 'Delegato a:';
$labels['delegatedfrom'] = 'Delegato da:';
$labels['scheduletime'] = 'Trova disponibilità';
$labels['sendinvitations'] = 'Manda inviti';
$labels['sendnotifications'] = 'Notifica le modifiche ai partecipanti';
$labels['sendcancellation'] = 'Notifica ai partecipanti la cancellazione dell\'evento';
$labels['onlyworkinghours'] = 'Trova disponibilità durante le ore lavorative';
$labels['reqallattendees'] = 'Necessario/tutti i partecipanti';
$labels['prevslot'] = 'Spazio precedente';
$labels['nextslot'] = 'Spazio successivo';
$labels['suggestedslot'] = 'Spazio suggerito';
$labels['noslotfound'] = 'Impossibile trovare uno spazio di tempo libero';
$labels['invitationsubject'] = 'Sei stato invitato a "$title"';
$labels['invitationmailbody'] = "*\$title*\n\nQuando: \$date\n\nInvitati: \$attendees\n\nIn allegato un file iCalendar con tutti i dettagli dell'evento, che puoi importare nella tua applicazione calendario.";
$labels['invitationattendlinks'] = "Se il tuo client di posta elettronica non supporta le richieste iTip, puoi seguire il seguente collegamento per accettare o rifiutare l'invito:\n\$url";
$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";
$labels['itipmailbodytentative'] = "\$sender ha accettato con riserva l'invito al seguente evento:\n\n*\$title*\n\nQuando: \$date\n\nInvitati: \$attendees";
$labels['itipmailbodydeclined'] = "\$sender ha rifiutato l'invito al seguente evento:\n\n*\$title*\n\nQuando: \$date\n\nInvitati: \$attendees";
$labels['itipmailbodycancel'] = "\$Il mittente ha rifiutato la tua partecipazione nel seguente evento:\n\n*\$title*\n\nQuando: \$date";
$labels['itipmailbodydelegated'] = "\$Il mittente ha delegato la partecipazione nel seguente evento:\n\n*\$title*\n\nQuando: \$date";
$labels['itipmailbodydelegatedto'] = "\$Il mittente ha delegato a te la partecipazione nel seguente evento:\n\n*\$title*\n\nQuando:\$date";
$labels['itipdeclineevent'] = 'Vuoi rifiutare l\'invito a questo evento?';
$labels['declinedeleteconfirm'] = 'Vuoi anche cancellare dal calendario l\'evento rifiutato?';
$labels['itipcomment'] = 'Commento all\'invito/notifica';
$labels['itipcommenttitle'] = 'Questo commento verrà allegato al messaggio di invito/notifica spedito ai partecipanti';
$labels['notanattendee'] = 'Non sei elencato tra i partecipanti a questo evento';
$labels['eventcancelled'] = 'L\'evento è stato annullato';
$labels['saveincalendar'] = 'salva in';
$labels['updatemycopy'] = 'Aggiorna nel mio calendario';
$labels['savetocalendar'] = 'Salva sul calendario';
$labels['openpreview'] = 'Controlla calendario';
$labels['noearlierevents'] = 'Non ci sono eventi precedenti';
$labels['nolaterevents'] = 'Non ci sono eventi successivi';
$labels['resource'] = 'Risorsa';
$labels['addresource'] = 'Prenota risorsa';
$labels['findresources'] = 'Trova risorse';
$labels['resourcedetails'] = 'Dettagli';
$labels['resourceavailability'] = 'Disponibilità';
$labels['resourceowner'] = 'Proprietario';
$labels['resourceadded'] = 'La risorsa è stata aggiunta al tuo evento';
$labels['tabsummary'] = 'Riepilogo';
$labels['tabrecurrence'] = 'Ricorrenza';
$labels['tabattendees'] = 'Partecipanti';
$labels['tabresources'] = 'Risorse';
$labels['tabattachments'] = 'Allegati';
$labels['tabsharing'] = 'Condivisione';
$labels['deleteobjectconfirm'] = 'Cancellare davvero questo evento?';
$labels['deleteventconfirm'] = 'Cancellare davvero questo evento?';
$labels['deletecalendarconfirm'] = 'Cancellare davvero questo calendario con tutti i suoi eventi?';
$labels['deletecalendarconfirmrecursive'] = 'Vuoi veramente eliminare questo calendario con tutti i suoi eventi e i suoi sotto-calendari?';
$labels['savingdata'] = 'Salvataggio dati...';
$labels['errorsaving'] = 'Impossibile salvare le modifiche.';
$labels['operationfailed'] = 'L\'operazione richiesta è fallita.';
$labels['invalideventdates'] = 'Le date inserite non sono valide. Controllare l\'inserimento.';
$labels['invalidcalendarproperties'] = 'Proprietà del calendario non valide. Impostare un nome valido.';
$labels['searchnoresults'] = 'Nessun evento trovato nel calendario selezionato.';
$labels['successremoval'] = 'L\'evento è stato cancellato correttamente.';
$labels['successrestore'] = 'L\'evento è stato ripristinato correttamente.';
$labels['errornotifying'] = 'Spedizione delle notifiche ai partecipanti dell\'evento fallita';
$labels['errorimportingevent'] = 'Importazione evento fallita';
$labels['importwarningexists'] = 'Una copia di questo evento esiste già nel tuo calendario';
$labels['newerversionexists'] = 'Esiste già una versione più recente di questo evento. Abortito.';
$labels['nowritecalendarfound'] = 'Non c\'è nessun calendario dove salvare l\'evento';
$labels['importedsuccessfully'] = 'Evento aggiunto correttamente a \'$calendar\'';
$labels['updatedsuccessfully'] = 'L\'evento è stato aggiornato con successo su \'$calendar\'';
$labels['attendeupdateesuccess'] = 'Stato dei partecipanti aggiornato correttamente';
$labels['itipsendsuccess'] = 'Invito spedito ai partecipanti.';
$labels['itipresponseerror'] = 'Spedizione della risposta all\'invito fallita';
$labels['itipinvalidrequest'] = 'Questo invito non è più valido';
$labels['sentresponseto'] = 'Risposta all\'invito inviata correttamente a $mailto';
$labels['localchangeswarning'] = 'Stai per fare dei cambiamenti che compariranno solo nel tuo calendario e non saranno spediti all\'organizzatore dell\'evento.';
$labels['importsuccess'] = '$nr eventi importati correttamente';
$labels['importnone'] = 'Nessun evento trovato da importare';
$labels['importerror'] = 'Si è verificato un errore durante l\'importazione';
$labels['aclnorights'] = 'Non hai i diritti di amministratore per questo calendario.';
$labels['changeeventconfirm'] = 'Cambia evento';
$labels['removeeventconfirm'] = 'Cancella evento';
$labels['changerecurringeventwarning'] = 'This is a recurring event. Would you like to edit the current event only, this and all future occurences, all occurences or save it as a new event?';
$labels['removerecurringeventwarning'] = 'Questo è un evento ricorrente. Vuoi cancellare solamente l\'evento corrente, quest\'ultimo e tutte le future ricorrenze oppure tutte le ricorrenze di questo evento?';
$labels['currentevent'] = 'Current';
$labels['futurevents'] = 'Futuro';
$labels['allevents'] = 'Tutto';
$labels['saveasnew'] = 'Salva come nuovo';
$labels['birthdays'] = 'Compleanni';
$labels['birthdayscalendar'] = 'Calendario compleanni';
$labels['displaybirthdayscalendar'] = 'Mostra il calendario compleanni';
$labels['birthdayscalendarsources'] = 'Da queste rubriche';
$labels['birthdayeventtitle'] = 'Compleanno di $name';
$labels['birthdayage'] = 'Età: $age anni';
-$labels['eventchangelog'] = 'Storico modifiche';
+$labels['objectchangelog'] = 'Storico modifiche';
$labels['revision'] = 'Revisione';
$labels['user'] = 'Utente';
$labels['operation'] = 'Azione';
$labels['actionappend'] = 'Salvato';
$labels['actionmove'] = 'Spostato';
$labels['actiondelete'] = 'Cancellato';
$labels['compare'] = 'Confronta';
$labels['showrevision'] = 'Mostra questa versione';
$labels['restore'] = 'Rirpistina questa versione';
-$labels['eventnotfound'] = 'Caricamento dati dell\'evento fallito';
+$labels['objectnotfound'] = 'Caricamento dati dell\'evento fallito';
$labels['objectchangelognotavailable'] = 'Lo storico modifiche non è disponibile per questo evento';
-$labels['eventdiffnotavailable'] = 'Nessun confronto possibile tra le revisioni selezionate';
+$labels['objectdiffnotavailable'] = 'Nessun confronto possibile tra le revisioni selezionate';
$labels['revisionrestoreconfirm'] = 'Vuoi veramente ripristinare la revisione $rev di questo evento? L\'evento corrente verrà sostituito dalla vecchia versione.';
$labels['arialabelminical'] = 'Selezione della data del calendario';
$labels['arialabelcalendarview'] = 'Vista calendario';
$labels['arialabelsearchform'] = 'Modulo ricerca evento';
$labels['arialabelquicksearchbox'] = 'Inserimento ricerca evento';
$labels['arialabelcalsearchform'] = 'Modulo ricerca calendari';
$labels['calendaractions'] = 'Azione calendari';
$labels['arialabeleventattendees'] = 'Lista partecipanti all\'evento';
$labels['arialabeleventresources'] = 'Lista risorse dell\'evento';
$labels['arialabelresourcesearchform'] = 'Modulo ricerca risorse';
$labels['arialabelresourceselection'] = 'Risorse disponibili';
?>
diff --git a/plugins/calendar/localization/pl_PL.inc b/plugins/calendar/localization/pl_PL.inc
index 4495e2f4..7e6d5ac3 100644
--- a/plugins/calendar/localization/pl_PL.inc
+++ b/plugins/calendar/localization/pl_PL.inc
@@ -1,272 +1,272 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Domyślny widok';
$labels['time_format'] = 'Format czasu';
$labels['timeslots'] = 'Przedziały czasowe w ciągu godziny';
$labels['first_day'] = 'Pierwszy dzień tygodnia';
$labels['first_hour'] = 'Pierwsza godzina';
$labels['workinghours'] = 'Godziny robocze';
$labels['add_category'] = 'Dodaj kategorię';
$labels['remove_category'] = 'Usuń kategorię';
$labels['defaultcalendar'] = 'Twórz nowe zdarzenia w';
$labels['eventcoloring'] = 'Kolor zdarzenia';
$labels['coloringmode0'] = 'Zgodnie z kalendarzem';
$labels['coloringmode1'] = 'Zgodnie z kategorią';
$labels['coloringmode2'] = 'Kalendarz dla obramowania, kategoria dla środka';
$labels['coloringmode3'] = 'Kategoria dla obramowania, kalendarz dla środka';
$labels['afternothing'] = 'Nie rób nic';
$labels['aftertrash'] = 'Przenieś do Kosza';
$labels['afterdelete'] = 'Usuń wiadomość';
$labels['afterflagdeleted'] = 'Oznacz jako usunięta';
$labels['aftermoveto'] = 'Przenieś do...';
$labels['itipoptions'] = 'Zaproszenia';
$labels['afteraction'] = 'Wiadomość jest przetwarzana po zaproszeniu lub aktualizacji';
$labels['calendar'] = 'Kalendarz';
$labels['calendars'] = 'Kalendarze';
$labels['category'] = 'Kategoria';
$labels['categories'] = 'Kategorie';
$labels['createcalendar'] = 'Utwórz nowy kalendarz';
$labels['editcalendar'] = 'Edytuj właściwości kalendarza';
$labels['name'] = 'Nazwa';
$labels['color'] = 'Kolor';
$labels['day'] = 'Dzień';
$labels['week'] = 'Tydzień';
$labels['month'] = 'Miesiąc';
$labels['agenda'] = 'Agenda';
$labels['new'] = 'Nowy';
$labels['new_event'] = 'Nowe zdarzenie';
$labels['edit_event'] = 'Edytuj zdarzenie';
$labels['edit'] = 'Edytuj';
$labels['save'] = 'Zapisz';
$labels['removelist'] = 'Usuń z listy';
$labels['cancel'] = 'Anuluj';
$labels['select'] = 'Wybierz';
$labels['print'] = 'Drukuj';
$labels['printtitle'] = 'Drukuj kalendarze';
$labels['title'] = 'Podsumowanie';
$labels['description'] = 'Opis';
$labels['all-day'] = 'cały dzień';
$labels['export'] = 'Eksport';
$labels['exporttitle'] = 'Eksport w formacie iCalendar';
$labels['exportrange'] = 'Zdarzenia z';
$labels['exportattachments'] = 'Z załącznikami';
$labels['customdate'] = 'Własna data';
$labels['location'] = 'Położenie';
$labels['url'] = 'Adres URL';
$labels['date'] = 'Data';
$labels['start'] = 'Początek';
$labels['starttime'] = 'Początek';
$labels['end'] = 'Koniec';
$labels['endtime'] = 'Koniec';
$labels['repeat'] = 'Powtórz';
$labels['selectdate'] = 'Wybierz datę';
$labels['freebusy'] = 'Pokaż mnie jako';
$labels['free'] = 'Wolny';
$labels['busy'] = 'Zajęty';
$labels['outofoffice'] = 'Poza biurem';
$labels['tentative'] = 'Niepewny';
$labels['mystatus'] = 'Mój status';
$labels['status'] = 'Status';
$labels['status-confirmed'] = 'Potwierdzony';
$labels['status-cancelled'] = 'Anulowany';
$labels['priority'] = 'Priorytet';
$labels['sensitivity'] = 'Poufność';
$labels['public'] = 'publiczny';
$labels['private'] = 'prywatny';
$labels['confidential'] = 'poufny';
$labels['links'] = 'Reference';
$labels['alarms'] = 'Przypomnienie';
$labels['comment'] = 'Komentarz';
$labels['created'] = 'Utworzono';
$labels['changed'] = 'Ostatnia modyfikacja';
$labels['unknown'] = 'Nieznany';
$labels['eventoptions'] = 'Opcje';
$labels['generated'] = 'wygenerowano';
$labels['eventhistory'] = 'Historia';
$labels['removelink'] = 'Usuń odnośnik e-mail';
$labels['printdescriptions'] = 'Drukuj opisy';
$labels['parentcalendar'] = 'Wstaw wewnątrz';
$labels['searchearlierdates'] = '« Szukaj wcześniejszych zdarzeń';
$labels['searchlaterdates'] = 'Szukaj późniejszych zdarzeń »';
$labels['andnmore'] = '$nr więcej...';
$labels['togglerole'] = 'Kliknuj aby przestawić rolę';
$labels['createfrommail'] = 'Zapisz jako zdarzenie';
$labels['importevents'] = 'Importuj zdarzenia';
$labels['importrange'] = 'Zdarzenia z';
$labels['onemonthback'] = '1 miesiąc wstecz';
$labels['nmonthsback'] = '$nr miesięcy wstecz';
$labels['showurl'] = 'Pokaż adres URL kalendarza';
$labels['showurldescription'] = 'Używaj tego adresu aby dostać się do kalendarza z innych programów (w trybie tylko-do-odczytu). Możesz wkleić go do dowolnej aplikacji obsługującej format iCal.';
$labels['caldavurldescription'] = 'Skopiuj ten adres do aplikacji obsługującej format <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> (np. Evolution lub Mozilla Thunderbird) aby zsynchronizować wybrany kalendarz z twoim komputerem lub urządzeniem przenośnym.';
$labels['findcalendars'] = 'Wyszukaj kalendarze...';
$labels['searchterms'] = 'Szukana fraza';
$labels['calsearchresults'] = 'Dostępne kalendarze';
$labels['calendarsubscribe'] = 'Dodaj do listy na stałe';
$labels['nocalendarsfound'] = 'Nie znaleziono żadych kalendarzy';
$labels['nrcalendarsfound'] = 'znaleziono $nr kalendarzy';
$labels['quickview'] = 'Pokaż tylko ten kalendarz';
$labels['invitationspending'] = 'Oczekujące zaproszenia';
$labels['invitationsdeclined'] = 'Odrzucone zaproszenia';
$labels['changepartstat'] = 'Zmień status uczestnika';
$labels['rsvpcomment'] = 'Treść zaproszenia';
$labels['listrange'] = 'Zakres do pokazania:';
$labels['listsections'] = 'Podziel na:';
$labels['smartsections'] = 'Inteligentne sekcje';
$labels['until'] = 'dopóki';
$labels['today'] = 'Dzisiaj';
$labels['tomorrow'] = 'Jutro';
$labels['thisweek'] = 'Bieżący tydzień';
$labels['nextweek'] = 'Następny tydzień';
$labels['prevweek'] = 'Poprzedni tydzień';
$labels['thismonth'] = 'Bieżący miesiąc';
$labels['nextmonth'] = 'Następny miesiąc';
$labels['weekofyear'] = 'Tydzień';
$labels['pastevents'] = 'Przeszłe';
$labels['futureevents'] = 'Przyszłe';
$labels['showalarms'] = 'Pokaż powiadomienia';
$labels['defaultalarmtype'] = 'Domyślne powiadomienie';
$labels['defaultalarmoffset'] = 'Domyślny czas powiadomienia';
$labels['attendee'] = 'Uczestnik';
$labels['role'] = 'Rola';
$labels['availability'] = 'Dostępny';
$labels['confirmstate'] = 'Status';
$labels['addattendee'] = 'Dodaj uczestnika';
$labels['roleorganizer'] = 'Organizator';
$labels['rolerequired'] = 'Wymagany';
$labels['roleoptional'] = 'Opcjonalny';
$labels['rolechair'] = 'Przewodniczący';
$labels['rolenonparticipant'] = 'Nieobecny';
$labels['cutypeindividual'] = 'Osoba';
$labels['cutypegroup'] = 'Grupa';
$labels['cutyperesource'] = 'Zasób';
$labels['cutyperoom'] = 'Pokój';
$labels['availfree'] = 'Wolny';
$labels['availbusy'] = 'Zajęty';
$labels['availunknown'] = 'Nieznany';
$labels['availtentative'] = 'Niepewny';
$labels['availoutofoffice'] = 'Poza biurem';
$labels['delegatedto'] = 'Oddelegowany do:';
$labels['delegatedfrom'] = 'Oddelegowany z:';
$labels['scheduletime'] = 'Sprawdź dostępność';
$labels['sendinvitations'] = 'Wyślij zaproszenia';
$labels['sendnotifications'] = 'Powiadom uczestników o zmianach';
$labels['sendcancellation'] = 'Powiadom uczestników o anulowaniu zdarzenia';
$labels['onlyworkinghours'] = 'Sprawdź dostępność w moich godzinach pracy';
$labels['reqallattendees'] = 'Wymagany/wszyscy uczestnicy';
$labels['prevslot'] = 'Poprzedni przedział';
$labels['nextslot'] = 'Następny przedział';
$labels['suggestedslot'] = 'Sugerowany przedział';
$labels['noslotfound'] = 'Nie znaleziono wolnego przedziału czasu';
$labels['invitationsubject'] = 'Zostałeś zaproszony do "$title"';
$labels['invitationmailbody'] = "*\$title*\n\nKiedy: \$date\n\nZaproszeni: \$attendees\n\nW załączeniu plik w formacie iCalendar ze szczegółami zdarzenia, który możesz zaimportować do twojej aplikacji kalendarza.";
$labels['invitationattendlinks'] = "W przypadku gdy klient poczty elektronicznej nie obsługuje rządań w formacie iTip, aby zaakceptować lub odrzucić to zaproszenie, można skorzystać z następującego linku:\n\$url ";
$labels['eventupdatesubject'] = '"$title" zostało zaktualizowane';
$labels['eventupdatesubjectempty'] = 'Zdarzenie które cię dotyczy zostało zaktualizowane';
$labels['eventupdatemailbody'] = "*\$title*\n\nKiedy: \$date\n\nZaproszeni: \$attendees\n\nW załączeniu plik w formacie iCalendar zawierający zaktualizowane szczegóły zdarzenia, które możesz zaimportować do swojej aplikacji kalendarza.";
$labels['eventcancelsubject'] = '"$title" zostało anulowane';
$labels['eventcancelmailbody'] = "*\$title*\n\nKiedy: \$date\n\nZaproszeni: \$attendees\n\nZdarzenie zostało anulowane przez \$organizer.\n\nW załączeniu plik w formacie iCalendar ze zaktualizowanymi szczegółami zdarzenia.";
$labels['itipobjectnotfound'] = 'W twoim kalendarzu nie znaleziono zdarzenia związanego z tą wiadomością.';
$labels['itipmailbodyaccepted'] = "\$sender zaakceptował zaproszenie do następującego zdarzenia:\n\n*\$title*\n\nKiedy: \$date\n\nZaproszeni: \$attendees";
$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['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';
$labels['itipcommenttitle'] = 'Komentarz ten będzie dołączony do wiadomości wysłanej do uczestników zdarzenia';
$labels['notanattendee'] = 'Nie jesteś na liście uczestników tego zdarzenia';
$labels['eventcancelled'] = 'Zdarzenie zostało anulowane';
$labels['saveincalendar'] = 'zapisz w';
$labels['updatemycopy'] = 'Uaktualnij w moim kalendarzu';
$labels['savetocalendar'] = 'Zapisz do kalendarza';
$labels['openpreview'] = 'Sprawdź kalendarz';
$labels['noearlierevents'] = 'Brak wcześniejszych zdarzeń';
$labels['nolaterevents'] = '« Brak póżniejszych zdarzeń';
$labels['resource'] = 'Zasób';
$labels['addresource'] = 'Rezerwuj zasób';
$labels['findresources'] = 'Wyszukaj zasoby';
$labels['resourcedetails'] = 'Szczegóły';
$labels['resourceavailability'] = 'Dostępność';
$labels['resourceowner'] = 'Właściciel';
$labels['resourceadded'] = 'Zasób został dodany do twojego zdarzenia';
$labels['tabsummary'] = 'Podsumowanie';
$labels['tabrecurrence'] = 'Powtarzalność';
$labels['tabattendees'] = 'Uczestnicy';
$labels['tabresources'] = 'Zasoby';
$labels['tabattachments'] = 'Załączniki';
$labels['tabsharing'] = 'Udostępnianie';
$labels['deleteobjectconfirm'] = 'Czy na pewno chcesz usunąć to zdarzenie?';
$labels['deleteventconfirm'] = 'Czy na pewno chcesz usunąć to zdarzenie?';
$labels['deletecalendarconfirm'] = 'Czy na pewno chcesz usunąć ten kalendarz z wszystkimi zadaniami?';
$labels['deletecalendarconfirmrecursive'] = 'Czy na pewno chcesz usunąć ten kalendarz ze wszystkimi zdarzeniami i pod-kalendarzami?';
$labels['savingdata'] = 'Zapisuję dane...';
$labels['errorsaving'] = 'Błąd podczas zapisu danych.';
$labels['operationfailed'] = 'Żądana operacja nie powiodła się.';
$labels['invalideventdates'] = 'Błędna data! Proszę sprawdzić wprowadzone dane.';
$labels['invalidcalendarproperties'] = 'Błędna właściwość kalendarza! Proszę podać poprawną nazwę.';
$labels['searchnoresults'] = 'Nie znaleziono zdarzeń w wybranym kalendarzu.';
$labels['successremoval'] = 'Zdarzenie zostało usunięte.';
$labels['successrestore'] = 'Zdarzenie zostało przywrócone.';
$labels['errornotifying'] = 'Nie udało się wysłać powiadomień do uczestników zdarzenia';
$labels['errorimportingevent'] = 'Nie udało się zaimportować zdarzenia';
$labels['importwarningexists'] = 'Kopia tego zdarzenia już istnieje w twoim kalendarzu.';
$labels['newerversionexists'] = 'Istnieje nowsza wersja tego zdarzenia ! Przerwano.';
$labels['nowritecalendarfound'] = 'Nie znaleziono kalendarza aby zapisać zdarzenie.';
$labels['importedsuccessfully'] = 'Zdarzenie dodano do \'$calendar\'';
$labels['updatedsuccessfully'] = 'Zdarzenie zostało pomyślnie zaktualizowane w \'$calendar\'';
$labels['attendeupdateesuccess'] = 'Zaktualizowano status uczestnika.';
$labels['itipsendsuccess'] = 'Wysłano zaproszenia do uczestników.';
$labels['itipresponseerror'] = 'Nie udało się wysłać odpowiedzi na to zaproszenie.';
$labels['itipinvalidrequest'] = 'To zaproszenie nie jest już aktualne.';
$labels['sentresponseto'] = 'Wysłano odpowiedź na zaproszenie do $mailto.';
$labels['localchangeswarning'] = 'Zamierzasz dokonać zmian, które mogą zostać wykonane tylko w twoim kalendarzu i nie zostaną wysłane do organizatora zdarzenia.';
$labels['importsuccess'] = 'Zaimportowano $nr zdarzeń.';
$labels['importnone'] = 'Nie znaleziono zdarzeń do zaimportowania.';
$labels['importerror'] = 'Wystąpił błąd podczas importu.';
$labels['aclnorights'] = 'Nie masz uprawnień administracyjnych dla tego kalendarza.';
$labels['changeeventconfirm'] = 'Zmień zdarzenie';
$labels['removeeventconfirm'] = 'Usuń zdarzenie';
$labels['changerecurringeventwarning'] = 'To jest zdarzenie powtarzalne. Czy chcesz zmienić bieżące zdarzenie, bieżące i przyszłe, wszystkie, a może zapisać je jako nowe zdarzenie?';
$labels['removerecurringeventwarning'] = 'Jest to zdarzenie cykliczne. Czy chcesz usunąć wyłącznie bieżące zdarzenie i jego przyszłe wystąpienia, czy wszystkie wystąpienia tego zdarzenia?';
$labels['removerecurringallonly'] = 'Jest to zdarzenie cykliczne. Jako uczestnik, możesz jedynie usunąć całe zdarzenie ze wszystkimi jego wystąpieniami.';
$labels['currentevent'] = 'Bieżące';
$labels['futurevents'] = 'Przyszłe';
$labels['allevents'] = 'Wszystkie';
$labels['saveasnew'] = 'Zapisz jako nowe';
$labels['birthdays'] = 'Uruodziny';
$labels['birthdayscalendar'] = 'Kalendarz Urodzin';
$labels['displaybirthdayscalendar'] = 'Wyświetl kalendarz urodzin';
$labels['birthdayscalendarsources'] = 'Z tych książek adresowych';
$labels['birthdayeventtitle'] = 'Urodziny $name\'s';
$labels['birthdayage'] = 'Wiek $age';
-$labels['eventchangelog'] = 'Historia zmian';
+$labels['objectchangelog'] = 'Historia zmian';
$labels['revision'] = 'Wersja';
$labels['user'] = 'Użytkownik';
$labels['operation'] = 'Akcja';
$labels['actionappend'] = 'Zapisane';
$labels['actionmove'] = 'Przeniesione';
$labels['actiondelete'] = 'Usunięte';
$labels['compare'] = 'Porównaj';
$labels['showrevision'] = 'Pokaż tą wersję';
$labels['restore'] = 'Przywróć tą wersję';
-$labels['eventnotfound'] = 'Nie udało się wczytać zdarzenia';
+$labels['objectnotfound'] = 'Nie udało się wczytać zdarzenia';
$labels['objectchangelognotavailable'] = 'Historia zmian jest niedostępna dla tego zdarzenia';
-$labels['eventdiffnotavailable'] = 'Nie można porównać wybranych wersji';
+$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['arialabelminical'] = 'Wybór daty kalendarza';
$labels['arialabelcalendarview'] = 'Podgląd kalendarza';
$labels['arialabelsearchform'] = 'Formularz wyszukiwania zdarzeń';
$labels['arialabelquicksearchbox'] = 'Fraza wyszukiwania zdarzeń';
$labels['arialabelcalsearchform'] = 'Formularz wyszukiwania kalendarzy';
$labels['calendaractions'] = 'Akcje kalendarzy';
$labels['arialabeleventattendees'] = 'Lista uczestników zdarzenia';
$labels['arialabeleventresources'] = 'Lista zasobów zdarzenia';
$labels['arialabelresourcesearchform'] = 'Formularz wyszukiwania zasobów';
$labels['arialabelresourceselection'] = 'Dostępne zasoby';
?>
diff --git a/plugins/calendar/localization/pt_PT.inc b/plugins/calendar/localization/pt_PT.inc
new file mode 100644
index 00000000..d6b38aba
--- /dev/null
+++ b/plugins/calendar/localization/pt_PT.inc
@@ -0,0 +1,274 @@
+<?php
+/**
+ * Localizations for Kolab Calendar plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
+ */
+$labels['default_view'] = 'Visualização padrão';
+$labels['time_format'] = 'Formato da hora';
+$labels['timeslots'] = 'Entradas por hora';
+$labels['first_day'] = 'Primeiro dia da semana';
+$labels['first_hour'] = 'Primeira hora a mostrar';
+$labels['workinghours'] = 'Horário de trabalho';
+$labels['add_category'] = 'Adicionar categoria';
+$labels['remove_category'] = 'Remover categoria';
+$labels['defaultcalendar'] = 'Criar novos eventos em';
+$labels['eventcoloring'] = 'Cores dos eventos';
+$labels['coloringmode0'] = 'De acordo com o calendário';
+$labels['coloringmode1'] = 'De acordo com a categoria';
+$labels['coloringmode2'] = 'Calendário para esboço, categoria para conteúdo';
+$labels['coloringmode3'] = 'Categoria para esboço, calendário para conteúdo';
+$labels['afternothing'] = 'Manter';
+$labels['aftertrash'] = 'Enviar para o lixo';
+$labels['afterdelete'] = 'Eliminar a mensagem';
+$labels['afterflagdeleted'] = 'Marcar como eliminada';
+$labels['aftermoveto'] = 'Mover para...';
+$labels['itipoptions'] = 'Convites de eventos';
+$labels['afteraction'] = 'Depois do processamento de um convite ou mensagem de alteração';
+$labels['calendar'] = 'Calendário';
+$labels['calendars'] = 'Calendários';
+$labels['category'] = 'Categoria';
+$labels['categories'] = 'Categorias';
+$labels['createcalendar'] = 'Criar um novo calendário';
+$labels['editcalendar'] = 'Alterar propriedades do calendário';
+$labels['name'] = 'Nome';
+$labels['color'] = 'Cor';
+$labels['day'] = 'Dia';
+$labels['week'] = 'Semana';
+$labels['month'] = 'Mês';
+$labels['agenda'] = 'Agenda';
+$labels['new'] = 'Novo';
+$labels['new_event'] = 'Novo evento';
+$labels['edit_event'] = 'Alterar evento';
+$labels['edit'] = 'Alterar';
+$labels['save'] = 'Guardar';
+$labels['removelist'] = 'Remover da lista';
+$labels['cancel'] = 'Cancelar';
+$labels['select'] = 'Selecionar';
+$labels['print'] = 'Imprimir';
+$labels['printtitle'] = 'Imprimir calendários';
+$labels['title'] = 'Sumário';
+$labels['description'] = 'Descrição';
+$labels['all-day'] = 'dia todo';
+$labels['export'] = 'Exportar';
+$labels['exporttitle'] = 'Exportar para iCalendar';
+$labels['exportrange'] = 'Eventos de';
+$labels['exportattachments'] = 'Incluir anexos';
+$labels['customdate'] = 'Definir data';
+$labels['location'] = 'Local';
+$labels['url'] = 'Endereço web';
+$labels['date'] = 'Data';
+$labels['start'] = 'Início';
+$labels['starttime'] = 'Hora de início';
+$labels['end'] = 'Fim';
+$labels['endtime'] = 'Hora de fim';
+$labels['repeat'] = 'Repetir';
+$labels['selectdate'] = 'Escolher data';
+$labels['freebusy'] = 'Mostrar-me como';
+$labels['free'] = 'Livre';
+$labels['busy'] = 'Ocupado';
+$labels['outofoffice'] = 'Ausente';
+$labels['tentative'] = 'Tentativa';
+$labels['mystatus'] = 'O meu estado';
+$labels['status'] = 'Estado';
+$labels['status-confirmed'] = 'Confirmado';
+$labels['status-cancelled'] = 'Cancelado';
+$labels['priority'] = 'Prioridade';
+$labels['sensitivity'] = 'Privacidade';
+$labels['public'] = 'público';
+$labels['private'] = 'privado';
+$labels['confidential'] = 'confidencial';
+$labels['links'] = 'Referência';
+$labels['alarms'] = 'Lembrete';
+$labels['comment'] = 'Comentário';
+$labels['created'] = 'Criado em';
+$labels['changed'] = 'Alterado em';
+$labels['unknown'] = 'Desconhecido';
+$labels['eventoptions'] = 'Opções';
+$labels['generated'] = 'produzido a';
+$labels['eventhistory'] = 'Histórico';
+$labels['removelink'] = 'Remover referência de email ';
+$labels['printdescriptions'] = 'Descrições de impressão';
+$labels['parentcalendar'] = 'Inserir dentro';
+$labels['searchearlierdates'] = '« Procurar eventos anteriores';
+$labels['searchlaterdates'] = 'Procurar eventos posteriores »';
+$labels['andnmore'] = '$nr mais...';
+$labels['togglerole'] = 'Clique para alternar o papel';
+$labels['createfrommail'] = 'Salvar como evento';
+$labels['importevents'] = 'Importar eventos';
+$labels['importrange'] = 'Eventos de';
+$labels['onemonthback'] = '1 mês atrás';
+$labels['nmonthsback'] = '$nr meses atrás';
+$labels['showurl'] = 'Mostrar URL do calendário';
+$labels['showurldescription'] = 'Use o seguinte endereço para obter acesso (somente leitura) ao seu calendário com outras aplicações. Para isso pode copiar e colar este endereço em qualquer software que suporte o formato iCal.';
+$labels['caldavurldescription'] = 'Para sincronizar este calendário com o seu computador ou dispositivos móveis deverá copiar este endereço <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> para a aplicação cliente. (ex. Evolution ou Mozilla Thunderbird)';
+$labels['findcalendars'] = 'Procurar calendários...';
+$labels['searchterms'] = 'Procurar termos';
+$labels['calsearchresults'] = 'Calendários disponíveis';
+$labels['calendarsubscribe'] = 'Listar sempre';
+$labels['nocalendarsfound'] = 'Não foram encontrados calendários';
+$labels['nrcalendarsfound'] = '$nr calendários encontrados';
+$labels['quickview'] = 'Só mostrar este calendário';
+$labels['invitationspending'] = 'Convites pendentes';
+$labels['invitationsdeclined'] = 'Convites recusados';
+$labels['changepartstat'] = 'Mudar estado de participante';
+$labels['rsvpcomment'] = 'Mensagem de convite';
+$labels['listrange'] = 'Intervalo para exibir:';
+$labels['listsections'] = 'Dividir em:';
+$labels['smartsections'] = 'Seções inteligentes';
+$labels['until'] = 'até';
+$labels['today'] = 'Hoje';
+$labels['tomorrow'] = 'Amanhã';
+$labels['thisweek'] = 'Esta semana';
+$labels['nextweek'] = 'Próxima semana';
+$labels['prevweek'] = 'Semana anterior';
+$labels['thismonth'] = 'Este mês';
+$labels['nextmonth'] = 'Próximo mês';
+$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['attendee'] = 'Participante';
+$labels['role'] = 'Papel';
+$labels['availability'] = 'Disp.';
+$labels['confirmstate'] = 'Estado';
+$labels['addattendee'] = 'Adicionar participante';
+$labels['roleorganizer'] = 'Organizador';
+$labels['rolerequired'] = 'Obrigatório';
+$labels['roleoptional'] = 'Facultativo';
+$labels['rolechair'] = 'Responsável';
+$labels['rolenonparticipant'] = 'Ausente';
+$labels['cutypeindividual'] = 'Individual';
+$labels['cutypegroup'] = 'Grupo';
+$labels['cutyperesource'] = 'Recurso';
+$labels['cutyperoom'] = 'Sala';
+$labels['availfree'] = 'Disponível';
+$labels['availbusy'] = 'Ocupado';
+$labels['availunknown'] = 'Desconhecido';
+$labels['availtentative'] = 'Tentativa';
+$labels['availoutofoffice'] = 'Ausente';
+$labels['delegatedto'] = 'Delegado a:';
+$labels['delegatedfrom'] = 'Delegado de:';
+$labels['scheduletime'] = 'Procurar disponibilidade';
+$labels['sendinvitations'] = 'Enviar convites';
+$labels['sendnotifications'] = 'Avisar os participantes sobre as alterações';
+$labels['sendcancellation'] = 'Avisar os participantes sobre o cancelamento do evento';
+$labels['onlyworkinghours'] = 'Procurar disponibilidade dentro do meu horário de trabalho';
+$labels['reqallattendees'] = 'Necessário/todos os participantes';
+$labels['prevslot'] = 'Espaço anterior';
+$labels['nextslot'] = 'Próximo espaço';
+$labels['suggestedslot'] = 'Espaço sugerido';
+$labels['noslotfound'] = 'Incapaz de encontrar um horário disponível';
+$labels['invitationsubject'] = 'Foi convidado para "$title"';
+$labels['invitationmailbody'] = "*\$title*\n\nQuando: \$date\n\nConvidados: \$attendees\n\nSegue em anexo um arquivo iCalendar com todos os detalhes de um evento, o qual pode importar para o seu calendário.";
+$labels['invitationattendlinks'] = "No caso do seu cliente de e-mail não suportar pedidos do tipo iTIP, pode usar o seguinte link para aceitar ou recusar este convite:\n\$url";
+$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['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";
+$labels['itipmailbodytentative'] = "\$sender aceitou o convite como \"tentativa\" para o seguinte evento:\n\n*\$title*\n\nQuando: \$date\n\nConvidados: \$attendees";
+$labels['itipmailbodydeclined'] = "\$sender recusou o convite para o seguinte evento:\n\n*\$title*\n\nQuando: \$date\n\nConvidados: \$attendees";
+$labels['itipmailbodycancel'] = "\$sender rejeitou a sua participação no seguinte evento:\n\n*\$title*\n\nQuando: \$date";
+$labels['itipmailbodydelegated'] = "\$sender delegou a participação no seguinte evento:\n\n*\$title*\n\nWhen: \$date";
+$labels['itipmailbodydelegatedto'] = "\$sender delegou a sua participação no seguinte evento:\n\n*\$title*\n\nWhen: \$date";
+$labels['itipdeclineevent'] = 'Deseja recusar o convite para este evento?';
+$labels['declinedeleteconfirm'] = 'Também deseja apagar o evento recusado do seu calendário?';
+$labels['itipcomment'] = 'Observações — Convite/notificação';
+$labels['itipcommenttitle'] = 'Estas observações serão enviadas com o convite/notificação aos participantes.';
+$labels['notanattendee'] = 'Não está listado como participante neste evento';
+$labels['eventcancelled'] = 'O evento foi cancelado';
+$labels['saveincalendar'] = 'guardar em';
+$labels['updatemycopy'] = 'Atualizar no meu calendário';
+$labels['savetocalendar'] = 'Guardar no calendário';
+$labels['openpreview'] = 'Verificar calendário';
+$labels['noearlierevents'] = 'Sem eventos anteriores';
+$labels['nolaterevents'] = 'Sem eventos posteriores';
+$labels['resource'] = 'Recurso';
+$labels['addresource'] = 'Livro de recursos';
+$labels['findresources'] = 'Encontrar recursos';
+$labels['resourcedetails'] = 'Detalhes';
+$labels['resourceavailability'] = 'Disponibilidade';
+$labels['resourceowner'] = 'Dono';
+$labels['resourceadded'] = 'O recurso foi adicionado ao seu evento';
+$labels['tabsummary'] = 'Sumário';
+$labels['tabrecurrence'] = 'Repetição';
+$labels['tabattendees'] = 'Participantes';
+$labels['tabresources'] = 'Recursos';
+$labels['tabattachments'] = 'Anexos';
+$labels['tabsharing'] = 'Partilha';
+$labels['deleteobjectconfirm'] = 'Tem a certeza que quer eliminar este evento?';
+$labels['deleteventconfirm'] = 'Tem a certeza que quer eliminar este evento?';
+$labels['deletecalendarconfirm'] = 'Tem a certeza que quer eliminar este calendário e todos os seus eventos?';
+$labels['deletecalendarconfirmrecursive'] = 'Tem a certeza que quer eliminar este calendário com todos os seus eventos e sub-calendários?';
+$labels['savingdata'] = 'A guardar os dados...';
+$labels['errorsaving'] = 'Falha ao guardar as alterações.';
+$labels['operationfailed'] = 'A operação pedida falhou.';
+$labels['invalideventdates'] = 'As datas são inválidas! Por favor, verifique novamente.';
+$labels['invalidcalendarproperties'] = 'Propriedades de calendário inválidas! Por favor defina um nome válido.';
+$labels['searchnoresults'] = 'Nenhum evento encontrado nos calendários selecionados.';
+$labels['successremoval'] = 'O evento foi excluído com sucesso.';
+$labels['successrestore'] = 'O evento foi restaurado com sucesso.';
+$labels['errornotifying'] = 'Falha ao enviar notificações para os participantes do evento.';
+$labels['errorimportingevent'] = 'Falha ao importar evento';
+$labels['importwarningexists'] = 'Uma cópia deste evento já existe em seu calendário.';
+$labels['newerversionexists'] = 'Já existe uma nova versão deste evento! Abortado.';
+$labels['nowritecalendarfound'] = 'Nenhum calendário encontrado para salvar o evento';
+$labels['importedsuccessfully'] = 'O evento foi adicionado com sucesso em \'$calendar\'';
+$labels['updatedsuccessfully'] = 'O evento foi atualizado com sucesso em \'$calendar\'.';
+$labels['attendeupdateesuccess'] = 'O status do participante foi atualizado com sucesso.';
+$labels['itipsendsuccess'] = 'Convite enviado aos participantes.';
+$labels['itipresponseerror'] = 'Falha ao enviar a resposta para este convite de evento';
+$labels['itipinvalidrequest'] = 'Este convite já não é válido';
+$labels['sentresponseto'] = 'Resposta de convite enviada com sucesso para $mailto';
+$labels['localchangeswarning'] = 'As alterações que pretende efetuar só serão válidas no seu calendário e não serão enviadas ao organizador do evento.';
+$labels['importsuccess'] = 'Importado com sucesso $nr eventos';
+$labels['importnone'] = 'Não há eventos a serem importados';
+$labels['importerror'] = 'Ocorreu um erro na importação';
+$labels['aclnorights'] = 'Não tem permissão de administrador neste calendário.';
+$labels['changeeventconfirm'] = 'Alterar evento';
+$labels['removeeventconfirm'] = 'Eliminar evento';
+$labels['changerecurringeventwarning'] = 'Este evento é recorrente. Deseja alterar a ocorrência atual, esta e todas as futuras ocorrências ou guardar como um novo evento?';
+$labels['removerecurringeventwarning'] = 'Este evento é recorrente. Deseja eliminar a ocorrência atual, esta e todas as futuras ocorrências ou todas as ocorrências do evento?';
+$labels['removerecurringallonly'] = 'Este evento é recorrente. Como participante, só pode apagar apagar o evento com todas as ocorrências.';
+$labels['currentevent'] = 'Atual';
+$labels['futurevents'] = 'Futuro';
+$labels['allevents'] = 'Todos';
+$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['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['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['arialabelminical'] = 'Seleção da data do calendário';
+$labels['arialabelcalendarview'] = 'Vista do calendário';
+$labels['arialabelsearchform'] = 'Quadro de pesquisa de eventos';
+$labels['arialabelquicksearchbox'] = 'Pesquisa de eventos';
+$labels['arialabelcalsearchform'] = 'Quadro de pesquisa de calendários';
+$labels['calendaractions'] = 'Ações do calendário';
+$labels['arialabeleventattendees'] = 'Lista de participantes do evento';
+$labels['arialabeleventresources'] = 'Lista de recursos para eventos';
+$labels['arialabelresourcesearchform'] = 'Quadro de pesquisa de recursos';
+$labels['arialabelresourceselection'] = 'Recursos disponíveis';
+?>
diff --git a/plugins/calendar/localization/ru_RU.inc b/plugins/calendar/localization/ru_RU.inc
index a7b09185..b5c3c1d3 100644
--- a/plugins/calendar/localization/ru_RU.inc
+++ b/plugins/calendar/localization/ru_RU.inc
@@ -1,274 +1,277 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$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['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'] = 'Категория';
$labels['categories'] = 'Категории';
$labels['createcalendar'] = 'Создать новый календарь';
$labels['editcalendar'] = 'Редактировать свойства календаря';
$labels['name'] = 'Имя';
$labels['color'] = 'Цвет';
$labels['day'] = 'День';
$labels['week'] = 'Неделя';
$labels['month'] = 'Месяц';
$labels['agenda'] = 'Список';
$labels['new'] = 'Новый';
$labels['new_event'] = 'Новое событие';
$labels['edit_event'] = 'Изменить событие';
$labels['edit'] = 'Редактировать';
$labels['save'] = 'Сохранить';
$labels['removelist'] = 'Удалить из списка';
$labels['cancel'] = 'Отмена';
$labels['select'] = 'Выбрать';
$labels['print'] = 'Распечатать';
$labels['printtitle'] = 'Распечатать календарь';
$labels['title'] = 'Сводка';
$labels['description'] = 'Описание';
$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['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'] = 'События начиная с';
$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> (например, Evolution или Mozilla Thunderbird) для полной синхронизации данного календаря со своим компьютером или мобильным устройством.';
$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'] = 'Умные секции';
$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['rolechair'] = 'Место';
$labels['rolenonparticipant'] = 'Absent';
$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'] = 'Уведомить участников об изменениях';
$labels['sendcancellation'] = 'Уведомить участников об отмене события';
$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Во вложении вы найдёте файл iCalendar со всеми деталями события, который Вы можете импортировать в Вашу программу-ежедневник.";
$labels['invitationattendlinks'] = "В случае, если Ваш почтовый клиент не поддерживает запросы iTip, Вы можете использовать ссылку данную ниже, чтобы принять или отклонить это приглашение:\n\$url";
$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['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'] = 'Участники';
$labels['tabresources'] = 'Ресурсы';
$labels['tabattachments'] = 'Вложения';
$labels['tabsharing'] = 'Совместное использование';
$labels['deleteobjectconfirm'] = 'Вы действительно хотите удалить это событие?';
$labels['deleteventconfirm'] = 'Вы действительно хотите удалить это событие?';
$labels['deletecalendarconfirm'] = 'Вы действительно хотите удалить этот календарь со всеми его событиями?';
$labels['deletecalendarconfirmrecursive'] = 'Вы действительно хотите удалить этот календарь со всеми его событиями и вложенными календарями?';
$labels['savingdata'] = 'Сохранение данных...';
$labels['errorsaving'] = 'Ошибка сохранения изменений.';
$labels['operationfailed'] = 'Не удалось выполнить запрошенную операцию.';
$labels['invalideventdates'] = 'Неверная дата! Пожалуйста проверьте данные.';
$labels['invalidcalendarproperties'] = 'Неверные свойства календаря! Пожалуйста введите допустимые данные.';
$labels['searchnoresults'] = 'Событие не найдено в выбранных календарях.';
$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['eventchangelog'] = 'История изменений';
+$labels['objectchangelog'] = 'История изменений';
+$labels['objectdiff'] = 'Изменения с $rev1 до $rev2';
$labels['revision'] = 'Ревизия';
$labels['user'] = 'Пользователь';
$labels['operation'] = 'Действие';
$labels['actionappend'] = 'Сохранено';
$labels['actionmove'] = 'Перемещено';
$labels['actiondelete'] = 'Удалено';
$labels['compare'] = 'Сравнить';
$labels['showrevision'] = 'Показать эту версию';
$labels['restore'] = 'Восстановить эту версию';
-$labels['eventnotfound'] = 'Не удалось загрузить информацию о мероприятиях';
+$labels['objectnotfound'] = 'Не удалось загрузить информацию о мероприятиях';
$labels['objectchangelognotavailable'] = 'История изменений для этого события недоступна';
-$labels['eventdiffnotavailable'] = 'Невозможно провести сравнение выбранных ревизий ';
+$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'] = 'Доступные ресурсы';
?>
diff --git a/plugins/calendar/localization/sl_SI.inc b/plugins/calendar/localization/sl_SI.inc
index 9ab874b8..0691d42b 100644
--- a/plugins/calendar/localization/sl_SI.inc
+++ b/plugins/calendar/localization/sl_SI.inc
@@ -1,273 +1,273 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Privzeti pogled';
$labels['time_format'] = 'Format časa';
$labels['timeslots'] = 'Časovnih oken na uro';
$labels['first_day'] = 'Prvi dan v tednu';
$labels['first_hour'] = 'Prva ura za prikaz';
$labels['workinghours'] = 'Ure dela';
$labels['add_category'] = 'Dodaj kategorijo';
$labels['remove_category'] = 'Odstrani kategorijo';
$labels['defaultcalendar'] = 'Ustvari nove dogodke v';
$labels['eventcoloring'] = 'Barva dogodka';
$labels['coloringmode0'] = 'Po koledarju';
$labels['coloringmode1'] = 'Po kategoriji';
$labels['coloringmode2'] = 'Koledar za prikaz, kategorija za vsebino';
$labels['coloringmode3'] = 'Kategorija za prikaz, koledar za vsebino';
$labels['afternothing'] = 'Ne naredi ničesar';
$labels['aftertrash'] = 'Premakni v koš';
$labels['afterdelete'] = 'Izbriši sporočilo';
$labels['afterflagdeleted'] = 'Označi kot izbrisano';
$labels['aftermoveto'] = 'Premakni v...';
$labels['itipoptions'] = 'Vabila za dogodek';
$labels['afteraction'] = 'Po obdelavi vabila ali posodobljenega sporočila';
$labels['calendar'] = 'Koledar';
$labels['calendars'] = 'Koledarji';
$labels['category'] = 'Kategorija';
$labels['categories'] = 'Kategorije';
$labels['createcalendar'] = 'Ustvari nov koledar';
$labels['editcalendar'] = 'Uredi nastavitve koledarja';
$labels['name'] = 'Ime';
$labels['color'] = 'Barva';
$labels['day'] = 'Dan';
$labels['week'] = 'Teden';
$labels['month'] = 'Mesec';
$labels['agenda'] = 'Urnik';
$labels['new'] = 'Nov';
$labels['new_event'] = 'Nov dogodek';
$labels['edit_event'] = 'Uredi dogodek';
$labels['edit'] = 'Uredi';
$labels['save'] = 'Shrani';
$labels['removelist'] = 'Odstrani iz seznama';
$labels['cancel'] = 'Prekliči';
$labels['select'] = 'Izberi';
$labels['print'] = 'Natisni';
$labels['printtitle'] = 'Natisni koledarje';
$labels['title'] = 'Pregled';
$labels['description'] = 'Opis';
$labels['all-day'] = 'cel dan';
$labels['export'] = 'Izvozi';
$labels['exporttitle'] = 'Izvozi v iCalendar';
$labels['exportrange'] = 'Dogodki od';
$labels['exportattachments'] = 'S priponkami';
$labels['customdate'] = 'Poljubni datum';
$labels['location'] = 'Lokacija';
$labels['url'] = 'URL';
$labels['date'] = 'Datum';
$labels['start'] = 'Začetek';
$labels['starttime'] = 'Čas začetka';
$labels['end'] = 'Konec';
$labels['endtime'] = 'Čas konca';
$labels['repeat'] = 'Ponovi';
$labels['selectdate'] = 'Izberi datum';
$labels['freebusy'] = 'Prikaži me kot';
$labels['free'] = 'Prost';
$labels['busy'] = 'Zaseden';
$labels['outofoffice'] = 'Izven pisarne';
$labels['tentative'] = 'Pogojno';
$labels['mystatus'] = 'Moj status';
$labels['status'] = 'Status';
$labels['status-confirmed'] = 'Potrjeno';
$labels['status-cancelled'] = 'Preklicano';
$labels['priority'] = 'Prednost';
$labels['sensitivity'] = 'Zasebnost';
$labels['public'] = 'javno';
$labels['private'] = 'zasebno';
$labels['confidential'] = 'zaupno';
$labels['links'] = 'Sklic';
$labels['alarms'] = 'Opomnik';
$labels['comment'] = 'Komentar';
$labels['created'] = 'Ustvarjeno';
$labels['changed'] = 'Nazadnje urejeno';
$labels['unknown'] = 'Neznano';
$labels['eventoptions'] = 'Nastavitve';
$labels['generated'] = 'generirano ob';
$labels['eventhistory'] = 'Zgodovina';
$labels['removelink'] = 'Odstrani email povezavo';
$labels['printdescriptions'] = 'Opis za tisk';
$labels['parentcalendar'] = 'Vstavi';
$labels['searchearlierdates'] = '« Išči po prejšnjih dogodkih';
$labels['searchlaterdates'] = 'Išči po kasnejših dogodkih »';
$labels['andnmore'] = '$nr več...';
$labels['togglerole'] = 'Klikni za prikaz vloge';
$labels['createfrommail'] = 'Shrani kot dogodek';
$labels['importevents'] = 'Uvozi dogodke';
$labels['importrange'] = 'Dogodki od';
$labels['onemonthback'] = '1 mesec nazaj';
$labels['nmonthsback'] = '$nr mesecev nazaj';
$labels['showurl'] = 'Prikaži URL koledarja';
$labels['showurldescription'] = 'Za dostop do koledarja (samo za branje) iz drugih aplikacij uporabi naslednji naslov. Funkcija kopiraj in prilepi deluje z vsakim koledarjem v iCal formatu.';
$labels['caldavurldescription'] = 'Za sinhronizacijo tega koledarja z vašim računalnikom ali mobilno napravo, v podprto aplikacijo (npr. Evolution ali Mozilla Thunderbird) kopirajte ta naslov <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> .';
$labels['findcalendars'] = 'Išči koledarje...';
$labels['searchterms'] = 'Iskalni pogoji';
$labels['calsearchresults'] = 'Razpoložljivi koledarji';
$labels['calendarsubscribe'] = 'Označi za vedno';
$labels['nocalendarsfound'] = 'Ni najdenih koledarjev';
$labels['nrcalendarsfound'] = '$nr najdenih koledarjev';
$labels['quickview'] = 'Prikaži samo ta koledar';
$labels['invitationspending'] = 'Vabila za dogodek';
$labels['invitationsdeclined'] = 'Zavrnjena vabila';
$labels['changepartstat'] = 'Spremeni status sodelujočega';
$labels['rsvpcomment'] = 'Sporočilo vabila';
$labels['listrange'] = 'Prikaži v razponu:';
$labels['listsections'] = 'Razdeli v:';
$labels['smartsections'] = 'Pametni razdelki';
$labels['until'] = 'do';
$labels['today'] = 'Danes';
$labels['tomorrow'] = 'Jutri';
$labels['thisweek'] = 'Ta teden';
$labels['nextweek'] = 'Naslednji teden';
$labels['prevweek'] = 'Prejšnji teden';
$labels['thismonth'] = 'Ta mesec';
$labels['nextmonth'] = 'Naslednji mesec';
$labels['weekofyear'] = 'Teden';
$labels['pastevents'] = 'Pretekli';
$labels['futureevents'] = 'Prihodnji';
$labels['showalarms'] = 'Prikaži opomnike';
$labels['defaultalarmtype'] = 'Privzeta nastavitev opomnika';
$labels['defaultalarmoffset'] = 'Privzeti čas opomnika';
$labels['attendee'] = 'Udeleženec';
$labels['role'] = 'Vloga';
$labels['availability'] = 'Razpol.';
$labels['confirmstate'] = 'Status';
$labels['addattendee'] = 'Dodaj udeleženca';
$labels['roleorganizer'] = 'Organizator';
$labels['rolerequired'] = 'Zahtevano';
$labels['roleoptional'] = 'Neobvezno';
$labels['rolechair'] = 'Vodja sestanka';
$labels['rolenonparticipant'] = 'Odsoten';
$labels['cutypeindividual'] = 'Osebni';
$labels['cutypegroup'] = 'Skupina';
$labels['cutyperesource'] = 'Vir';
$labels['cutyperoom'] = 'Soba';
$labels['availfree'] = 'Prost';
$labels['availbusy'] = 'Zaseden';
$labels['availunknown'] = 'Neznano';
$labels['availtentative'] = 'Pogojno';
$labels['availoutofoffice'] = 'Izven pisarne';
$labels['delegatedto'] = 'Preneseno na:';
$labels['delegatedfrom'] = 'Preneseno od:';
$labels['scheduletime'] = 'Najdi razpoložljivost';
$labels['sendinvitations'] = 'Pošlji vabila';
$labels['sendnotifications'] = 'Sporoči udeležencem spremembe';
$labels['sendcancellation'] = 'Sporoči udeležencem odpoved dogodka';
$labels['onlyworkinghours'] = 'Najdi razpoložljivost med mojim delavnikom';
$labels['reqallattendees'] = 'Zahtevano/vsi udeleženci';
$labels['prevslot'] = 'Prejšnje mesto';
$labels['nextslot'] = 'Naslednje mesto';
$labels['suggestedslot'] = 'Predlagano mesto';
$labels['noslotfound'] = 'Ne najdem prostega mesta';
$labels['invitationsubject'] = 'Vabljeni ste v "$title"';
$labels['invitationmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nProsim preglejte pripeto iCalendar datoteko z vsemi informacijami o dogodku. Datoteko lahko uvozite v vašo koledar aplikacijo.";
$labels['invitationattendlinks'] = "V kolikor vaš email klient ne podpira iTip zahtevkov lahko uporabite naslednjo povezavo za sprejem ali zavrnitev vabila:\n\$url";
$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";
$labels['itipmailbodytentative'] = "\$sender je okvirno sprejel vabilo na dogodek:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
$labels['itipmailbodydeclined'] = "\$sender ni sprejel vabila na dogodek:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
$labels['itipmailbodycancel'] = "\$sender je zavrnil vaše sodelovanje pri dogodku:\n\n*\$title*\n\nWhen: \$date";
$labels['itipmailbodydelegated'] = "\$sender je prenesel sodelovanje na dogodku:\n\n*\$title*\n\nWhen: \$date";
$labels['itipmailbodydelegatedto'] = "\$sender je na vas prenesel sodelovanje na dogodku:\n\n*\$title*\n\nWhen: \$date";
$labels['itipdeclineevent'] = 'Želite zavrniti vabilo na ta dogodek?';
$labels['declinedeleteconfirm'] = 'Ali želite tudi izbrisati zavrnjeni dogodek iz vašega koledarja?';
$labels['itipcomment'] = 'Komentar vabila/obvestila';
$labels['itipcommenttitle'] = 'Komentar bo dodan k vabilu/obvestilu, ki bo poslano sodelujočim';
$labels['notanattendee'] = 'Niste označeni kot sodelujoči na tem sestanku';
$labels['eventcancelled'] = 'Ta dogodek je bil preklican';
$labels['saveincalendar'] = 'shrani v';
$labels['updatemycopy'] = 'Posodobi v mojem koledarju';
$labels['savetocalendar'] = 'Shrani v koledar';
$labels['openpreview'] = 'Preveri Koledar';
$labels['noearlierevents'] = 'Ni predhodnjih dogodkov';
$labels['nolaterevents'] = 'Ni kasnejših dogodkov';
$labels['resource'] = 'Vir';
$labels['addresource'] = 'Označi vir';
$labels['findresources'] = 'Poišči vire';
$labels['resourcedetails'] = 'Podrobnosti';
$labels['resourceavailability'] = 'Razpoložljivost';
$labels['resourceowner'] = 'Lastnik';
$labels['resourceadded'] = 'Vir je bil dodan v vašem dogodku';
$labels['tabsummary'] = 'Pregled';
$labels['tabrecurrence'] = 'Ponovitev';
$labels['tabattendees'] = 'Sodelujoči';
$labels['tabresources'] = 'Viri';
$labels['tabattachments'] = 'Priponke';
$labels['tabsharing'] = 'Deli z ostalimi';
$labels['deleteobjectconfirm'] = 'Ali želite potrditi brisanje tega dogodka?';
$labels['deleteventconfirm'] = 'Ali želite potrditi brisanje tega dogodka?';
$labels['deletecalendarconfirm'] = 'Ali želite izbrisati ta koledar z vsemi dogodki?';
$labels['deletecalendarconfirmrecursive'] = 'Ali želite izbrisati to koledar z vsemi dogodki in pod-koledarji?';
$labels['savingdata'] = 'Shranjujem...';
$labels['errorsaving'] = 'Napaka pri shranjevanju sprememb.';
$labels['operationfailed'] = 'Zahtevana operacija ni uspela.';
$labels['invalideventdates'] = 'Vnos datumov napačen! Prosim preverite vaš vnos.';
$labels['invalidcalendarproperties'] = 'Napačne nastavitve koledarja! Prosim nastavite pravilno ime.';
$labels['searchnoresults'] = 'V izbranih koledarjih ni dogodkov.';
$labels['successremoval'] = 'Dogodek je bil uspešno izbrisan.';
$labels['successrestore'] = 'Dogodek je bil uspešno obnovljen.';
$labels['errornotifying'] = 'Napaka. Pošiljanje obvestil sodelujočim ni bilo uspešno.';
$labels['errorimportingevent'] = 'Napaka pri uvozu dogodka';
$labels['importwarningexists'] = 'Različica tega dogodka že obstaja v vašem koledarju.';
$labels['newerversionexists'] = 'Obstaja novejša verzija tega dogodka!';
$labels['nowritecalendarfound'] = 'Za shranjevanje dogodka ni na voljo nobenega koledarja';
$labels['importedsuccessfully'] = 'Dogodek je bil uspešno dodan v \'$calendar\'';
$labels['updatedsuccessfully'] = 'Dogodek je bil uspešno posodobljen v \'$calendar\'';
$labels['attendeupdateesuccess'] = 'Posodabljanje statusa sodelujočega uspešno';
$labels['itipsendsuccess'] = 'Vabilo sodelujočim poslano';
$labels['itipresponseerror'] = 'Napaka. Pošiljanje odgovora na vabilo ni bilo uspešno';
$labels['itipinvalidrequest'] = 'To vabilo ni več veljavno';
$labels['sentresponseto'] = 'Odgovor je bil uspešno poslan na naslov $mailto';
$labels['localchangeswarning'] = 'Spremembe bodo vidne samo v vašem koledarju in ne bodo poslane organizatorju dogodka';
$labels['importsuccess'] = 'Uspešno uvoženih $nr dogodkov';
$labels['importnone'] = 'Ne najdem dogodkov za uvoz';
$labels['importerror'] = 'Pri uvozu je prišlo do napake';
$labels['aclnorights'] = 'Na tem koledarju nimate administratorskih pravic';
$labels['changeeventconfirm'] = 'Spremeni dogodek';
$labels['removeeventconfirm'] = 'Izbriši dogodek';
$labels['changerecurringeventwarning'] = 'To je ponavljajoč dogodek. Ali želite urediti samo trenutni dogodek, trenutni in vse prihodnje dogodke, vse ponavljajoče dogodke ali shraniti kot nov dogodek?';
$labels['removerecurringeventwarning'] = 'To je ponavljajoč dogodek. Ali želite izbrisati trenutni dogodek, trenutni in vse prihodnje dogodke ali vsa ponavljanja tega dogodka?';
$labels['currentevent'] = 'Trenutni';
$labels['futurevents'] = 'Prihodnji';
$labels['allevents'] = 'Vsi';
$labels['saveasnew'] = 'Shrani kot nov';
$labels['birthdays'] = 'Rojstni dnevi';
$labels['birthdayscalendar'] = 'Koledar rojstnih dnevov';
$labels['displaybirthdayscalendar'] = 'Prikaži koledar rojstnih dnevov';
$labels['birthdayscalendarsources'] = 'Iz teh imenikov';
$labels['birthdayeventtitle'] = 'Rojstni dan osebe $name';
$labels['birthdayage'] = 'Starost $age';
-$labels['eventchangelog'] = 'Spremeni Zgodovino';
+$labels['objectchangelog'] = 'Spremeni Zgodovino';
$labels['revision'] = 'Verzija';
$labels['user'] = 'Uporabnik';
$labels['operation'] = 'Dejanje';
$labels['actionappend'] = 'Shranjeno';
$labels['actionmove'] = 'Premaknjeno';
$labels['actiondelete'] = 'Izbrisano';
$labels['compare'] = 'Primerjaj';
$labels['showrevision'] = 'Prikaži to verzijo';
$labels['restore'] = 'Obnovi to verzijo';
-$labels['eventnotfound'] = 'Napaka pri nalaganju podatkov o dogodku';
+$labels['objectnotfound'] = 'Napaka pri nalaganju podatkov o dogodku';
$labels['objectchangelognotavailable'] = 'Sprememba zgodovine za ta dogodek ni na voljo';
-$labels['eventdiffnotavailable'] = 'Primerjava za izbrane verzije ni na voljo';
+$labels['objectdiffnotavailable'] = 'Primerjava za izbrane verzije ni na voljo';
$labels['revisionrestoreconfirm'] = 'Ali želite obnoviti verzijo $rev tega dogodka? To bo nadomestilo trenutni dogodek s starejšo verzijo.';
$labels['arialabelminical'] = 'Izbira datuma v koledarju';
$labels['arialabelcalendarview'] = 'Prikaz koledarja';
$labels['arialabelsearchform'] = 'Obrazec za iskanje dogodkov';
$labels['arialabelquicksearchbox'] = 'Vnos iskanja dogodkov';
$labels['arialabelcalsearchform'] = 'Obrazec za iskanje koledarjev';
$labels['calendaractions'] = 'Dejanja koledarja';
$labels['arialabeleventattendees'] = 'Seznam sodelujočih na dogodku';
$labels['arialabeleventresources'] = 'Seznam virov za dogodek';
$labels['arialabelresourcesearchform'] = 'Obrazec za iskanje virov';
$labels['arialabelresourceselection'] = 'Viri na voljo';
?>
diff --git a/plugins/calendar/localization/sv_SE.inc b/plugins/calendar/localization/sv_SE.inc
index 94e72131..edf1db65 100644
--- a/plugins/calendar/localization/sv_SE.inc
+++ b/plugins/calendar/localization/sv_SE.inc
@@ -1,273 +1,273 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$labels['default_view'] = 'Standardvy';
$labels['time_format'] = 'Tidformat';
$labels['timeslots'] = 'Tidsluckor per timme';
$labels['first_day'] = 'Första veckodag';
$labels['first_hour'] = 'Dagen börjar';
$labels['workinghours'] = 'Arbetstid';
$labels['add_category'] = 'Lägg till kategori';
$labels['remove_category'] = 'Ta bort kategori';
$labels['defaultcalendar'] = 'Skapa nya händelser i';
$labels['eventcoloring'] = 'Händelsefärg';
$labels['coloringmode0'] = 'Enligt kalender';
$labels['coloringmode1'] = 'Enligt kategori';
$labels['coloringmode2'] = 'Kalender för översikt, kategori för innehåll';
$labels['coloringmode3'] = 'Kategori för översikt, kalender för innehåll';
$labels['afternothing'] = 'Gör inget';
$labels['aftertrash'] = 'Flytta till papperskorgen';
$labels['afterdelete'] = 'Ta bort meddelandet';
$labels['afterflagdeleted'] = 'Märk som borttaget';
$labels['aftermoveto'] = 'Flytta till ...';
$labels['itipoptions'] = 'Händelseinbjudningar';
$labels['afteraction'] = 'Efter en inbjudan eller uppdatering bearbetats meddelande';
$labels['calendar'] = 'Kalender';
$labels['calendars'] = 'Kalendrar';
$labels['category'] = 'Kategori';
$labels['categories'] = 'Kategorier';
$labels['createcalendar'] = 'Skapa ny kalender';
$labels['editcalendar'] = 'Redigera kalenderegenskaper';
$labels['name'] = 'Namn';
$labels['color'] = 'Färg';
$labels['day'] = 'Dag';
$labels['week'] = 'Vecka';
$labels['month'] = 'Månad';
$labels['agenda'] = 'Agenda';
$labels['new'] = 'Ny';
$labels['new_event'] = 'Ny händelse';
$labels['edit_event'] = 'Redigera händelse';
$labels['edit'] = 'Redigera';
$labels['save'] = 'Spara';
$labels['removelist'] = 'Ta bort från lista';
$labels['cancel'] = 'Avbryt';
$labels['select'] = 'Välj';
$labels['print'] = 'Skriv ut';
$labels['printtitle'] = 'Skriv ut kalendrar';
$labels['title'] = 'Sammanfattning';
$labels['description'] = 'Beskrivning';
$labels['all-day'] = 'heldag';
$labels['export'] = 'Exportera';
$labels['exporttitle'] = 'Exportera till iCalendar';
$labels['exportrange'] = 'Händelser från';
$labels['exportattachments'] = 'Med bilagor';
$labels['customdate'] = 'Anpassat datum';
$labels['location'] = 'Plats';
$labels['url'] = 'URL';
$labels['date'] = 'Datum';
$labels['start'] = 'Start';
$labels['starttime'] = 'Starttid';
$labels['end'] = 'Slut';
$labels['endtime'] = 'Sluttid';
$labels['repeat'] = 'Upprepa';
$labels['selectdate'] = 'Välj datum';
$labels['freebusy'] = 'Visa mig som';
$labels['free'] = 'Ledig';
$labels['busy'] = 'Upptagen';
$labels['outofoffice'] = 'Frånvarande';
$labels['tentative'] = 'Preliminärt';
$labels['mystatus'] = 'Min status';
$labels['status'] = 'Status';
$labels['status-confirmed'] = 'Bekräftad';
$labels['status-cancelled'] = 'Inställd';
$labels['priority'] = 'Prioritet';
$labels['sensitivity'] = 'Integritet';
$labels['public'] = 'publik';
$labels['private'] = 'privat';
$labels['confidential'] = 'konfidentiell';
$labels['links'] = 'Referens';
$labels['alarms'] = 'Påminnelse';
$labels['comment'] = 'Kommentar';
$labels['created'] = 'Skapad';
$labels['changed'] = 'Senast ändrad';
$labels['unknown'] = 'Okänd';
$labels['eventoptions'] = 'Alternativ';
$labels['generated'] = 'genererad vid';
$labels['eventhistory'] = 'Historik';
$labels['removelink'] = 'Ta bort e-postreferens';
$labels['printdescriptions'] = 'Skriv ut beskrivning';
$labels['parentcalendar'] = 'Infoga inuti';
$labels['searchearlierdates'] = '« Sök efter tidigare händelser';
$labels['searchlaterdates'] = 'Sök efter senare händelser »';
$labels['andnmore'] = '$nr fler ...';
$labels['togglerole'] = 'Klicka för att växla roll';
$labels['createfrommail'] = 'Spara som händelse';
$labels['importevents'] = 'Importera händelser';
$labels['importrange'] = 'Händelser från';
$labels['onemonthback'] = '1 månad bakåt';
$labels['nmonthsback'] = '$nr månader bakåt';
$labels['showurl'] = 'Visa kalender-URL';
$labels['showurldescription'] = 'Använd följande adress för åtkomst (endast läsbar) till din kalender från andra applikationer. Du kan kopiera och klistra in adressen in i ett kalenderprogram som stöder iCal-formatet.';
$labels['caldavurldescription'] = 'Kopiera denna adress till ett <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> klientprogram (t.ex. Evolution eller Mozilla Thunderbird) för att helt synkronisera denna specifika kalender med din dator eller mobila enhet.';
$labels['findcalendars'] = 'Hitta kalendrar ...';
$labels['searchterms'] = 'Sökord';
$labels['calsearchresults'] = 'Tillgängliga kalendrar';
$labels['calendarsubscribe'] = 'Lista permanent';
$labels['nocalendarsfound'] = 'Inga kalendrar hittades';
$labels['nrcalendarsfound'] = '$nr kalendrar hittades';
$labels['quickview'] = 'Visa endast denna kalender';
$labels['invitationspending'] = 'Avvaktade inbjudningar';
$labels['invitationsdeclined'] = 'Avböjda inbjudningar';
$labels['changepartstat'] = 'Ändra deltagarstatus';
$labels['rsvpcomment'] = 'Inbjudningstext';
$labels['listrange'] = 'Intervall att visa';
$labels['listsections'] = 'Dela upp i';
$labels['smartsections'] = 'Smarta sektioner';
$labels['until'] = 'tills';
$labels['today'] = 'Idag';
$labels['tomorrow'] = 'Imorgon';
$labels['thisweek'] = 'Denna vecka';
$labels['nextweek'] = 'Nästa vecka';
$labels['prevweek'] = 'Föregående vecka';
$labels['thismonth'] = 'Denna månad';
$labels['nextmonth'] = 'Nästa månad';
$labels['weekofyear'] = 'Vecka';
$labels['pastevents'] = 'Förflutna';
$labels['futureevents'] = 'Framtida';
$labels['showalarms'] = 'Visa påminnelser';
$labels['defaultalarmtype'] = 'Standardinställning för påminnelser';
$labels['defaultalarmoffset'] = 'Standartid för påminnelser';
$labels['attendee'] = 'Deltagare';
$labels['role'] = 'Roll';
$labels['availability'] = 'Tillg.';
$labels['confirmstate'] = 'Status';
$labels['addattendee'] = 'Lägg till deltagare';
$labels['roleorganizer'] = 'Organisatör';
$labels['rolerequired'] = 'Obligatorisk';
$labels['roleoptional'] = 'Valfritt';
$labels['rolechair'] = 'Stol';
$labels['rolenonparticipant'] = 'Frånvarande';
$labels['cutypeindividual'] = 'Individuell';
$labels['cutypegroup'] = 'Grupp';
$labels['cutyperesource'] = 'Resurs';
$labels['cutyperoom'] = 'Rum';
$labels['availfree'] = 'Ledig';
$labels['availbusy'] = 'Upptagen';
$labels['availunknown'] = 'Okänd';
$labels['availtentative'] = 'Preliminärt';
$labels['availoutofoffice'] = 'Frånvarande';
$labels['delegatedto'] = 'Delegerad till:';
$labels['delegatedfrom'] = 'Delegerad från:';
$labels['scheduletime'] = 'Hitta tillgänglighet';
$labels['sendinvitations'] = 'Skicka inbjudningar';
$labels['sendnotifications'] = 'Meddela deltagare om ändringar';
$labels['sendcancellation'] = 'Meddela deltagare om att händelsen ställts in';
$labels['onlyworkinghours'] = 'Sök tillgänglighet inom min arbetstid';
$labels['reqallattendees'] = 'Obligatorisk/alla deltagare';
$labels['prevslot'] = 'Föregående lucka';
$labels['nextslot'] = 'Nästa lucka';
$labels['suggestedslot'] = 'Föreslagen lucka';
$labels['noslotfound'] = 'Det gick inte att hitta en ledig tidslucka';
$labels['invitationsubject'] = 'Du har blivit inbjuden till "$title"';
$labels['invitationmailbody'] = "*\$title*\n\nNär: \$date\n\nInbjudna: \$attendees\n\nHärmed bifogas en iCalendar-fil med alla detaljer om händelsen som du kan importera till din kalenderapplikation.";
$labels['invitationattendlinks'] = "Om din e-postklient inte stöder iTip-förfrågningar kan du använda följande länk för att antingen tacka ja eller eller nej till denna inbjudan:\n\$url";
$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";
$labels['itipmailbodytentative'] = "\$sender har preliminärt accepterat inbjudan till följande evenemang:\n\n*\$title*\n\nNär: \$date\n\nInbjudna: \$attendees";
$labels['itipmailbodydeclined'] = "\$sender har tackat nej till inbjudan till följande händelse:\n\n*\$title*\n\nNär: \$date\n\nIbjudna: \$attendees";
$labels['itipmailbodycancel'] = "\$sender har avvisat ditt deltagande i följande händelse:\n\n*\$title*\n\nNär: \$dat";
$labels['itipmailbodydelegated'] = "\$sender har delegerat deltagandet i följande händelse:\n\n*\$title*\n\nNär: \$date";
$labels['itipmailbodydelegatedto'] = "\$sender har delegerat deltagandet i följande händelse till dig:\n\n*\$title*\n\nNär: \$date";
$labels['itipdeclineevent'] = 'Vill du tacka nej till inbjudan till denna händelse?';
$labels['declinedeleteconfirm'] = 'Vill du även ta bort denna händelse, som du tackat nej till, från din kalender?';
$labels['itipcomment'] = 'Kommentar till inbjudan/meddelande';
$labels['itipcommenttitle'] = 'Denna kommentar kommer att bifogas i inbjudan/meddelandet som skickas till deltagarna';
$labels['notanattendee'] = 'Du är inte listad som en deltagare i denna händelse';
$labels['eventcancelled'] = 'Händelsen har ställts in';
$labels['saveincalendar'] = 'Spara i';
$labels['updatemycopy'] = 'Uppdatera i min kalender';
$labels['savetocalendar'] = 'Spara till kalender';
$labels['openpreview'] = 'Kontrollera kalender';
$labels['noearlierevents'] = 'Inga tidigare händelser';
$labels['nolaterevents'] = 'Inga senare händelser';
$labels['resource'] = 'Resurs';
$labels['addresource'] = 'Boka resurs';
$labels['findresources'] = 'Hitta resurser';
$labels['resourcedetails'] = 'Detaljer';
$labels['resourceavailability'] = 'Tillgänglighet';
$labels['resourceowner'] = 'Ägare';
$labels['resourceadded'] = 'Resursen har kopplats till din händelser ';
$labels['tabsummary'] = 'Sammanfattning';
$labels['tabrecurrence'] = 'Återkommande';
$labels['tabattendees'] = 'Deltagare';
$labels['tabresources'] = 'Resurser';
$labels['tabattachments'] = 'Bilagor';
$labels['tabsharing'] = 'Delning';
$labels['deleteobjectconfirm'] = 'Vill du verkligen ta bort denna händelse';
$labels['deleteventconfirm'] = 'Vill du verkligen ta bort denna händelse';
$labels['deletecalendarconfirm'] = 'Vill du verkligen ta bort denna kalender med alla dess händelser?';
$labels['deletecalendarconfirmrecursive'] = 'Vill du verkligen ta bort denna kalender med alla händelser och delkalendrar?';
$labels['savingdata'] = 'Sparar data ...';
$labels['errorsaving'] = 'Misslyckades att spara ändringar.';
$labels['operationfailed'] = 'Den begärda åtgärden misslyckades.';
$labels['invalideventdates'] = 'Ogiltiga datum angivna! Kontrollera din inmatning.';
$labels['invalidcalendarproperties'] = 'Ogiltiga kalenderegenskaper! Var god ange ett giltigt namn.';
$labels['searchnoresults'] = 'Inga händelser hittades i de valda kalendrarna.';
$labels['successremoval'] = 'Händelsen har tagits bort.';
$labels['successrestore'] = 'Händelsen har återställts.';
$labels['errornotifying'] = 'Det gick inte att skicka meddelande till händelsens deltagare';
$labels['errorimportingevent'] = 'Det gick inte att importera händelsen';
$labels['importwarningexists'] = 'En kopia av denna händelse finns redan i din kalender.';
$labels['newerversionexists'] = 'En nyare version av denna händelse finns redan! Åtgärd avbruten.';
$labels['nowritecalendarfound'] = 'Ingen kalender hittades att spara händelsen i';
$labels['importedsuccessfully'] = 'Händelsen har lagts till i \'$calendar\'';
$labels['updatedsuccessfully'] = 'Händelsen uppdaterades i \'$calendar\'';
$labels['attendeupdateesuccess'] = 'Uppdaterade deltagarens status';
$labels['itipsendsuccess'] = 'Inbjudan har skickats till deltagare.';
$labels['itipresponseerror'] = 'Det gick inte att skicka ett svar på inbjudan till denna händelse';
$labels['itipinvalidrequest'] = 'Denna inbjudan är inte längre giltig';
$labels['sentresponseto'] = 'Skickade svar på inbjudan till $mailto';
$labels['localchangeswarning'] = 'Du är på väg att göra ändringar som endast kommer att återspeglas i din kalender och inte skickas till organisatören av händelsen.';
$labels['importsuccess'] = 'Importerade $nr händelser';
$labels['importnone'] = 'Hittade inga händelser att importera';
$labels['importerror'] = 'Ett fel uppstod vid import';
$labels['aclnorights'] = 'Du har inga administratörsrättigheter i denna kalender.';
$labels['changeeventconfirm'] = 'Ändra händelse';
$labels['removeeventconfirm'] = 'Ta bort händelse';
$labels['changerecurringeventwarning'] = 'Detta är en återkommande händelse. Vill du redigera endast den aktuella händelsen, denna och alla framtida händelser, alla händelser eller spara den som en ny händelse?';
$labels['removerecurringeventwarning'] = 'etta är en återkommande händelse. Vill du ta bort endast den aktuella händelsen, denna och alla framtida händelser eller alla förekomster av denna händelse';
$labels['currentevent'] = 'Nuvarande';
$labels['futurevents'] = 'Framtida';
$labels['allevents'] = 'Alla';
$labels['saveasnew'] = 'Spara som ny';
$labels['birthdays'] = 'Födelsedagar';
$labels['birthdayscalendar'] = 'Födelsedagskalender';
$labels['displaybirthdayscalendar'] = 'Visa födelsedagskalender';
$labels['birthdayscalendarsources'] = 'Från dessa adressböcker';
$labels['birthdayeventtitle'] = '$name\s födelsedag';
$labels['birthdayage'] = '$age år';
-$labels['eventchangelog'] = 'Ändringshistorik';
+$labels['objectchangelog'] = 'Ändringshistorik';
$labels['revision'] = 'Revision';
$labels['user'] = 'Användare';
$labels['operation'] = 'Åtgärd';
$labels['actionappend'] = 'Sparad';
$labels['actionmove'] = 'Flyttad';
$labels['actiondelete'] = 'Borttagen';
$labels['compare'] = 'Jämför';
$labels['showrevision'] = 'Visa denna version';
$labels['restore'] = 'Återställ denna verson';
-$labels['eventnotfound'] = 'Det gick inte att läsa in data för händelsen';
+$labels['objectnotfound'] = 'Det gick inte att läsa in data för händelsen';
$labels['objectchangelognotavailable'] = 'Ändringshistorik är inte tillgänglig för denna händelse';
-$labels['eventdiffnotavailable'] = 'Ingen jämförelse möjlig för valda revisioner';
+$labels['objectdiffnotavailable'] = 'Ingen jämförelse möjlig för valda revisioner';
$labels['revisionrestoreconfirm'] = 'Vill du verkligen återställa revision $rev för denna händelse? Det kommer att ersätta den aktuella händelsen med den gamla versionen.';
$labels['arialabelminical'] = 'Kalender datumurval';
$labels['arialabelcalendarview'] = 'Kalender vy';
$labels['arialabelsearchform'] = 'Händelse sökformulär';
$labels['arialabelquicksearchbox'] = 'Händelse sökinmatning';
$labels['arialabelcalsearchform'] = 'Kalender sökformulär';
$labels['calendaractions'] = 'Kalender åtgärder';
$labels['arialabeleventattendees'] = 'Händelse deltagarlista';
$labels['arialabeleventresources'] = 'Händelse resurslista';
$labels['arialabelresourcesearchform'] = 'Resurser sökformulär';
$labels['arialabelresourceselection'] = 'Tillgängliga resurser';
?>
diff --git a/plugins/calendar/localization/th_TH.inc b/plugins/calendar/localization/th_TH.inc
index f1575436..c9933fc7 100644
--- a/plugins/calendar/localization/th_TH.inc
+++ b/plugins/calendar/localization/th_TH.inc
@@ -1,257 +1,257 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$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['coloringmode1'] = 'ตามหมวดหมู่';
$labels['afternothing'] = 'ไม่ต้องทำอะไร';
$labels['aftertrash'] = 'ย้ายลงถังขยะ';
$labels['afterdelete'] = 'ลบข้อความ';
$labels['afterflagdeleted'] = 'ติดธงว่าลบแล้ว';
$labels['aftermoveto'] = 'ย้ายไปยัง...';
$labels['itipoptions'] = 'เชิญเข้าร่วมนัดหมาย';
$labels['afteraction'] = 'ภายหลังการประมวลผลข้อความ คำเชิญ หรือ ปรับปรุงสถานภาพ';
$labels['calendar'] = 'ปฎิทิน';
$labels['calendars'] = 'ปฎิทิน';
$labels['category'] = 'หมวดหมู่';
$labels['categories'] = 'หมวดหมู่';
$labels['createcalendar'] = 'สร้างปฎิทินฉบับใหม่';
$labels['editcalendar'] = 'แก้ไขคุณสมบัติของปฎิทิน';
$labels['name'] = 'ชื่อ';
$labels['color'] = 'สี';
$labels['day'] = 'วัน';
$labels['week'] = 'สัปดาห์';
$labels['month'] = 'เดือน';
$labels['new'] = 'เพิ่ม';
$labels['new_event'] = 'เพิ่มนัดหมาย';
$labels['edit_event'] = 'แก้ไขนัดหมาย';
$labels['edit'] = 'แก้ไข';
$labels['save'] = 'บันทึก';
$labels['removelist'] = 'นำออกจากรายการ';
$labels['cancel'] = 'ยกเลิก';
$labels['select'] = 'เลือก';
$labels['print'] = 'พิมพ์';
$labels['printtitle'] = 'พิมพ์ปฎิทิน';
$labels['title'] = 'สรุป';
$labels['description'] = 'คำอธิบาย';
$labels['all-day'] = 'ทั้งวัน';
$labels['export'] = 'ส่งออก';
$labels['exporttitle'] = 'ส่งออกไปยัง iCalendar';
$labels['exportrange'] = 'เหตุการณ์จาก';
$labels['exportattachments'] = 'พร้อมสิ่งที่แนบมาด้วย';
$labels['location'] = 'สถานที่';
$labels['date'] = 'วันที่';
$labels['start'] = 'เริ่ม';
$labels['starttime'] = 'เวลาเริ่ม';
$labels['end'] = 'จบ';
$labels['endtime'] = 'กำหนดเสร็จ';
$labels['repeat'] = 'เกิดซ้ำ';
$labels['selectdate'] = 'เลือกวันที่';
$labels['free'] = 'ว่าง';
$labels['busy'] = 'ติดธุระ';
$labels['outofoffice'] = 'อยู่นอกออฟฟิศ';
$labels['tentative'] = 'แนวโน้ม';
$labels['mystatus'] = 'สถานะของฉัน';
$labels['status'] = 'สถานะ';
$labels['status-confirmed'] = 'ยืนยัน';
$labels['status-cancelled'] = 'ยกเลิก';
$labels['priority'] = 'ความสำคัญ';
$labels['sensitivity'] = 'ความเป็นส่วนตัว';
$labels['public'] = 'สาธารณะ';
$labels['private'] = 'ส่วนตัว';
$labels['confidential'] = 'ลับเฉพาะ';
$labels['links'] = 'อ้างอิง';
$labels['alarms'] = 'คำแจ้งเตือน';
$labels['comment'] = 'ความคิดเห็น';
$labels['created'] = 'สร้างเมื่อ';
$labels['changed'] = 'แก้ไขครั้งสุดท้ายเมื่อ';
$labels['unknown'] = 'ไม่ทราบ';
$labels['eventoptions'] = 'ทางเลือก';
$labels['eventhistory'] = 'ประวัติ';
$labels['printdescriptions'] = 'พิมพ์คำอธิบาย';
$labels['parentcalendar'] = 'เพิ่มเข้าภายใต้';
$labels['searchearlierdates'] = '« ค้นหากำหนดการณ์ที่เกิดชึ้นก่อนหน้า';
$labels['searchlaterdates'] = 'ค้นหากำหนดการณ์ที่เกิดขึ้นหลังจาก »';
$labels['andnmore'] = 'มีอีก $nr';
$labels['togglerole'] = 'กดเพื่อเปลี่ยนสลับบทบาท';
$labels['createfrommail'] = 'บันทึกเป็นเหตุการณ์';
$labels['importevents'] = 'นำเข้าเหตุการณ์';
$labels['importrange'] = 'เหตุการณ์จาก';
$labels['onemonthback'] = 'ย้อนหลัง 1 เดือน';
$labels['nmonthsback'] = 'ย้อนหลัง $nr เดือน';
$labels['showurl'] = 'แสดงลิงค์ปฎิทิน';
$labels['showurldescription'] = 'ใช้ลิงค์ที่อยู่ต่อไปนี้เพื่อเข้าถึง (อ่านเท่านั้น) ปฎิทินของคุณจากโปรแกรมอื่น คุณสามารถคัดลอกและนำไปวางไว้ในซอฟท์แวร์ปฎิทินที่รับรองรูปแบบ iCal';
$labels['caldavurldescription'] = 'คัดลอกลิงค์ที่อยู่นี้ไปยัง <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> โปรแกรมในเครื่องลูกข่าย (เช่น Evolution หรือ Mozilla Thunderbird) เพื่อซิงค์ข้อมูลปฎิทินฉบับนี้กับคอมพิวเตอร์หรืออุปกรณ์มือถือของคุณ';
$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['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['attendee'] = 'ผู้เข้าร่วม';
$labels['role'] = 'บทบาท';
$labels['confirmstate'] = 'สถานะ';
$labels['addattendee'] = 'เพิ่มผู้เข้าร่วม';
$labels['roleorganizer'] = 'ผู้จัดงาน';
$labels['rolerequired'] = 'บังคับ';
$labels['roleoptional'] = 'เลือกได้';
$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'] = 'แจ้งเตือนผู้เข้าร่วมสำหรับการแก้ไข';
$labels['sendcancellation'] = 'แจ้งเตือนผู้เข้าร่วมเกี่ยวกับการยกเลิก';
$labels['onlyworkinghours'] = 'ค้นหาเวลาว่างในช่วงชั่วโมงการทำงานของฉัน';
$labels['reqallattendees'] = 'บังคับ/ผู้เข้าร่วมทุกคน';
$labels['prevslot'] = 'ช่องว่างก่อนหน้านี้';
$labels['nextslot'] = 'ช่องว่า่งถัดจากนี้';
$labels['suggestedslot'] = 'แนะนำช่องว่าง';
$labels['noslotfound'] = 'ไม่สามารถหาช่วงเวลาที่ว่าง';
$labels['invitationsubject'] = 'คุณได้รับเชิญไปยัง "$title"';
$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";
$labels['itipmailbodytentative'] = "\$sender มีแนวโน้มที่จะตอบรับคำเชิญสำหรับเหตุการณ์ต่อไปนี้:\n\n*\$title*\n\nเมื่อ: \$date\n\nInvitees: \$attendees";
$labels['itipmailbodydeclined'] = "\$sender ได้ปฎิเสธคำเชิญสำหรับเหตุการณ์ต่อไปนี้ :\n\n*\$title*\n\nเมื่อ: \$date\n\nInvitees: \$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'] = 'ผู้เข้าร่วม';
$labels['tabresources'] = 'ทรัพยากร';
$labels['tabattachments'] = 'สิ่งที่แนบมาด้วย';
$labels['tabsharing'] = 'แบ่งปัน';
$labels['deleteobjectconfirm'] = 'คุณต้องการลบเหตุการณ์นี้หรือไม่';
$labels['deleteventconfirm'] = 'คุณต้องการลบเหตุการณ์นี้หรือไม่';
$labels['deletecalendarconfirm'] = 'คุณต้องการลบปฎิทินฉบับนี้พร้อมกับเหตุการณ์ทั้งหมดหรือไม่';
$labels['deletecalendarconfirmrecursive'] = 'คุณต้องการลบปฎิทินฉบับนี้พร้อมเหตุการณ์และปฎิทินย่อยทั้งหมดหรือไม่';
$labels['savingdata'] = 'บันทึกข้อมูล';
$labels['errorsaving'] = 'การบันทึกการเปลี่ยนแปลงล้มเหลว';
$labels['operationfailed'] = 'การทำตามคำร้องล้มเหลว';
$labels['invalideventdates'] = 'วันที่ที่ป้อนเข้ามาไม่ถูกต้อง โปรดตรวจสอบการป้อนข้อมูลของท่าน';
$labels['invalidcalendarproperties'] = 'การตั้งค่าคุณสมบัติปฎิทินไม่ถูกต้อง โปรดตั้งชื่อให้ถูกต้อง';
$labels['searchnoresults'] = 'ไม่พบเหตุการณ์ในปฎิทินฉบับที่เลือก';
$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['eventchangelog'] = 'ประวัติการปรับเปลี่ยน';
+$labels['objectchangelog'] = 'ประวัติการปรับเปลี่ยน';
$labels['revision'] = 'รุ่นการปรับปรุง';
$labels['user'] = 'ผู้ใช้';
$labels['operation'] = 'การกระทำ';
$labels['actionappend'] = 'บันทึกเรียบร้อย';
$labels['actionmove'] = 'ย้ายเรียบร้อย';
$labels['actiondelete'] = 'ลบเรียบร้อย';
$labels['compare'] = 'เปรียบเทียบ';
$labels['showrevision'] = 'แสดงรุ่นการปรับปรุงนี้';
$labels['restore'] = 'ย้อนกลับไปยังรุ่นการปรับปรุงนี้';
-$labels['eventnotfound'] = 'การโหลดข้อมูลของเหตุการณ์ล้มเหลว';
+$labels['objectnotfound'] = 'การโหลดข้อมูลของเหตุการณ์ล้มเหลว';
$labels['objectchangelognotavailable'] = 'ไม่มีประวัติการปรับเปลี่ยนสำหรับเหตุการณ์นี้';
-$labels['eventdiffnotavailable'] = 'ไม่สามารถเปรียบเทียบรุ่นการปรับปรุงที่เลือกได้';
+$labels['objectdiffnotavailable'] = 'ไม่สามารถเปรียบเทียบรุ่นการปรับปรุงที่เลือกได้';
$labels['revisionrestoreconfirm'] = 'คุณต้องการกู้คืนรุ่นการปรับปรุง $rev ของเหตุการณ์นี้หรือ นี่จะเป็นการเขียนทับข้อมูลปัจจุบันด้วยข้อมูลที่เก่ากว่า';
$labels['arialabelcalendarview'] = 'มุมมองปฎิทิน';
$labels['arialabelquicksearchbox'] = 'ป้อนข้อมูลเพื่อค้นหาเหตุการณ์';
$labels['arialabelcalsearchform'] = 'ฟอร์มค้นหาปฎิทิน';
$labels['arialabeleventattendees'] = 'รายชื่อผู้เข้าร่วมเหตุการณ์';
$labels['arialabeleventresources'] = 'รายการทรัพยากรที่ใช้ในเหตุการณ์';
$labels['arialabelresourcesearchform'] = 'ฟอร์มค้นหาทรัพยากร';
$labels['arialabelresourceselection'] = 'ทรัพยากรที่ยังว่าง';
?>
diff --git a/plugins/calendar/localization/uk_UA.inc b/plugins/calendar/localization/uk_UA.inc
index aac583a4..f4306675 100644
--- a/plugins/calendar/localization/uk_UA.inc
+++ b/plugins/calendar/localization/uk_UA.inc
@@ -1,228 +1,228 @@
<?php
/**
* Localizations for Kolab Calendar plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/calendar/
*/
$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['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'] = 'Категорія';
$labels['categories'] = 'Категорії';
$labels['createcalendar'] = 'Створити новий календар';
$labels['editcalendar'] = 'Змінити властивості календаря';
$labels['name'] = 'Назва';
$labels['color'] = 'Колір';
$labels['day'] = 'День';
$labels['week'] = 'Тиждень';
$labels['month'] = 'Місяць';
$labels['agenda'] = 'Розпорядок дня';
$labels['new'] = 'Новий';
$labels['new_event'] = 'Нова подія';
$labels['edit_event'] = 'Редагувати подію';
$labels['edit'] = 'Редагувати';
$labels['save'] = 'Зберегти';
$labels['removelist'] = 'Вилучити зі списку';
$labels['cancel'] = 'Відмінити';
$labels['select'] = 'Вибрати';
$labels['print'] = 'Друк';
$labels['printtitle'] = 'Друкувати календар';
$labels['title'] = 'Резюме';
$labels['description'] = 'Опис';
$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['public'] = 'публічна';
$labels['private'] = 'приватна';
$labels['confidential'] = 'конфіденційна';
$labels['alarms'] = 'Нагадування';
$labels['comment'] = 'Коментарій';
$labels['created'] = 'Створена';
$labels['changed'] = 'Змінена';
$labels['unknown'] = 'Невідомо';
$labels['eventoptions'] = 'Опції';
$labels['generated'] = 'створений';
$labels['eventhistory'] = 'Історія';
$labels['printdescriptions'] = 'Друк опису';
$labels['parentcalendar'] = 'Вставити всередину';
$labels['searchearlierdates'] = '« Шукати події раніше';
$labels['searchlaterdates'] = 'Шукати події пізніше »';
$labels['andnmore'] = '$nr більше...';
$labels['togglerole'] = 'Клікніть для перемикання ролі';
$labels['createfrommail'] = 'Зберегти як подію';
$labels['importevents'] = 'Імпортувати подію';
$labels['importrange'] = 'Події починаючи з';
$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> (наприклад, Evolution або Mozilla Thunderbird) для повної синхронізації даного календаря зі своїм комп\'ютером або мобільним пристроєм.';
$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'] = 'Розумні секції';
$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['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'] = 'Повідомити учасників про зміни';
$labels['sendcancellation'] = 'Повідомити учасників про скасування події';
$labels['reqallattendees'] = 'Необхідні/всі учасники';
$labels['prevslot'] = 'Попередній час';
$labels['nextslot'] = 'Наступний час';
$labels['suggestedslot'] = 'Пропонований час';
$labels['noslotfound'] = 'Неможливо знайти вільний час';
$labels['invitationsubject'] = 'Ви запрошені на ';
$labels['invitationmailbody'] = "*\$title*\n\nКоли: \$date\n\nЗапрошені: \$attendees\n\nУ вкладенні Ви знайдете файл iCalendar з усіма деталями події, який Ви можете імпортувати у Вашу програму-щоденник.";
$labels['invitationattendlinks'] = "У разі, якщо Ваш поштовий клієнт не підтримує запити iTip, Ви можете використати дане нижче посилання, щоб прийняти або відхилити це запрошення:\n\$url";
$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'] = 'Ви хочете відхилити запрошення на дану подію?';
$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'] = 'Учасники';
$labels['tabresources'] = 'Ресурси';
$labels['tabattachments'] = 'Вкладення';
$labels['tabsharing'] = 'Спільне використання';
$labels['savingdata'] = 'Збереження даних...';
$labels['errorsaving'] = 'Помилка збереження змін.';
$labels['changeeventconfirm'] = 'Змінити подію';
$labels['removeeventconfirm'] = 'Вилучити подію';
$labels['currentevent'] = 'Поточну';
$labels['futurevents'] = 'Майбутню';
$labels['allevents'] = 'Всі';
$labels['birthdays'] = 'Дні Народження';
$labels['birthdayscalendar'] = 'Календар Днів Народжень';
$labels['displaybirthdayscalendar'] = 'Показувати календар Днів Народжень';
$labels['birthdayscalendarsources'] = 'З даних адресних книг';
$labels['birthdayeventtitle'] = 'День Народження $name';
$labels['birthdayage'] = 'Вік $age';
-$labels['eventchangelog'] = 'Історія змін';
+$labels['objectchangelog'] = 'Історія змін';
$labels['revision'] = 'Ревізія';
$labels['user'] = 'Користувач';
$labels['operation'] = 'Дія';
$labels['actionappend'] = 'Збережено';
$labels['actionmove'] = 'Переміщено';
$labels['actiondelete'] = 'Вилучено';
$labels['compare'] = 'Порівняти';
$labels['showrevision'] = 'Показати дану весію';
$labels['restore'] = 'Відновити дану версію';
$labels['arialabelminical'] = 'Вибір дати';
$labels['arialabelcalendarview'] = 'Вигляд календаря';
$labels['arialabelsearchform'] = 'Форма пошуку подій';
$labels['arialabelquicksearchbox'] = 'Пошук подій';
$labels['arialabelcalsearchform'] = 'Форма пошуку календарів';
$labels['calendaractions'] = 'Дії з календарями';
$labels['arialabeleventattendees'] = 'Учасники події';
$labels['arialabeleventresources'] = 'Ресурси подій';
$labels['arialabelresourcesearchform'] = 'Форма пошуку ресурсів';
$labels['arialabelresourceselection'] = 'Доступні ресурси';
?>
diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css
index b0a86600..0669a8fd 100644
--- a/plugins/calendar/skins/larry/calendar.css
+++ b/plugins/calendar/skins/larry/calendar.css
@@ -1,2327 +1,2327 @@
/**
* Roundcube Calendar plugin styles for skin "Larry"
*
* Copyright (c) 2012-2014, Kolab Systems AG <contact@kolabsys.com>
* Screendesign by FLINT / Büro für Gestaltung, bueroflint.com
*
* The contents are subject to the Creative Commons Attribution-ShareAlike
* License. It is allowed to copy, distribute, transmit and to adapt the work
* by keeping credits to the original autors in the README file.
* See http://creativecommons.org/licenses/by-sa/3.0/ for details.
*/
body.calendarmain {
overflow: hidden;
}
body.calendarmain #mainscreen {
left: 0;
}
/* overrides for tablets and mobile phones */
@media screen and (max-device-width: 1024px){
body.calendarmain {
overflow: visible;
}
body.calendarmain #mainscreen {
min-width: 1000px !important;
min-height: 520px !important;
}
body.calendarmain #header {
min-width: 1020px !important;
}
}
#calendarsidebar {
position: absolute;
top: 0;
left: 10px;
bottom: 0;
width: 250px;
}
#datepicker {
position: absolute;
top: 40px;
left: 0;
width: 100%;
min-height: 190px;
}
#datepicker .ui-datepicker {
width: 100% !important;
box-shadow: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
}
#datepicker .ui-datepicker td a {
padding: 5px 4px;
font-size: 12px;
}
#datepicker td.ui-datepicker-activerange {
border-color: #69a2b6;
}
#datepicker .ui-datepicker-activerange a {
color: #185d7a;
background: #d9f1fb;
background: -moz-linear-gradient(top, #d9f1fb 0%, #c5e3ee 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#d9f1fb), color-stop(100%,#c5e3ee));
background: -o-linear-gradient(top, #d9f1fb 0%, #c5e3ee 100%);
background: -ms-linear-gradient(top, #d9f1fb 0%, #c5e3ee 100%);
background: linear-gradient(top, #d9f1fb 0%, #c5e3ee 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d9f1fb', endColorstr='#c5e3ee', GradientType=0);
}
#datepicker .ui-datepicker-days-cell-over a.ui-state-default {
color: #fff;
border-color: #2fa0c0;
background: rgba(73,180,210,0.6);
text-shadow: 0px 1px 1px #666;
filter: none;
}
#datepicker .ui-datepicker-activerange a.ui-state-active {
color: #fff;
background: #00acd4;
background: -moz-linear-gradient(top, #00acd4 0%, #008fc7 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#00acd4), color-stop(100%,#008fc7));
background: -o-linear-gradient(top, #00acd4 0%, #008fc7 100%);
background: -ms-linear-gradient(top, #00acd4 0%, #008fc7 100%);
background: linear-gradient(top, #00acd4 0%, #008fc7 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00acd4', endColorstr='#008fc7', GradientType=0);
}
#datepicker td.ui-datepicker-week-col {
cursor: pointer;
}
#datepicker .ui-datepicker-title {
margin: 2px 2.3em 3px 2.3em;
}
#datepicker .ui-datepicker .ui-datepicker-prev,
#datepicker .ui-datepicker .ui-datepicker-next {
top: 4px;
}
#calsidebarsplitter {
position: absolute;
left: 264px;
width: 6px;
top: 40px !important;
bottom: 0;
background: url(images/toggle.gif) -1px 48% no-repeat transparent;
}
div.sidebarclosed {
background-position: -8px 48% !important;
cursor: pointer;
}
#calsidebarsplitter:hover {
background-color: #ddd;
}
#calendar {
position: absolute;
top: 0;
left: 276px;
right: 0;
bottom: 0;
}
.calendarmain #message.statusbar {
border: 1px solid #c3c3c3;
border-bottom-color: #ababab;
}
#timezonedisplay {
position: absolute;
bottom: 5px;
right: 12px;
font-size: 0.85em;
color: #666;
}
#print {
width: 680px;
}
pre {
font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
}
#calendars {
position: absolute;
top: 276px;
left: 0;
bottom: 0;
right: 0;
}
#calendars .boxtitle {
position: relative;
}
#calendars .boxtitle a.iconbutton.search {
position: absolute;
top: 8px;
right: 8px;
width: 16px;
cursor: pointer;
background-position: -2px -317px;
}
#calendars .listsearchbox {
display: none;
}
#calendars .listsearchbox.expanded {
display: block;
}
#calendars .scroller {
top: 34px;
}
#calendars .listsearchbox.expanded + .scroller {
top: 68px;
}
#calendars .treelist li {
margin: 0;
position: relative;
}
#calendars .treelist li div.folder,
#calendars .treelist li div.calendar {
position: relative;
height: 28px;
}
#calendars .treelist li div.virtual {
height: 22px;
}
#calendars .treelist li span.calname {
display: block;
padding: 0px 18px 2px 2px;
position: absolute;
top: 7px;
left: 38px;
right: 45px;
cursor: default;
background: url(images/calendars.png) right 20px no-repeat;
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #004458;
}
.quickview-active #calendars .treelist div input,
.quickview-active #calendars .treelist div .calname {
opacity: 0.35;
}
.quickview-active #calendars .treelist div.focusview .calname {
opacity: 1.0;
background-image: none;
}
#calendars .treelist li div.virtual > span.calname {
color: #aaa;
top: 4px;
left: 20px;
}
#calendars .treelist li.x-birthdays span.calname,
#calendars .treelist li.x-invitations span.calname {
font-style: italic;
}
#calendars .treelist.flat li span.calname {
left: 24px;
right: 42px;
}
#calendars .treelist li span.handle {
display: inline-block;
position: absolute;
top: 8px;
right: 6px;
padding: 0;
width: 10px;
height: 10px;
border-radius: 7px;
font-size: 0.8em;
border: 1px solid rgba(0, 0, 0, 0.5);
-webkit-box-shadow: inset 0px 0 1px 1px rgba(0, 0, 0, 0.3);
-moz-box-shadow: inset 0px 0 1px 1px rgba(0, 0, 0, 0.3);
box-shadow: inset 0px 0 1px 1px rgba(0, 0, 0, 0.3);
}
#calendars .treelist div span.actions {
display: inline-block;
position: absolute;
top: 2px;
right: 22px;
padding: 5px 20px 0 6px;
/* min-width: 40px; */
height: 19px;
text-align: right;
z-index: 4;
}
#calendars .treelist div:hover span.actions {
top: 1px;
right: 21px;
border: 1px solid #c6c6c6;
border-radius: 4px;
background: #f7f7f7;
background: -moz-linear-gradient(top, #f9f9f9 0%, #e6e6e6 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f9f9f9), color-stop(100%,#e6e6e6));
background: -o-linear-gradient(top, #f9f9f9 0%, #e6e6e6 100%);
background: -ms-linear-gradient(top, #f9f9f9 0%, #e6e6e6 100%);
background: linear-gradient(top, #f9f9f9 0%, #e6e6e6 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f9f9', endColorstr='#e6e6e6', GradientType=0);
}
#calendars .treelist li a.subscribed {
display: inline-block;
position: absolute;
top: 5px;
right: 3px;
height: 16px;
width: 16px;
padding: 0;
background: url(images/calendars.png) -100px 0 no-repeat;
overflow: hidden;
text-indent: -5000px;
cursor: pointer;
}
#calendars .treelist div:hover a.subscribed,
#calendars .treelist div a.subscribed:focus {
background-position: 0 -110px;
}
#calendars .treelist div.subscribed a.subscribed,
#calendars .treelist div.subscribed a.subscribed:focus {
background-position: -16px -110px;
}
#calendars .treelist div.subscribed.partial a.subscribed,
#calendars .treelist div.subscribed.partial a.subscribed:focus {
background-position: -16px -148px;
}
#calendars .treelist div a.remove:focus,
#calendars .treelist div a.quickview:focus,
#calendars .treelist div a.subscribed:focus {
border-radius: 3px;
outline: 2px solid rgba(30,150,192, 0.5);
}
#calendars .treelist div a.remove,
#calendars .treelist div a.quickview {
display: inline-block;
width: 16px;
height: 16px;
margin-right: 4px;
padding: 0;
background: url(images/calendars.png) -100px 0 no-repeat;
overflow: hidden;
text-indent: -5000px;
cursor: pointer;
}
#calendars .treelist div a.quickview:focus,
#calendars .treelist div:hover a.quickview {
background-position: 0 -128px;
background-color: transparent !important;
}
#calendars .treelist div.focusview a.quickview {
background-position: -16px -128px;
}
#calendars .treelist div a.remove:focus,
#calendars .treelist div:hover a.remove {
background-position: -16px -168px;
background-color: transparent !important;
}
#calendars .searchresults .treelist div a.remove {
display: none;
}
#calendars .treelist li input {
position: absolute;
top: 5px;
left: 18px;
}
#calendars .treelist li div.treetoggle {
top: 8px;
}
#calendars .treelist li.virtual div.treetoggle {
top: 6px;
}
#calendars .treelist.flat li input {
left: 4px;
}
#calendars .treelist ul li div.folder,
#calendars .treelist ul li div.calendar {
margin-left: 16px;
}
#calendars .treelist ul ul li div.folder,
#calendars .treelist ul ul li div.calendar {
margin-left: 32px;
}
#calendars .treelist ul ul ul li div.folder,
#calendars .treelist ul ul ul li div.calendar {
margin-left: 48px;
}
#calendars .treelist li.selected > div.calendar {
background-color: #c7e3ef;
}
#calendars .treelist li.selected > span.calname {
font-weight: bold;
}
#calendars .treelist div.readonly span.calname {
background-position: right -20px;
}
#calendars .treelist li.user > div > span.calname {
background-position: right -38px;
}
/*
#calendars .treelist div.user.readonly span.calname {
background-position: right -56px;
}
#calendars .treelist div.shared span.calname {
background-position: right -74px;
}
#calendars .treelist div.shared.readonly span.calname {
background-position: right -92px;
}
*/
#calendars .treelist .calendar .count {
position: absolute;
display: inline-block;
top: 5px;
right: 68px;
min-width: 1.3em;
padding: 2px 4px;
background: #005d76;
background: -moz-linear-gradient(top, #005d76 0%, #004558 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#005d76), color-stop(100%,#004558));
background: -o-linear-gradient(top, #005d76 0%, #004558 100%);
background: -ms-linear-gradient(top, #005d76 0%, #004558 100%);
background: linear-gradient(to bottom, #005d76 0%, #004558 100%);
-webkit-box-shadow: inset 0 1px 1px 0 #002635;
box-shadow: inset 0 1px 1px 0 #002635;
border-radius: 10px;
color: #fff;
text-align: center;
font-style: normal;
font-weight: bold;
text-shadow: none;
z-index: 3;
}
#calendars .searchresults {
background: #b0ccd7;
margin-top: 8px;
}
#calendars .searchresults .boxtitle {
background: none;
padding: 2px 8px 2px 8px;
}
#calendars .searchresults .listing li {
background-color: #c7e3ef;
}
#calfeedurl,
#caldavurl {
width: 98%;
background: #fbfbfb;
padding: 4px;
margin-bottom: 1em;
resize: none;
}
#agendalist {
width: 100%;
margin: 0 auto;
margin-top: 60px;
border: 1px solid #C1DAD7;
display: none;
}
#agendalist table {
width: 100%;
}
#agendalist td,
#agendalist th {
border-right: 1px solid #C1DAD7;
border-bottom: 1px solid #C1DAD7;
background: #fff;
padding: 6px 6px 6px 12px;
}
#agendalist tr {
vertical-align: top;
}
#agendalist th {
font-weight: bold;
}
#calendartoolbar {
position: absolute;
top: -6px;
left: 0;
height: 40px;
white-space: nowrap;
}
#calendartoolbar a.button {
background-image: url(images/toolbar.png);
padding-left: 0;
padding-right: 0;
min-width: 50px;
max-width: 60px;
}
#calendartoolbar a.button.addevent {
background-position: center 1px;
max-width: 70px;
}
#calendartoolbar a.button.export {
background-position: center -40px;
}
#calendartoolbar a.button.import {
background-position: center -440px;
}
#calendartoolbar a.button.print {
background-position: center -80px;
}
body.calendarmain #quicksearchbar {
z-index: 20;
}
body.calendarmain #searchmenulink {
width: 15px;
}
.calendarmain div.uidialog {
display: none;
}
#user {
position: absolute;
top: 10px;
right: 100px;
left: 100px;
text-align: center;
}
a.morelink {
font-size: 90%;
color: #0069a6;
text-decoration: none;
}
a.morelink:hover {
text-decoration: underline;
}
a.miniColors-trigger {
margin-top: -3px;
}
.calendar.attachmentwin #attachmenttoolbar {
position: relative;
top: -6px;
height: 40px;
}
.calendar.attachmentwin #attachmentcontainer {
position: absolute;
top: 0;
left: 232px;
right: 0;
bottom: 0;
}
.calendar.attachmentwin #attachmentframe {
width: 100%;
height: 100%;
border: 0;
background-color: #fff;
border-radius: 4px;
}
.calendar.attachmentwin #partheader {
position: absolute;
top: 0;
left: 0;
width: 220px;
bottom: 0;
}
.calendar.attachmentwin #partheader table {
table-layout: fixed;
overflow: hidden;
}
.calendar.attachmentwin #partheader table td {
color: #666;
padding: 4px 6px;
text-overflow: ellipsis;
overflow: hidden;
}
.calendar.attachmentwin #partheader table td.header {
font-weight: bold;
}
.calendar.attachmentwin #partheader table td.title {
width: 60px;
padding-right: 0;
}
#edit-attachments {
margin: 0.6em 0;
}
#edit-attachments ul li {
display: block;
color: #333;
font-weight: bold;
padding: 4px 4px 3px 30px;
text-shadow: 0px 1px 1px #fff;
text-decoration: none;
white-space: nowrap;
line-height: 20px;
}
#edit-attachments ul li a.file {
padding: 0;
}
#edit-attachments-form {
margin-top: 1em;
padding-top: 0.8em;
border-top: 2px solid #fafafa;
}
#edit-attachments-form .formbuttons {
margin: 0.5em 0;
}
#eventedit .droptarget {
background-image: url(../../../../skins/larry/images/filedrop.png) !important;
background-position: center bottom !important;
background-repeat: no-repeat !important;
}
#eventedit .droptarget.hover,
#eventedit .droptarget.active {
border-color: #019bc6;
box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
-moz-box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
-webkit-box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
-o-box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
}
#eventedit .droptarget.hover {
background-color: #d9ecf4;
box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
-moz-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
-webkit-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
-o-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
}
#event-attachments .attachmentslist li {
float: left;
margin-right: 1em;
}
#event-attachments .attachmentslist li a {
outline: none;
}
#event-panel-attachments.disabled .attachmentslist li a.delete {
visibility: hidden;
}
.event-attendees span.attendee {
padding-right: 18px;
margin-right: 0.5em;
background: url(images/attendee-status.png) right 0 no-repeat;
}
.event-attendees span.attendee a.mailtolink {
text-decoration: none;
white-space: nowrap;
outline: none;
}
.event-attendees span.attendee a.mailtolink:hover {
text-decoration: underline;
}
.event-attendees span.accepted {
background-position: right -20px;
}
.event-attendees span.declined {
background-position: right -40px;
}
.event-attendees span.tentative {
background-position: right -60px;
}
.event-attendees span.delegated {
background-position: right -180px;
}
.event-attendees span.organizer {
background-position: right -80px;
}
#all-event-attendees span.attendee {
display: block;
margin-bottom: 0.4em;
padding-bottom: 0.3em;
border-bottom: 1px solid #ddd;
}
.calendarmain .fc-view-table td.fc-list-header,
#attendees-freebusy-table h3.boxtitle,
#schedule-freebusy-times thead th,
.edit-attendees-table thead th
{
color: #69939e;
font-size: 11px;
font-weight: bold;
background: #d6eaf3;
background: -moz-linear-gradient(left, #e3f2f6 0, #d6eaf3 14px, #d6eaf3 100%);
background: -webkit-gradient(linear, left top, right top, color-stop(0,#e3f2f6), color-stop(8%,#d6eaf3), color-stop(100%,#d6eaf3));
background: -o-linear-gradient(left, #e3f2f6 0, #d6eaf3 14px, #d6eaf3 100%);
background: -ms-linear-gradient(left, #e3f2f6 0, #d6eaf3 14px ,#d6eaf3 100%);
background: linear-gradient(left, #e3f2f6 0, #d6eaf3 14px, #d6eaf3 100%);
border: 0;
border-bottom: 1px solid #ccc;
height: 18px;
line-height: 18px;
padding: 8px 7px 3px 7px;
}
/* jQuery UI overrides */
.calendarmain .eventdialog h1 {
font-size: 18px;
margin: -0.3em 0 0.4em 0;
}
.calendarmain .eventdialog label,
.calendarmain .eventdialog h5.label {
font-weight: normal;
font-size: 1em;
color: #999;
margin: 0 0 0.2em 0;
}
.calendarmain .eventdialog label span.index,
.calendarmain .eventdialog h5.label .index {
vertical-align: inherit;
margin-left: 0.6em;
}
.calendarmain .eventdialog {
margin: 0 -0.2em;
}
.calendarmain .eventdialog.status-cancelled {
background: url(images/badge_cancelled.png) top right no-repeat;
}
.calendarmain .eventdialog.sensitivity-private {
background: url(images/badge_private.png) top right no-repeat;
}
.calendarmain .eventdialog.sensitivity-confidential {
background: url(images/badge_confidential.png) top right no-repeat;
}
.calendarmain .sensitivity-private #event-title {
margin-right: 50px;
}
.calendarmain .sensitivity-confidential #event-title {
margin-right: 60px;
}
.calendarmain .eventdialog div.event-line {
margin-top: 0.1em;
margin-bottom: 0.3em;
}
.calendarmain .eventdialog div.event-line a.iconbutton {
margin-left: 0.5em;
line-height: 17px;
}
.calendarmain .eventdialog div.event-line span.event-text + label {
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 {
padding: 2px;
}
.eventdialog .event-text-diff del,
.eventdialog .event-text-diff ins {
text-decoration: none;
color: inherit;
}
.eventdialog .event-text-old,
.eventdialog .event-text-diff del {
background-color: #fdd;
/* text-decoration: line-through; */
}
.eventdialog .event-text-new,
.eventdialog .event-text-diff ins {
background-color: #dfd;
}
#eventdiff .attachmentslist li a,
#eventdiff .attachmentslist li a:hover {
cursor: default;
text-decoration: none;
}
-#eventhistory .loading {
+.changelog-table .loading {
color: #666;
margin: 1em 0;
padding: 1px 0 2px 24px;
background: url(images/loading_blue.gif) top left no-repeat;
}
-#eventhistory .compare-button {
+.changelog-dialog .compare-button {
margin: 4px 0;
}
.changelog-table tbody td {
padding: 4px 7px;
vertical-align: middle;
}
.changelog-table tbody tr:last-child td {
border-bottom: 0;
}
.changelog-table tbody tr.undisclosed td.date,
.changelog-table tbody tr.undisclosed td.user {
font-style: italic;
}
.changelog-table .diff {
width: 4em;
padding: 2px;
}
.changelog-table .revision {
width: 6em;
}
.changelog-table .date {
width: 11em;
}
.changelog-table .user {
width: auto;
}
.changelog-table .operation {
width: 15%;
}
.changelog-table .actions {
width: 50px;
text-align: right;
padding: 4px;
}
.changelog-table td a.iconbutton.restore,
.changelog-table td a.iconbutton.preview {
width: 16px;
margin-right: 2px;
background-image: url(images/calendars.png);
background-position: -1px -147px;
}
.changelog-table td a.iconbutton.restore {
background-image: url(images/calendars.png);
background-position: -1px -167px;
}
.changelog-table tr.first td a.iconbutton {
opacity: 0.3;
cursor: default;
}
#event-partstat .changersvp {
cursor: pointer;
color: #333;
text-decoration: none;
}
#event-partstat .iconbutton {
visibility: hidden;
}
#event-partstat .changersvp:focus .iconbutton,
#event-partstat:hover .iconbutton {
visibility: visible;
}
#eventedit {
position: relative;
top: -1.5em;
padding: 0.5em 0.1em;
margin: 0 -0.2em;
}
#eventedit input.text,
#eventedit textarea {
width: 97%;
}
#eventtabs {
position: relative;
padding: 0;
border: 0;
border-radius: 0;
}
div.form-section,
.calendarmain .eventdialog div.event-section,
#eventtabs div.event-section {
margin-top: 0.2em;
margin-bottom: 0.6em;
}
#eventtabs .border-after {
padding-bottom: 0.8em;
margin-bottom: 0.8em;
border-bottom: 2px solid #fafafa;
}
.calendarmain .eventdialog label,
#eventedit label,
.form-section label {
display: inline-block;
min-width: 7em;
padding-right: 0.5em;
}
.calendarmain .eventdialog #event-url .event-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
#event-links .attachmentslist {
display: inline-block;
}
#event-links label,
#edit-event-links label {
float: left;
margin-top: 0.3em;
padding-right: 0.75em;
}
#edit-event-links .event-text {
margin-left: 8em;
min-height: 22px;
}
#edit-event-links .attachmentslist li.message a.messagelink,
#event-links .attachmentslist li.message a.messagelink {
padding: 0 0 0 24px;
}
#edit-event-links .attachmentslist li a.delete {
top: 0;
background-position: -6px -378px;
}
#edit-event-links .attachmentslist li.deleted a.messagelink,
#edit-event-links .attachmentslist li.deleted a.messagelink:hover {
text-decoration: line-through;
}
#eventedit .formtable td.label {
min-width: 6em;
}
td.topalign {
vertical-align: top;
}
#eventedit label.weekday,
#eventedit label.monthday {
min-width: 3em;
}
#eventedit label.month {
min-width: 5em;
}
#eventedit .formtable td {
padding: 0.2em 0;
}
.ui-dialog .event-update-confirm {
padding: 0 0.5em 0.5em 0.5em;
}
.event-dialog-message,
.event-update-confirm .message {
margin-top: 0.5em;
padding: 0.8em;
border: 1px solid #ffdf0e;
background-color: #fef893;
}
.event-dialog-message .message,
.event-update-confirm .message {
margin-bottom: 0.5em;
}
.edit-recurring-warning .savemode {
padding-left: 20px;
}
.event-update-confirm .savemode {
padding-left: 30px;
}
.event-dialog-message span.ui-icon,
.event-update-confirm span.ui-icon {
float: left;
margin: 0 7px 20px 0;
}
.event-dialog-message label,
.event-update-confirm label {
min-width: 3em;
padding-right: 1em;
}
.event-update-confirm a.button {
margin: 0 0.5em 0 0.2em;
min-width: 5em;
text-align: center;
}
.libcal-rsvp-replymode li a {
cursor: default;
}
#event-rsvp,
#edit-attendees-notify {
margin: 0.6em 0 0.3em 0;
padding: 0.5em;
}
#event-rsvp .itip-reply-controls {
margin-top: 0.5em;
}
#event-rsvp .itip-reply-controls label {
color: #333;
}
#event-rsvp .itip-reply-controls textarea {
width: 95%;
}
#eventedit .edit-attendees-table {
width: 100%;
margin-top: 0.5em;
}
#eventedit .edit-attendees-table th.role,
#eventedit .edit-attendees-table td.role {
width: 9em;
}
#eventedit .edit-attendees-table th.availability,
#eventedit .edit-attendees-table td.availability,
#eventedit .edit-attendees-table th.confirmstate,
#eventedit .edit-attendees-table td.confirmstate {
width: 4em;
}
#eventedit .edit-attendees-table th.options,
#eventedit .edit-attendees-table td.options {
width: 16px;
padding: 2px 4px;
}
#eventedit .edit-attendees-table th.invite,
#eventedit .edit-attendees-table td.invite {
width: 44px;
padding: 2px;
}
#eventedit .edit-attendees-table th.invite label {
display: inline-block;
position: relative;
top: 4px;
width: 24px;
height: 18px;
min-width: 24px;
padding: 0;
overflow: hidden;
text-indent: -5000px;
white-space: nowrap;
background: url(images/sendinvitation.png) 1px 0 no-repeat;
}
#eventedit .edit-attendees-table tbody tr:last-child td {
border-bottom: 0;
}
#eventedit .edit-attendees-table th.name,
#eventedit .edit-attendees-table td.name {
width: auto;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#eventedit .edit-attendees-table td.name select {
width: 100%;
}
#eventedit .edit-attendees-table td.name .attendee-name {
display: block;
position: relative;
overflow: hidden;
text-overflow: ellipsis;
padding: 5px 7px 6px;
margin: -5px -7px -6px;
}
#eventedit .edit-attendees-table a.deletelink {
display: inline-block;
width: 17px;
height: 17px;
padding: 0;
overflow: hidden;
text-indent: 1000px;
}
#eventedit .edit-attendees-table a.expandlink {
position: absolute;
top: 4px;
right: 6px;
width: 16px;
height: 16px;
}
#edit-attendees-form,
#edit-resources-form {
position: relative;
margin-top: 15px;
}
#edit-attendees-form .attendees-invitebox {
text-align: right;
margin: 0;
}
#edit-attendees-form .attendees-invitebox label {
padding-right: 3px;
}
#edit-resources-form #edit-resource-find {
position: absolute;
top: 0;
right: 0;
}
#edit-attendees-form #edit-attendee-schedule {
position: absolute;
right: 0;
top: 0;
}
.edit-attendees-table select.edit-attendee-role {
border: 0;
padding: 2px;
background: white;
width: 100%;
}
.availability img.availabilityicon {
margin: 1px;
width: 14px;
height: 14px;
border-radius: 4px;
-moz-border-radius: 4px;
}
.availability img.availabilityicon.loading {
background: url(images/loading_blue.gif) center no-repeat;
}
#schedule-freebusy-times td.unknown,
.availability img.availabilityicon.unknown {
background: #ddd;
}
#schedule-freebusy-times td.free,
.availability img.availabilityicon.free {
background: #abd640;
}
#schedule-freebusy-times td.busy,
.availability img.availabilityicon.busy {
background: #e26569;
}
#schedule-freebusy-times td.tentative,
.availability img.availabilityicon.tentative {
background: #8383fc;
}
#schedule-freebusy-times td.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 {
background-image: url(images/freebusy-colors.png);
background-position: top right;
background-repeat: no-repeat;
}
#schedule-freebusy-times td.all-tentative {
background-position: right -40px;
}
#schedule-freebusy-times td.all-out-of-office {
background-position: right -80px;
}
#edit-attendees-legend {
margin-top: 3em;
margin-bottom: 0.5em;
}
#edit-attendees-legend .legend {
margin-right: 2em;
white-space: nowrap;
}
#edit-attendees-legend img.availabilityicon {
vertical-align: middle;
}
.edit-attendees-table tbody td.confirmstate {
overflow: hidden;
white-space: nowrap;
text-indent: -2000%;
}
.edit-attendees-table td.confirmstate span {
display: block;
width: 20px;
background: url(images/attendee-status.png) 5px 0 no-repeat;
}
.edit-attendees-table td.confirmstate span.needs-action {
}
.edit-attendees-table td.confirmstate span.accepted {
background-position: 5px -20px;
}
.edit-attendees-table td.confirmstate span.declined {
background-position: 5px -40px;
}
.edit-attendees-table td.confirmstate span.tentative {
background-position: 5px -60px;
}
.edit-attendees-table td.confirmstate span.delegated {
background-position: 5px -180px;
}
#attendees-freebusy-table {
width: 100%;
table-layout: fixed;
border: 1px solid #bbd3da;
}
#attendees-freebusy-table td.attendees {
width: 18em;
vertical-align: top;
overflow: hidden;
}
#attendees-freebusy-table td.times {
width: auto;
vertical-align: top;
}
#attendees-freebusy-table div.scroll {
position: relative;
overflow: auto;
}
#attendees-freebusy-table h3.boxtitle {
margin: 0;
border-color: #ccc;
}
.attendees-list .attendee {
padding: 4px 4px 4px 1px;
background: url(images/attendee-status.png) 2px -97px no-repeat;
white-space: nowrap;
}
.attendees-list a.attendee-role-toggle {
display: inline-block;
width: 16px;
margin-right: 3px;
cursor: pointer;
}
.attendees-list div.attendee {
border-top: 1px solid #ccc;
}
.attendees-list span.attendee {
padding-left: 20px;
margin-right: 2em;
}
.attendees-list .organizer {
background-position: 3px -77px;
}
.attendees-list .opt-participant {
background-position: 2px -117px;
}
.attendees-list .non-participant {
background-position: 2px -137px;
}
.attendees-list .chair {
background-position: 2px -157px;
}
.attendees-list .loading {
background: url(images/loading_blue.gif) 1px 50% no-repeat;
}
.attendees-list .total {
background: none;
padding-left: 4px;
font-weight: bold;
}
.attendees-list .spacer,
#schedule-freebusy-times tr.spacer td {
background: 0;
font-size: 50%;
}
#schedule-freebusy-times {
border-collapse: collapse;
width: 100%;
}
#schedule-freebusy-times td {
padding: 4px;
border: 1px solid #ccc;
}
#attendees-freebusy-table div.timesheader,
#schedule-freebusy-times tr.times td {
min-width: 30px;
font-size: 9px;
padding: 5px 2px 6px 2px;
text-align: center;
color: #004658;
}
#schedule-freebusy-times tr.times td.allday {
min-width: 60px;
}
#schedule-freebusy-times tr.times td {
cursor: pointer;
}
#schedule-event-time {
position: absolute;
border: 2px solid #333;
background: #777;
background: rgba(60, 60, 60, 0.6);
opacity: 0.5;
border-radius: 4px;
cursor: move;
filter: alpha(opacity=40); /* IE8 */
}
#eventfreebusy .schedule-options {
position: relative;
margin-bottom: 1.5em;
}
#eventfreebusy .schedule-buttons {
position: absolute;
top: 0.5em;
right: 0;
margin-right: 0;
}
#eventfreebusy .schedule-find-buttons {
padding-bottom:0.5em;
}
#eventfreebusy .schedule-find-buttons button {
min-width: 9em;
text-align: center;
}
#eventedit .attendees-commentbox label {
display: block;
}
#eventedit .ui-tabs-panel {
min-height: 24em;
}
#rcmKSearchpane ul li.resource i.icon,
#rcmKSearchpane ul li.collection i.icon {
background-image: url(images/autocomplete.png);
background-position: -1px -2px;
}
#rcmKSearchpane ul li.collection i.icon {
background-position: -1px -26px;
}
a.dropdown-link {
font-size: 11px;
text-decoration: none;
}
a.dropdown-link:after {
content: ' ▼';
font-size: 10px;
color: #666;
}
.ui-dialog-buttonset a.dropdown-link {
position: relative;
top: 2px;
margin: 0 1em;
color: #333;
}
#calendarsidebar .ui-datepicker-calendar {
table-layout: fixed;
}
.ui-datepicker-calendar .ui-datepicker-week-col {
border: 0;
color: #999;
font-size: 90%;
text-align: right;
padding-right: 6px;
width: 20px;
overflow: hidden;
}
.ui-autocomplete {
max-height: 160px;
overflow-y: auto;
overflow-x: hidden;
}
.ui-autocomplete .ui-menu-item {
white-space: nowrap;
}
* html .ui-autocomplete {
height: 160px;
}
.calendarmain span.spacer {
padding-left: 3em;
}
#agendaoptions {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: auto;
z-index: 10;
padding: 4px 5px;
border: 1px solid #c3c3c3;
border-top-color: #ddd;
border-bottom-color: #bbb;
border-radius: 0 0 4px 4px;
background: #ebebeb;
background: -moz-linear-gradient(top, #ebebeb 0%, #c6c6c6 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ebebeb), color-stop(100%,#c6c6c6));
background: -o-linear-gradient(top, #ebebeb 0%, #c6c6c6 100%);
background: -ms-linear-gradient(top, #ebebeb 0%, #c6c6c6 100%);
background: linear-gradient(top, #ebebeb 0%, #c6c6c6 100%);
}
#agendaoptions label {
text-shadow: 1px 1px #fff;
padding-right: 0.5em;
}
#calendar-kolabform {
position: relative;
margin: 0 -8px;
min-width: 660px;
min-height: 400px;
}
#calendar-kolabform table td.title {
font-weight: bold;
white-space: nowrap;
color: #666;
padding-right: 10px;
}
#resource-selection {
position: absolute;
top: 0;
left: 8px;
right: 0;
bottom: 0;
}
#resource-selection .scroller {
top: 34px;
}
#resource-dialog-left {
position: absolute;
top: 10px;
left: 0;
width: 380px;
bottom: 10px;
}
#resource-dialog-right {
position: absolute;
top: 10px;
left: 392px;
right: 8px;
bottom: 10px;
}
#resource-info {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 48%;
}
#resource-info table {
margin: 8px;
width: 97%;
}
#resource-info thead td {
background: none;
font-weight: bold;
font-size: 14px;
}
#resource-availability {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 49%;
}
#resource-freebusy-calendar {
position: absolute;
top: 33px;
left: -1px;
right: -1px;
bottom: -1px;
}
#resource-freebusy-calendar .fc-content {
top: 0;
}
#resource-freebusy-calendar .fc-content .fc-event-bg {
background: 0;
}
#resource-freebusy-calendar .fc-event.status-busy,
#resource-freebusy-calendar .status-busy .fc-event-skin {
border-color: #e26569;
background-color: #e26569;
}
#resource-freebusy-calendar .fc-event.status-tentative,
#resource-freebusy-calendar .status-tentative .fc-event-skin {
border-color: #8383fc;
background: #8383fc;
}
#resource-freebusy-calendar .fc-event.status-outofoffice,
#resource-freebusy-calendar .status-outofoffice .fc-event-skin {
border-color: #fbaa68;
background: #fbaa68;
}
#resourcequicksearch {
padding: 4px;
background: #c7e3ef;
}
#resourcesearchbox {
width: 100%;
height: 26px;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#resourcequicksearch .iconbutton.searchoptions {
position: absolute;
top: 5px;
left: 6px;
width: 16px;
}
.searchbox .iconbutton.reset {
position: absolute;
top: 4px;
right: 1px;
}
/* fullcalendar style overrides */
.rcube-fc-content {
overflow: hidden;
border: 0;
border-radius: 4px;
box-shadow: 0 0 2px #999;
-o-box-shadow: 0 0 2px #999;
-webkit-box-shadow: 0 0 2px #999;
-moz-box-shadow: 0 0 2px #999;
}
.calendarmain .fc-content {
position: absolute !important;
top: 40px;
left: 0;
right: 0;
bottom: 0;
background: #fff;
}
.calendarmain.quickview-active .fc-content {
background-image: url('images/focusview.png');
background-position: center;
background-repeat: no-repeat;
}
#fish-eye-view .fc-content {
top: 2px;
bottom: 2px;
}
#quickview-calendar {
padding: 8px;
overflow: hidden;
}
.calendarmain .fc-button,
.calendarmain .fc-button.fc-state-default,
.calendarmain .fc-button.fc-state-hover {
background-color: #f5f5f5;
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
background-position: 0 0;
}
.calendarmain #calendar .fc-button,
.calendarmain #calendar .fc-button.fc-state-default,
.calendarmain #calendar .fc-button.fc-state-hover {
margin: 0 0 0 0;
height: 20px;
line-height: 20px;
color: #505050;
text-shadow: 0px 1px 1px #fff;
border: 1px solid #e6e6e6;
background: #d8d8d8;
background: -moz-linear-gradient(top, #d8d8d8 0%, #bababa 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#d8d8d8), color-stop(100%,#bababa));
background: -o-linear-gradient(top, #d8d8d8 0%, #bababa 100%);
background: -ms-linear-gradient(top, #d8d8d8 0%, #bababa 100%);
background: linear-gradient(top, #d8d8d8 0%, #bababa 100%);
box-shadow: 0 1px 1px 0 #999;
-o-box-shadow: 0 1px 1px 0 #999;
-webkit-box-shadow: 0 1px 1px 0 #999;
-moz-box-shadow: 0 1px 1px 0 #999;
text-decoration: none;
}
.calendarmain #calendar .fc-button.fc-state-disabled {
color: #999;
background: #d8d8d8;
}
.calendarmain .fc-button.fc-state-active,
.calendarmain .fc-button.fc-state-down,
.calendarmain #calendar .fc-button.fc-state-active,
.calendarmain #calendar .fc-button.fc-state-down {
color: #333;
background: #bababa;
background: -moz-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#bababa), color-stop(100%,#d8d8d8));
background: -o-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
background: -ms-linear-gradient(top, #bababa 0%, #d8d8d8 100%);
background: linear-gradient(top, #bababa 0%, #d8d8d8 100%);
}
.calendarmain #calendar .fc-header .fc-button {
margin-left: -1px;
margin-right: 0;
}
.calendarmain #calendar .fc-header-left .fc-button {
display: inline-block;
margin: 0;
text-align: center;
font-size: 10px;
color: #555;
min-width: 50px;
max-width: 75px;
height: 13px;
line-height: 1em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin: -7px 0 0 0;
padding: 28px 2px 0 2px;
text-shadow: 0px 1px 1px #EEE;
border: 0;
background: url(images/toolbar.png) center 100px no-repeat;
box-shadow: none;
-o-box-shadow: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
outline: none;
}
.calendarmain #calendar .fc-header-left .fc-button:focus {
color: #fff;
text-shadow: 0px 1px 1px #666;
background-color: rgba(30,150,192, 0.5);
border-radius: 3px;
}
.calendarmain #calendar .fc-header-left .fc-button.fc-state-active {
font-weight: bold;
color: #222;
text-shadow: none;
background-color: transparent;
}
.calendarmain #calendar .fc-header-left .fc-button-agendaDay {
background-position: center -120px;
}
.calendarmain #calendar .fc-header-left .fc-button-agendaDay.fc-state-active {
background-position: center -160px;
}
.calendarmain #calendar .fc-header-left .fc-button-agendaWeek {
background-position: center -200px;
}
.calendarmain #calendar .fc-header-left .fc-button-agendaWeek.fc-state-active {
background-position: center -240px;
}
.calendarmain #calendar .fc-header-left .fc-button-month {
background-position: center -280px;
}
.calendarmain #calendar .fc-header-left .fc-button-month.fc-state-active {
background-position: center -320px;
}
.calendarmain #calendar .fc-header-left .fc-button-table {
background-position: center -360px;
}
.calendarmain #calendar .fc-header-left .fc-button-table.fc-state-active {
background-position: center -400px;
}
.calendarmain #calendar .fc-header-right {
padding-right: 252px;
padding-top: 4px;
}
.calendarmain #calendar .fc-header-title {
padding-top: 5px;
}
.fc-event {
font-size: 1em !important;
}
.fc-event-hori.fc-type-freebusy,
.fc-event-vert.fc-type-freebusy {
opacity: 0.60;
/*
color: #fff !important;
background: rgba(80,80,80,0.85) !important;
background: -moz-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.9) 100%) !important;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(80,80,80,0.85)), color-stop(100%,rgba(48,48,48,0.9))) !important;
background: -webkit-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
background: -o-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
background: -ms-linear-gradient(top, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
background: linear-gradient(to bottom, rgba(80,80,80,0.85) 0%, rgba(48,48,48,0.85) 100%) !important;
border-color: #444 !important;
cursor: default !important;
*/
-moz-box-shadow: inset 0px 1px 0 0px #888;
-webkit-box-shadow: inset 0px 1px 0 0px #888;
-o-box-shadow: inset 0px 1px 0 0px #888;
box-shadow: inset 0px 1px 0 0px #888;
}
.fc-event-row.fc-type-freebusy td {
color: #999;
}
.fc-event-hori.fc-type-freebusy .fc-event-skin,
.fc-event-hori.fc-type-freebusy .fc-event-inner,
.fc-event-vert.fc-type-freebusy .fc-event-skin,
.fc-event-vert.fc-type-freebusy .fc-event-inner {
/*
background-color: transparent !important;
border-color: #444 !important;
color: #fff !important;
text-shadow: 0 1px 1px #000;
*/
}
.fc-event-hori.fc-type-freebusy .fc-event-title,
.fc-event-vert.fc-type-freebusy .fc-event-title {
position: absolute;
top: -5000px;
}
.fc-event-vert.fc-invitation-needs-action,
.fc-event-hori.fc-invitation-needs-action {
border: 1px dashed #5757c7 !important;
}
.fc-event-vert.fc-invitation-tentative,
.fc-event-hori.fc-invitation-tentative {
border: 1px dashed #eb8900 !important;
}
.fc-event-vert.fc-invitation-declined,
.fc-event-hori.fc-invitation-declined {
border: 1px dashed #c00 !important;
}
.fc-event-vert.fc-event-ns-other.fc-invitation-declined,
.fc-event-hori.fc-event-ns-other.fc-invitation-declined {
opacity: 0.7;
}
.fc-event-ns-other.fc-invitation-declined .fc-event-title {
text-decoration: line-through;
}
.fc-event-vert.fc-invitation-tentative .fc-event-head,
.fc-event-vert.fc-invitation-declined .fc-event-head,
.fc-event-vert.fc-invitation-needs-action .fc-event-head {
/* background-color: transparent !important; */
}
.fc-event-vert.fc-invitation-tentative .fc-event-bg {
background: url(data:image/gif;base64,R0lGODlhCAAIAPABAOuJAP///yH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAQAsAAAAAAgACAAAAg4Egmipx+ZaDPCtVPFNBQA7) 0 0 repeat #fff;
}
.fc-event-vert.fc-invitation-needs-action .fc-event-bg {
background: url(data:image/gif;base64,R0lGODlhCAAIAPABAFdXx////yH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAQAsAAAAAAgACAAAAg4Egmipx+ZaDPCtVPFNBQA7) 0 0 repeat #fff;
}
.fc-event-vert.fc-invitation-declined .fc-event-bg {
background: url(data:image/gif;base64,R0lGODlhCAAIAPABAMwAAP///yH/C1hNUCBEYXRhWE1QAT8AIfkEBQAAAQAsAAAAAAgACAAAAg4Egmipx+ZaDPCtVPFNBQA7) 0 0 repeat #fff;
}
.fc-view-table tr.fc-invitation-tentative td,
.fc-view-table tr.fc-invitation-declined td,
.fc-view-table tr.fc-invitation-needs-action td {
color: #888;
}
.fc-view-table tr.fc-invitation-tentative td.fc-event-title,
.fc-view-table tr.fc-invitation-declined td.fc-event-title,
.fc-view-table tr.fc-invitation-needs-action td.fc-event-title {
font-weight: normal;
}
#quickview-calendar .fc-view-table tr.fc-invitation-tentative td,
#quickview-calendar .fc-view-table tr.fc-invitation-declined td,
#quickview-calendar .fc-view-table tr.fc-invitation-needs-action td {
color: #333;
}
.calendarmain .fc-event:focus {
outline: 1px solid rgba(71,135,177, 0.4);
-webkit-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
-moz-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
-o-box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
box-shadow: 0 0 2px 3px rgba(71,135,177, 0.6);
}
.fc-event-title {
font-weight: bold;
}
.cal-event-status-cancelled .fc-event-title {
text-decoration: line-through;
}
.fc-event-hori .fc-event-title {
font-weight: normal;
white-space: nowrap;
}
.fc-event-hori .fc-event-time {
white-space: nowrap;
font-weight: normal !important;
font-size: 10px;
padding-right: 0.6em;
}
.fc-grid .fc-event-time {
font-weight: normal !important;
padding-right: 0.3em;
}
.calendarmain .fc-event-vert .fc-event-inner {
z-index: 0;
}
.fc-event-cateories {
font-style:italic;
}
div.fc-event-location {
font-size: 90%;
}
.fc-more-link {
color: #999;
padding-top: 1px;
cursor: pointer;
}
.fc-agenda-slots td div {
height: 22px;
}
.fc-sat, .fc-sun {
background-color: rgba(198,198,198, 0.08);
}
.calendarmain .fc-state-highlight {
background-color: rgba(233,198,14, 0.12);
}
.fc-widget-header {
background-color: #d6eaf3;
color: #004458;
text-shadow: 0px 1px 1px #fff;
}
.fc-view thead th.fc-widget-header {
padding: 8px 0;
color: #69939e;
}
.fc-day-number {
color: #578da5;
}
.fc-icon-alarms,
.fc-icon-sensitive,
.fc-icon-recurring {
display: inline-block;
width: 11px;
height: 11px;
background: url(images/eventicons.png) 0 0 no-repeat;
margin-left: 3px;
line-height: 10px;
}
.fc-icon-alarms {
background-position: 0 -13px;
}
.fc-icon-sensitive {
background-position: 0 -25px;
}
.fc-list-section .fc-event {
cursor: pointer;
}
.calendarmain .fc-view-table td.fc-list-header {
color: #004458;
font-size: 12px;
}
.calendarmain .fc-view-table tr.fc-event td {
border-color: #ddd;
padding: 4px 7px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.calendarmain .fc-view-table tr.fc-event td.fc-event-handle {
padding: 5px 0 2px 7px;
width: 12px;
}
.calendarmain .fc-view-table .fc-event-handle .fc-event-skin {
margin: 0;
padding: 0;
display: inline-block;
width: 10px;
height: 10px;
font-size: 6px;
border-radius: 8px;
}
.calendarmain .fc-view-table .fc-event-handle .fc-event-inner {
display: inline-block;
width: 10px;
height: 10px;
padding: 0;
margin: -1px;
font-size: 10px;
border-radius: 8px;
border: 1px solid rgba(0, 0, 0, 0.4);
-webkit-box-shadow: inset 0px 0 1px 1px rgba(0, 0, 0, 0.3);
-moz-box-shadow: inset 0px 0 1px 1px rgba(0, 0, 0, 0.3);
box-shadow: inset 0px 0 1px 1px rgba(0, 0, 0, 0.3);
}
.calendarmain .fc-view-table col.fc-event-location {
width: 25%;
}
.fc-view-table table.fc-list-smart {
/* table-layout: auto; */
}
.fc-listappend {
text-align: center;
margin: 1em 0;
}
.fc-listappend .message {
padding: 0.5em;
margin-bottom: 0.5em;
font-size: 150%;
color: #999;
}
.fc-listappend .formlinks a {
font-size: 12px;
padding: 0 0.3em;
}
.fc-event-temp {
opacity: 0.4;
filter: alpha(opacity=40); /* IE8 */
}
/* Settings section */
fieldset #calendarcategories div {
margin-bottom: 0.3em;
}
/* Invitation UI in mail */
.messagelist tbody .attachment span.ical {
display: inline-block;
vertical-align: middle;
height: 18px;
width: 20px;
padding: 0;
background: url(images/ical-attachment.png) 2px 1px no-repeat;
}
ul.toolbarmenu li a.calendarlink span.calendar,
#attachmentmenu li a.calendarlink span.calendar {
background-position: 0px -2197px;
}
div.calendar-invitebox {
min-height: 20px;
margin: 5px 8px;
padding: 3px 6px 6px 34px;
border: 1px solid #ffdf0e;
background: url(images/calendar.png) 6px 5px no-repeat #fef893;
}
div.calendar-invitebox td.ititle {
font-weight: bold;
padding-right: 0.5em;
}
div.calendar-invitebox td {
padding: 2px;
}
div.calendar-invitebox td.label {
color: #666;
padding-right: 1em;
}
div.calendar-invitebox td.sensitivity {
color: #d31400;
font-weight: bold;
}
div.calendar-invitebox td.recurrence-id {
text-transform: uppercase;
font-style: italic;
}
div.calendar-invitebox td em {
font-weight: bold;
}
#event-rsvp .rsvp-buttons,
div.calendar-invitebox .itip-buttons div {
margin-top: 0.5em;
}
#event-rsvp input.button,
div.calendar-invitebox input.button {
font-weight: bold;
margin-right: 0.5em;
}
div.calendar-invitebox input.button.preview {
margin-left: 1em;
margin-right: 0;
}
div.calendar-invitebox .folder-select {
font-weight: 10px;
margin-left: 1em;
white-space: nowrap;
}
div.calendar-invitebox .rsvp-status {
padding-left: 2px;
}
div.calendar-invitebox .rsvp-status.loading {
color: #666;
padding: 1px 0 2px 24px;
background: url(images/loading_blue.gif) top left no-repeat;
}
div.calendar-invitebox .rsvp-status.hint {
color: #666;
text-shadow: none;
font-style: italic;
}
#event-partstat .changersvp,
div.calendar-invitebox .rsvp-status.declined,
div.calendar-invitebox .rsvp-status.tentative,
div.calendar-invitebox .rsvp-status.accepted,
div.calendar-invitebox .rsvp-status.delegated,
div.calendar-invitebox .rsvp-status.needs-action {
padding: 0 0 1px 22px;
background: url(images/attendee-status.png) 2px -20px no-repeat;
}
#event-partstat .changersvp.declined,
div.calendar-invitebox .rsvp-status.declined {
background-position: 2px -40px;
}
#event-partstat .changersvp.tentative,
div.calendar-invitebox .rsvp-status.tentative {
background-position: 2px -60px;
}
#event-partstat .changersvp.delegated,
div.calendar-invitebox .rsvp-status.delegated {
background-position: 2px -180px;
}
#event-partstat .changersvp.needs-action,
div.calendar-invitebox .rsvp-status.needs-action {
background-position: 2px 0;
}
div.calendar-invitebox .calendar-agenda-preview {
display: none;
border-top: 1px solid #dfdfdf;
margin-top: 1em;
padding-top: 0.6em;
}
div.calendar-invitebox .calendar-agenda-preview h3.preview-title {
margin: 0 0 0.5em 0;
font-size: 12px;
color: #333;
}
div.calendar-invitebox .calendar-agenda-preview .event-row {
color: #777;
padding: 2px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
div.calendar-invitebox .calendar-agenda-preview .event-row.current {
color: #333;
font-weight: bold;
}
div.calendar-invitebox .calendar-agenda-preview .event-row.no-event {
font-style: italic;
}
div.calendar-invitebox .calendar-agenda-preview .event-date {
display: inline-block;
min-width: 8em;
margin-right: 1em;
white-space: nowrap;
}
/* iTIP attend reply page */
.calendaritipattend .centerbox {
width: 40em;
min-height: 7em;
margin: 80px auto 0 auto;
padding: 10px 10px 10px 90px;
background: url(images/invitation.png) 10px 10px no-repeat #fff;
}
.calendaritipattend #message {
width: 46em;
margin: 0 auto;
padding: 10px;
}
.calendaritipattend .calendar-invitebox {
background: none;
padding-left: 0;
border: 0;
margin: 0 0 2em 0;
}
.calendaritipattend .calendar-invitebox .rsvp-status {
margin-top: 2.5em;
font-size: 110%;
font-weight: bold;
}
.calendaritipattend .calendar-invitebox td.title,
.calendaritipattend .calendar-invitebox td.ititle {
font-size: 120%;
}
.calendaritipattend .itip-reply-controls .noreply-toggle,
.calendaritipattend .itip-reply-controls #noreply-event-rsvp {
display: none;
}
.calendaritipattend .itip-reply-controls a.reply-comment-toggle {
margin-left: 2px;
}
diff --git a/plugins/calendar/skins/larry/templates/calendar.html b/plugins/calendar/skins/larry/templates/calendar.html
index b9ea905c..8d8e0105 100644
--- a/plugins/calendar/skins/larry/templates/calendar.html
+++ b/plugins/calendar/skins/larry/templates/calendar.html
@@ -1,532 +1,532 @@
<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>
<roundcube:if condition="env:extwin" /><body class="calendarmain extwin"><roundcube:else /><body class="calendarmain"><roundcube:endif />
<roundcube:include file="/includes/header.html" />
<h1 class="voice"><roundcube:label name="calendar.calendar" /></h1>
<div id="mainscreen">
<div id="calendarsidebar">
<h2 id="aria-label-toolbar" class="voice"><roundcube:label name="arialabeltoolbar" /></h2>
<div id="calendartoolbar" class="toolbar" role="toolbar" aria-labelledby="aria-label-toolbar">
<roundcube:button command="addevent" type="link" class="button addevent disabled" classAct="button addevent" classSel="button addevent pressed" label="calendar.new_event" title="calendar.new_event" />
<roundcube:button command="print" type="link" class="button print disabled" classAct="button print" classSel="button print pressed" label="calendar.print" title="calendar.printtitle" />
<roundcube:button command="events-import" type="link" class="button import disabled" classAct="button import" classSel="button import pressed" label="import" title="calendar.importevents" />
<roundcube:button command="export" type="link" class="button export disabled" classAct="button export" classSel="button export pressed" label="calendar.export" title="calendar.exporttitle" />
<roundcube:container name="toolbar" id="calendartoolbar" />
</div>
<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 withfooter">
<roundcube:object name="plugin.calendar_list" id="calendarslist" class="treelist listing" />
</div>
<div class="boxfooter">
<roundcube:button command="calendar-create" type="link" title="calendar.createcalendar" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button name="calendaroptionslink" id="calendaroptionsmenulink" type="link" title="moreactions" class="listbutton groupactions" onclick="return UI.toggle_popup('calendaroptionsmenu', event, { above:true })" innerClass="inner" label="calendar.calendaractions" aria-haspopup="true" aria-expanded="false" aria-owns="calendaroptionsmenu-menu" />
</div>
</div>
</div>
<div id="quicksearchbar" class="searchbox" role="search" aria-labelledby="aria-label-searchform">
<h2 id="aria-label-searchform" class="voice"><roundcube:label name="calendar.arialabelsearchform" /></h2>
<label for="quicksearchbox" class="voice"><roundcube:label name="calendar.arialabelquicksearchbox" /></label>
<roundcube:object name="plugin.searchform" id="quicksearchbox" />
<a id="searchmenulink" class="iconbutton searchoptions" tabindex="-1"> </a>
<roundcube:button command="reset-search" id="searchreset" class="iconbutton reset" title="resetsearch" label="resetsearch" />
</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:object name="message" id="messagestack" />
<div id="calendaroptionsmenu" class="popupmenu" aria-hidden="true">
<h3 id="aria-label-calendaroptions" class="voice"><roundcube:label name="calendar.calendaractions" /></h3>
<ul id="calendaroptionsmenu-menu" class="toolbarmenu" role="menu" aria-labelledby="aria-label-calendaroptions">
<li role="menuitem"><roundcube:button command="calendar-edit" label="calendar.edit" classAct="active" /></li>
<li role="menuitem"><roundcube:button command="calendar-delete" label="delete" classAct="active" /></li>
<roundcube:if condition="env:calendar_driver == 'kolab'" />
<li role="menuitem"><roundcube:button command="calendar-remove" label="calendar.removelist" classAct="active" /></li>
<roundcube:endif />
<li role="menuitem"><roundcube:button command="calendar-showurl" label="calendar.showurl" classAct="active" /></li>
<roundcube:if condition="env:calendar_driver == 'kolab'" />
<li role="menuitem"><roundcube:button command="folders" task="settings" type="link" label="managefolders" classAct="active" /></li>
<roundcube:endif />
</ul>
</div>
<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-links">
<label><roundcube:label name="calendar.links" /></label>
<span class="event-text"></span>
<br style="clear:left">
</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>
<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 />
</ul>
</div>
<div id="eventdiff" class="uidialog eventdialog" aria-hidden="true">
<h1 class="event-title">Event Title</h1>
<h1 class="event-title-new event-text-new"></h1>
<div class="event-section event-date"></div>
<div class="event-section event-location">
<h5 class="label"><roundcube:label name="calendar.location" /></h5>
<div class="event-text-old"></div>
<div class="event-text-new"></div>
</div>
<div class="event-section event-description">
<h5 class="label"><roundcube:label name="calendar.description" /></h5>
<div class="event-text-diff" style="white-space:pre-wrap"></div>
<div class="event-text-old"></div>
<div class="event-text-new"></div>
</div>
<div class="event-section event-url">
<h5 class="label"><roundcube:label name="calendar.url" /></h5>
<div class="event-text-old"></div>
<div class="event-text-new"></div>
</div>
<div class="event-section event-recurrence">
<h5 class="label"><roundcube:label name="calendar.repeat" /></h5>
<div class="event-text-old"></div>
<div class="event-text-new"></div>
</div>
<div class="event-section event-alarms">
<h5 class="label"><roundcube:label name="calendar.alarms" /><span class="index"></span></h5>
<div class="event-text-old"></div>
<div class="event-text-new"></div>
</div>
<div class="event-line event-start">
<label><roundcube:label name="calendar.start" /></label>
<span class="event-text-old"></span> &#8674;
<span class="event-text-new"></span>
</div>
<div class="event-line event-end">
<label><roundcube:label name="calendar.end" /></label>
<span class="event-text-old"></span> &#8674;
<span class="event-text-new"></span>
</div>
<div class="event-line event-attendees">
<label><roundcube:label name="calendar.tabattendees" /><span class="index"></span></label>
<span class="event-text-old"></span> &#8674;
<span class="event-text-new"></span>
</div>
<div class="event-line event-calendar">
<label><roundcube:label name="calendar.calendar" /></label>
<span class="event-text-old"></span> &#8674;
<span class="event-text-new"></span>
</div>
<div class="event-line event-categories">
<label><roundcube:label name="calendar.category" /></label>
<span class="event-text-old"></span> &#8674;
<span class="event-text-new"></span>
</div>
<div class="event-line event-status">
<label><roundcube:label name="calendar.status" /></label>
<span class="event-text-old"></span> &#8674;
<span class="event-text-new"></span>
</div>
<div class="event-line event-free_busy">
<label><roundcube:label name="calendar.freebusy" /></label>
<span class="event-text-old"></span> &#8674;
<span class="event-text-new"></span>
</div>
<div class="event-line event-priority">
<label><roundcube:label name="calendar.priority" /></label>
<span class="event-text-old"></span> &#8674;
<span class="event-text-new"></span>
</div>
<div class="event-line event-sensitivity">
<label><roundcube:label name="calendar.sensitivity" /></label>
<span class="event-text-old"></span> &#8674;
<span class="event-text-new"></span>
</div>
<div class="event-section event-attachments">
<label><roundcube:label name="attachments" /><span class="index"></span></label>
<div class="event-text-old"></div>
<div class="event-text-new"></div>
</div>
</div>
<roundcube:include file="/templates/eventedit.html" />
<div id="eventresourcesdialog" class="uidialog" aria-hidden="true">
<div id="resource-dialog-left">
<div id="resource-selection" class="uibox listbox" role="navigation" aria-labelledby="aria-label-resourceselection">
<h2 class="voice" id="aria-label-resourceselection"><roundcube:label name="calendar.arialabelresourceselection" /></h2>
<div id="resourcequicksearch">
<div class="searchbox" role="search" aria-labelledby="aria-label-resourcesearchform" aria-controls="resources-list">
<h3 id="aria-label-resourcesearchform" class="voice"><roundcube:label name="calendar.arialabelresourcesearchform" /></h3>
<label for="resourcesearchbox" class="voice"><roundcube:label name="calendar.searchterms" /></label>
<roundcube:object name="plugin.resources_searchform" id="resourcesearchbox" />
<a id="resourcesearchmenulink" class="iconbutton searchoptions"> </a>
<roundcube:button command="reset-resource-search" id="resourcesearchreset" class="iconbutton reset" title="resetsearch" label="resetsearch" />
</div>
</div>
<div class="scroller">
<roundcube:object name="plugin.resources_list" id="resources-list" class="listing treelist" />
</div>
</div>
</div>
<div id="resource-dialog-right">
<div id="resource-info" class="uibox contentbox" role="region" aria-labelledby="aria-label-resourcedetails">
<h2 class="boxtitle" id="aria-label-resourcedetails"><roundcube:label name="calendar.resourcedetails" /></h2>
<div class="scroller">
<roundcube:object name="plugin.resource_info" id="resource-details" class="propform" aria-live="polite" aria-relevant="text" aria-atomic="true" />
</div>
</div>
<div id="resource-availability" class="uibox contentbox" role="region" aria-labelledby="aria-label-resourceavailability">
<h2 class="boxtitle" id="aria-label-resourceavailability"><roundcube:label name="calendar.resourceavailability" /></h2>
<roundcube:object name="plugin.resource_calendar" id="resource-freebusy-calendar" />
<div class="boxpagenav">
<roundcube:button name="resource-cal-prev" id="resource-calendar-prev" type="link" class="icon prevpage" title="calendar.prevslot" label="calendar.prevweek" />
<roundcube:button name="resource-cal-next" id="resource-calendar-next" type="link" class="icon nextpage" title="calendar.nextslot" label="calendar.nextweek" />
</div>
</div>
</div>
</div>
<div id="eventfreebusy" class="uidialog" aria-hidden="true">
<roundcube:object name="plugin.attendees_freebusy_table" id="attendees-freebusy-table" cellpadding="0" />
<div class="schedule-options">
&nbsp;
<div class="schedule-buttons">
<button id="shedule-freebusy-prev" title="<roundcube:label name='previouspage' />">&#9668;</button><button id="shedule-freebusy-next" title="<roundcube:label name='nextpage' />">&#9658;</button>
</div>
</div>
<div style="float:left; width:28em">
<div class="form-section">
<label for="schedule-startdate"><roundcube:label name="calendar.start" /></label>
<input type="text" name="startdate" size="11" id="schedule-startdate" disabled="true" /> &nbsp;
<input type="text" name="starttime" size="6" id="schedule-starttime" disabled="true" />
</div>
<div class="form-section">
<label for="schedule-enddate"><roundcube:label name="calendar.end" /></label>
<input type="text" name="enddate" size="11" id="schedule-enddate" disabled="true" /> &nbsp;
<input type="text" name="endtime" size="6" id="schedule-endtime" disabled="true" />
</div>
</div>
<div style="float:left">
<div class="schedule-find-buttons">
<button id="shedule-find-prev">&#9668; <roundcube:label name="calendar.prevslot" /></button>
<button id="shedule-find-next"><roundcube:label name="calendar.nextslot" /> &#9658;</button>
</div>
<div class="schedule-options">
<label><input type="checkbox" id="schedule-freebusy-workinghours" value="1" /><roundcube:label name="calendar.onlyworkinghours" /></label>
</div>
</div>
<br style="clear:both;" />
<roundcube:include file="/templates/freebusylegend.html" />
<div class="attendees-list">
<span class="attendee organizer"><roundcube:label name="calendar.roleorganizer" /></span>
<span class="attendee req-participant"><roundcube:label name="calendar.rolerequired" /></span>
<span class="attendee opt-participant"><roundcube:label name="calendar.roleoptional" /></span>
<span class="attendee non-participant"><roundcube:label name="calendar.rolenonparticipant" /></span>
<span class="attendee chair"><roundcube:label name="calendar.rolechair" /></span>
</div>
</div>
<div id="eventhistory" class="uidialog" aria-hidden="true">
- <roundcube:object name="plugin.event_changelog_table" id="event-changelog-table" class="records-table changelog-table" />
+ <roundcube:object name="plugin.object_changelog_table" id="event-changelog-table" class="records-table changelog-table" domain="calendar" />
<div class="compare-button"><input type="button" class="button" value="↳ <roundcube:label name='calendar.compare' />" /></div>
</div>
<div id="calendarform" class="uidialog" aria-hidden="true">
<roundcube:label name="loading" />
</div>
<div id="eventsimport" class="uidialog">
<roundcube:object name="plugin.events_import_form" id="events-import-form" uploadFieldSize="30" />
</div>
<div id="eventsexport" class="uidialog">
<roundcube:object name="plugin.events_export_form" id="events-export-form" />
</div>
<div id="calendarurlbox" class="uidialog">
<p><roundcube:label name="calendar.showurldescription" /></p>
<textarea id="calfeedurl" rows="2" readonly="readonly"></textarea>
<div id="calendarcaldavurl" style="display:none">
<p><roundcube:label name="calendar.caldavurldescription" html="yes" /></p>
<textarea id="caldavurl" rows="2" readonly="readonly"></textarea>
</div>
</div>
<roundcube:object name="plugin.calendar_css" />
<script type="text/javascript">
// UI startup
var UI = new rcube_mail_ui();
$(document).ready(function(e){
UI.init();
new calendarview_splitter({ id:'calsidebarsplitter', p1:'#calendarsidebar', p2:'#calendar',
orientation:'v', relative:true, start:280, min:260, size:12, offset:0 });
new rcube_splitter({ id:'calresourceviewsplitter', p1:'#resource-dialog-left', p2:'#resource-dialog-right',
orientation:'v', relative:true, start:380, min:220, size:10, offset:-3 }).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;
if (!rcube_event.is_keyboard(e))
$(this).blur();
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;
});
});
/**
* Extended rcube_splitter class that entirely collapses the calendar sidebar
*/
function calendarview_splitter(p)
{
this.collapsed = false;
this.dragging = false;
this.threshold = 80;
this.lastpos = -1;
this._lastpos = -1;
this._min = p.min;
var me = this;
p.callback = function(e){
if (me.lastpos != me._lastpos) {
me.dragging = true;
setTimeout(function(){ me.dragging = false; }, 50);
me._lastpos = me.lastpos;
}
};
// extend base class
p.min = 20;
rcube_splitter.call(this, p);
// @override
this.resize = function()
{
if (this.pos < this.threshold) {
if (!this.collapsed)
this.collapse();
}
else if (this.pos < this._min && this.pos > this._min / 2) {
if (this.collapsed)
this.expand();
}
else if (this.pos >= this._min) {
this.p1.css('width', Math.floor(this.pos - this.p1pos.left - this.halfsize) + 'px');
this.p2.css('left', Math.ceil(this.pos + this.halfsize) + 'px');
this.handle.css('left', Math.round(this.pos - this.halfsize + this.offset + 3)+'px');
if (bw.ie) {
var new_width = parseInt(this.parent.outerWidth(), 10) - parseInt(this.p2.css('left'), 10) ;
this.p2.css('width', (new_width > 0 ? new_width : 0) + 'px');
}
this.p2.resize();
this.p1.resize();
this.lastpos = this.pos;
if (this._lastpos == -1)
this._lastpos = this.pos;
// also resize iframe covers
if (this.drag_active) {
$('iframe').each(function(i, elem) {
var pos = $(this).offset();
$('#iframe-splitter-fix-'+i).css({ top: pos.top+'px', left: pos.left+'px', width:elem.offsetWidth+'px', height: elem.offsetHeight+'px' });
});
}
if (typeof this.render == 'function')
this.render(this);
}
}
this.collapse = function(animated)
{
var me = this, time = 250;
if (animated) {
this.p1.animate({ left:'0px' }, time, function(){ $(this).hide(); });
this.p2.animate({ left:this.p.size + 'px' }, time, function(){ $(this).resize(); });
this.handle.animate({ left:'3px'}, time, function(){ $(this).addClass('sidebarclosed') });
}
else {
this.p1.css('left', 0).hide();
this.p2.css('left', this.p.size + 'px');
this.handle.css('left', '3px').addClass('sidebarclosed');
this.p2.resize();
}
// stop dragging
if (this.drag_active) {
this.drag_active = false;
$(document).unbind('.'+this.id);
$('div.iframe-splitter-fix').remove();
}
this.pos = 10;
this.collapsed = true;
this.set_cookie();
}
this.expand = function()
{
var me = this, time = 250;
this.handle.removeClass('sidebarclosed');
this.pos = this.lastpos > 0 ? this.lastpos : this._min;
this.p1pos.left = 10;
this.p1.show().animate({ left:'10px', width:(this.pos - this.p1pos.left - this.halfsize) + 'px' }, time);
this.p2.animate({ left:(this.pos + this.halfsize) + 'px' }, time, function(){ me.resize(); });
this.handle.animate({ left:(this.pos - this.halfsize + this.offset + 3) + 'px' }, time);
this.collapsed = false;
this.set_cookie();
}
this.init();
var me = this;
this.handle.bind('click', function(e){
if (!me.collapsed && !me.dragging)
me.collapse(true);
else if (!me.dragging)
me.expand();
});
}
</script>
</body>
</html>
diff --git a/plugins/libkolab/js/audittrail.js b/plugins/libkolab/js/audittrail.js
index 5c9eec02..0fe7bcb8 100644
--- a/plugins/libkolab/js/audittrail.js
+++ b/plugins/libkolab/js/audittrail.js
@@ -1,203 +1,203 @@
/**
* Kolab groupware audit trail utilities
*
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* @licstart The following is the entire license notice for the
* JavaScript code in this file.
*
* Copyright (C) 2015, 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
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @licend The above is the entire license notice
* for the JavaScript code in this file.
*/
var libkolab_audittrail = {}
libkolab_audittrail.quote_html = function(str)
{
return String(str).replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
};
// show object changelog in a dialog
libkolab_audittrail.object_history_dialog = function(p)
{
// render dialog
var $dialog = $(p.container);
// close show dialog first
if ($dialog.is(':ui-dialog'))
$dialog.dialog('close');
var buttons = {};
- buttons[rcmail.gettext('close', 'calendar')] = function() {
+ buttons[rcmail.gettext('close')] = function() {
$dialog.dialog('close');
};
// hide and reset changelog table
$dialog.find('div.notfound-message').remove();
$dialog.find('.changelog-table').show().children('tbody')
.html('<tr><td colspan="6"><span class="loading">' + rcmail.gettext('loading') + '</span></td></tr>');
// open jquery UI dialog
$dialog.dialog({
modal: false,
resizable: true,
closeOnEscape: true,
title: p.title,
open: function() {
$dialog.attr('aria-hidden', 'false');
setTimeout(function(){
$dialog.parent().find('.ui-button:not(.ui-dialog-titlebar-close)').first().focus();
}, 5);
},
close: function() {
$dialog.dialog('destroy').attr('aria-hidden', 'true').hide();
},
buttons: buttons,
minWidth: 450,
width: 650,
height: 350,
minHeight: 200,
})
.show().children('.compare-button').hide();
// initialize event handlers for history dialog UI elements
if (!$dialog.data('initialized')) {
// compare button
$dialog.find('.compare-button input').click(function(e) {
var rev1 = $dialog.find('.changelog-table input.diff-rev1:checked').val(),
rev2 = $dialog.find('.changelog-table input.diff-rev2:checked').val();
if (rev1 && rev2 && rev1 != rev2) {
// swap revisions if the user got it wrong
if (rev1 > rev2) {
var tmp = rev2;
rev2 = rev1;
rev1 = tmp;
}
if (p.comparefunc) {
p.comparefunc(rev1, rev2);
}
}
else {
alert('Invalid selection!')
}
if (!rcube_event.is_keyboard(e) && this.blur) {
this.blur();
}
return false;
});
// delegate handlers for list actions
$dialog.find('.changelog-table tbody').on('click', 'td.actions a', function(e) {
var link = $(this),
action = link.hasClass('restore') ? 'restore' : 'show',
event = $('#eventhistory').data('event'),
rev = link.attr('data-rev');
// ignore clicks on first row (current revision)
if (link.closest('tr').hasClass('first')) {
return false;
}
// let the user confirm the restore action
if (action == 'restore' && !confirm(rcmail.gettext('revisionrestoreconfirm', p.module).replace('$rev', rev))) {
return false;
}
if (p.listfunc) {
p.listfunc(action, rev);
}
if (!rcube_event.is_keyboard(e) && this.blur) {
this.blur();
}
return false;
})
.on('click', 'input.diff-rev1', function(e) {
if (!this.checked) return true;
var rev1 = this.value, selection_valid = false;
$dialog.find('.changelog-table input.diff-rev2').each(function(i, elem) {
$(elem).prop('disabled', elem.value <= rev1);
if (elem.checked && elem.value > rev1) {
selection_valid = true;
}
});
if (!selection_valid) {
$dialog.find('.changelog-table input.diff-rev2:not([disabled])').last().prop('checked', true);
}
});
$dialog.addClass('changelog-dialog').data('initialized', true);
}
return $dialog;
};
// callback from server with changelog data
libkolab_audittrail.render_changelog = function(data, object, folder)
{
var Q = libkolab_audittrail.quote_html;
var $dialog = $('.changelog-dialog')
if (data === false || !data.length) {
return false;
}
var i, change, accessible, op_append,
first = data.length - 1, last = 0,
is_writeable = !!folder.editable,
op_labels = { APPEND: 'actionappend', MOVE: 'actionmove', DELETE: 'actiondelete' },
actions = '<a href="#show" class="iconbutton preview" title="'+ rcmail.gettext('showrevision',data.module) +'" data-rev="{rev}" /> ' +
(is_writeable ? '<a href="#restore" class="iconbutton restore" title="'+ rcmail.gettext('restore',data.module) + '" data-rev="{rev}" />' : ''),
tbody = $dialog.find('.changelog-table tbody').html('');
for (i=first; i >= 0; i--) {
change = data[i];
accessible = change.date && change.user;
if (change.op == 'MOVE' && change.mailbox) {
op_append = ' ⇢ ' + change.mailbox;
}
else {
op_append = '';
}
$('<tr class="' + (i == first ? 'first' : (i == last ? 'last' : '')) + (accessible ? '' : 'undisclosed') + '">')
.append('<td class="diff">' + (accessible && change.op != 'DELETE' ?
'<input type="radio" name="rev1" class="diff-rev1" value="' + change.rev + '" title="" '+ (i == last ? 'checked="checked"' : '') +' /> '+
'<input type="radio" name="rev2" class="diff-rev2" value="' + change.rev + '" title="" '+ (i == first ? 'checked="checked"' : '') +' /></td>'
: ''))
.append('<td class="revision">' + Q(i+1) + '</td>')
.append('<td class="date">' + Q(change.date || '') + '</td>')
.append('<td class="user">' + Q(change.user || 'undisclosed') + '</td>')
- .append('<td class="operation" title="' + op_append + '">' + Q(rcmail.gettext(op_labels[change.op] || '', 'calendar') + (op_append ? ' ...' : '')) + '</td>')
+ .append('<td class="operation" title="' + op_append + '">' + Q(rcmail.gettext(op_labels[change.op] || '', data.module) + (op_append ? ' ...' : '')) + '</td>')
.append('<td class="actions">' + (accessible && change.op != 'DELETE' ? actions.replace(/\{rev\}/g, change.rev) : '') + '</td>')
.appendTo(tbody);
}
if (first > 0) {
$dialog.find('.compare-button').fadeIn(200);
$dialog.find('.changelog-table tr.last input.diff-rev1').click();
}
return $dialog;
};
\ No newline at end of file
diff --git a/plugins/libkolab/libkolab.php b/plugins/libkolab/libkolab.php
index f1c2c878..4aa1ce50 100644
--- a/plugins/libkolab/libkolab.php
+++ b/plugins/libkolab/libkolab.php
@@ -1,153 +1,171 @@
<?php
/**
* Kolab core library
*
* Plugin to setup a basic environment for the interaction with a Kolab server.
* Other Kolab-related plugins will depend on it and can use the library classes
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2012, 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
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class libkolab extends rcube_plugin
{
static $http_requests = array();
/**
* Required startup method of a Roundcube plugin
*/
public function init()
{
// load local config
$this->load_config();
// extend include path to load bundled lib classes
$include_path = $this->home . '/lib' . PATH_SEPARATOR . ini_get('include_path');
set_include_path($include_path);
$this->add_hook('storage_init', array($this, 'storage_init'));
$this->add_hook('user_delete', array('kolab_storage', 'delete_user_folders'));
$rcmail = rcube::get_instance();
try {
kolab_format::$timezone = new DateTimeZone($rcmail->config->get('timezone', 'GMT'));
}
catch (Exception $e) {
rcube::raise_error($e, true);
kolab_format::$timezone = new DateTimeZone('GMT');
}
}
/**
* Hook into IMAP FETCH HEADER.FIELDS command and request Kolab-specific headers
*/
function storage_init($p)
{
$p['fetch_headers'] = trim($p['fetch_headers'] .' X-KOLAB-TYPE X-KOLAB-MIME-VERSION');
return $p;
}
/**
* Wrapper function to load and initalize the HTTP_Request2 Object
*
* @param string|Net_Url2 Request URL
* @param string Request method ('OPTIONS','GET','HEAD','POST','PUT','DELETE','TRACE','CONNECT')
* @param array Configuration for this Request instance, that will be merged
* with default configuration
*
* @return HTTP_Request2 Request object
*/
public static function http_request($url = '', $method = 'GET', $config = array())
{
$rcube = rcube::get_instance();
$http_config = (array) $rcube->config->get('kolab_http_request');
// deprecated configuration options
if (empty($http_config)) {
foreach (array('ssl_verify_peer', 'ssl_verify_host') as $option) {
$value = $rcube->config->get('kolab_' . $option, true);
if (is_bool($value)) {
$http_config[$option] = $value;
}
}
}
if (!empty($config)) {
$http_config = array_merge($http_config, $config);
}
// force CURL adapter, this allows to handle correctly
// compressed responses with SplObserver registered (kolab_files) (#4507)
$http_config['adapter'] = 'HTTP_Request2_Adapter_Curl';
$key = md5(serialize($http_config));
if (!($request = self::$http_requests[$key])) {
// load HTTP_Request2
require_once 'HTTP/Request2.php';
try {
$request = new HTTP_Request2();
$request->setConfig($http_config);
}
catch (Exception $e) {
rcube::raise_error($e, true, true);
}
// proxy User-Agent string
$request->setHeader('user-agent', $_SERVER['HTTP_USER_AGENT']);
self::$http_requests[$key] = $request;
}
// cleanup
try {
$request->setBody('');
$request->setUrl($url);
$request->setMethod($method);
}
catch (Exception $e) {
rcube::raise_error($e, true, true);
}
return $request;
}
+ /**
+ * Table oultine for object changelog display
+ */
+ public static function object_changelog_table($attrib = array())
+ {
+ $rcube = rcube::get_instance();
+
+ $table = new html_table(array('cols' => 5, 'border' => 0, 'cellspacing' => 0));
+ $table->add_header('diff', '');
+ $table->add_header('revision', $rcube->gettext('revision', $attrib['domain']));
+ $table->add_header('date', $rcube->gettext('date', $attrib['domain']));
+ $table->add_header('user', $rcube->gettext('user', $attrib['domain']));
+ $table->add_header('operation', $rcube->gettext('operation', $attrib['domain']));
+ $table->add_header('actions', '&nbsp;');
+
+ return $table->show($attrib);
+ }
+
/**
* Wrapper function for generating a html diff using the FineDiff class by Raymond Hill
*/
public static function html_diff($from, $to)
{
include_once __dir__ . '/vendor/finediff.php';
$diff = new FineDiff($from, $to, FineDiff::$wordGranularity);
return $diff->renderDiffToHTML();
}
/**
* Return a date() format string to render identifiers for recurrence instances
*
* @param array Hash array with event properties
* @return string Format string
*/
public static function recurrence_id_format($event)
{
return $event['allday'] ? 'Ymd' : 'Ymd\THis';
}
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jul 8, 9:30 PM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1049560
Default Alt Text
(710 KB)

Event Timeline