diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php index 85357dd6..8fe4107f 100644 --- a/plugins/calendar/lib/calendar_ui.php +++ b/plugins/calendar/lib/calendar_ui.php @@ -1,849 +1,850 @@ * @author Thomas Bruederli * * Copyright (C) 2010, Lazlo Westerhof * Copyright (C) 2014, Kolab Systems AG * * 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 . */ 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', 'type' => 'link' ), '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.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_recurrence_sync', array($this, 'edit_recurrence_sync')); $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.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 kolab_attachments_handler::ui(); } /** * 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'); $this->cal->api->include_script('libkolab/libkolab.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, $attrib); } return html::tag('style', array('type' => 'text/css'), $css); } /** * */ public function calendar_css_classes($id, $prop, $mode, $attrib) { $color = $folder_color = $prop['color']; // replace white with skin-defined color if (!empty($attrib['folder-fallback-color']) && preg_match('/^f+$/i', $folder_color)) { $folder_color = $attrib['folder-fallback-color']; } $class = 'cal-' . asciiwords($id, true); $css = str_replace('$class', $class, $attrib['folder-class']) ?: "li .$class"; $css .= ", #eventshow .$class { color: #$folder_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 (!$prop['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('source', rcube_utils::get_input_value('source', rcube_utils::INPUT_GET)); $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
    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, RCUBE_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::a(array('class' => 'calname', 'id' => $label_id, 'title' => $title, 'href' => '#'), rcube::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')), ' ') ) ); } 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', 'class' => 'form-control')); $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', 'class' => 'form-control')); $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', ' '); $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('status-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); } /** * Render HTML for attendee notification warning */ 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'))); } /** * Render HTML for recurrence option to align start date with the recurrence rule */ function edit_recurrence_sync($attrib = array()) { $checkbox = new html_checkbox(array('name' => '_start_sync', 'value' => 1)); return html::div($attrib, html::label(null, $checkbox->show(1) . ' ' . $this->cal->gettext('eventstartsync'))); } /** * 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 = $this->rc->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', $this->rc->gettext(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 form-group row', html::label(array('for' => 'event-export-calendar', 'class' => 'col-sm-4 col-form-label'), $this->cal->gettext('calendar')) . html::div('col-sm-8', $this->calendar_select(array('name' => 'calendar', 'id' => 'event-export-calendar', 'class' => 'form-control')))); $select = new html_select(array('name' => 'range', 'id' => 'event-export-range', 'class' => 'form-control')); $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 form-group row', html::label(array('for' => 'event-export-range', 'class' => 'col-sm-4 col-form-label'), $this->cal->gettext('exportrange')) . html::div('col-sm-8', $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 form-group row', html::label(array('for' => 'event-export-attachments', 'class' => 'col-sm-4 col-form-label'), $this->cal->gettext('exportattachments')) . html::div('col-sm-8', $checkbox->show(1))); $this->rc->output->add_gui_object('exportform', $attrib['id']); return html::tag('form', $attrib + array( 'action' => $this->rc->url(array('task' => 'calendar', 'action' => 'export_events')), 'method' => "post", 'id' => $attrib['id'] ), $html ); } /** * Handler for calendar form template. * The form content could be overriden by the driver */ function calendar_editform($action, $calendar = array()) { $this->action = $action; $this->calendar = $calendar; // load miniColors js/css files jqueryui::miniColors(); - $this->rc->output->add_handler('calendarform', array($this, 'calendarform')); - $this->rc->output->send('calendar.folderform'); + $this->rc->output->set_env('pagetitle', $this->cal->gettext('calendarprops')); + $this->rc->output->add_handler('folderform', array($this, 'calendarform')); + $this->rc->output->send('libkolab.folderform'); } /** * Handler for calendar form template. * The form content could be overriden by the driver */ function calendarform($attrib) { // 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' => 7, 'class' => 'colors')); $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($this->calendar['showalarms'] ? 1 :0), 'id' => 'calendar-showalarms', ); } // allow driver to extend or replace the form content return html::tag('form', $attrib + array('action' => "#", 'method' => "get", 'id' => 'calendarpropform'), $this->cal->driver->calendar_form($this->action, $this->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', html::span('inner', $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', 'class' => 'form-control')); $textarea = new html_textarea(array('name' => 'comment', 'id' => 'edit-attendees-comment', 'class' => 'form-control', 'rows' => 4, 'cols' => 55, 'title' => $this->cal->gettext('itipcommenttitle'))); return html::div($attrib, html::div('form-searchbar', $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('edit-attendees-comment', $this->cal->gettext('itipcomment')) . $textarea->show()) ); } /** * */ function resources_form($attrib = array()) { $input = new html_inputfield(array('name' => 'resource', 'id' => 'edit-resource-name', 'class' => 'form-control')); return html::div($attrib, html::div('form-searchbar', $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), rcube::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', ' ') . 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'), ' ') ) ); 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/en_US.inc b/plugins/calendar/localization/en_US.inc index cd05ccd5..1eea00d4 100644 --- a/plugins/calendar/localization/en_US.inc +++ b/plugins/calendar/localization/en_US.inc @@ -1,305 +1,306 @@ CalDAV client application (e.g. Evolution or Mozilla Thunderbird) to fully synchronize this specific calendar with your computer or mobile device.'; $labels['showfburl'] = 'Show free-busy URL'; $labels['fburldescription'] = 'Use the following address to access Free-Busy information from other applications. You can copy and paste this into any calendar software that supports free-busy information in iCal format. No authentication is required for this URL.'; $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'; $labels['eventstartsync'] = 'Move the event start date to the first occurrence'; // 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['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\n\$description\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 cancelled'; $labels['eventcancelmailbody'] = "*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees\n\nThe event has been cancelled by \$organizer.\n\nPlease find attached an iCalendar file with the updated event details."; // invitation handling (overrides labels from libcalendaring) $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'; $labels['recurrenceerror'] = 'Unable to resolve recurrence rule for specified start date.'; // 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['objectchangelog'] = 'Change History'; $labels['objectdiff'] = 'Changes from $rev1 to $rev2'; $labels['objectnotfound'] = 'Failed to load event data'; $labels['objectchangelognotavailable'] = 'Change history is not available for this event'; $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['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['calendarprops'] = 'Calendar properties'; $labels['arialabeleventattendees'] = 'Event participants list'; $labels['arialabeleventresources'] = 'Event resources list'; $labels['arialabelresourcesearchform'] = 'Resources search form'; $labels['arialabelresourceselection'] = 'Available resources'; ?> diff --git a/plugins/calendar/skins/elastic/templates/folderform.html b/plugins/calendar/skins/elastic/templates/folderform.html deleted file mode 100644 index d6beaeb9..00000000 --- a/plugins/calendar/skins/elastic/templates/folderform.html +++ /dev/null @@ -1,9 +0,0 @@ - - -

    :

    - -
    - -
    - - diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css index 297b4e43..c5d53c97 100644 --- a/plugins/calendar/skins/larry/calendar.css +++ b/plugins/calendar/skins/larry/calendar.css @@ -1,2287 +1,2273 @@ /** * Roundcube Calendar plugin styles for skin "Larry" * * Copyright (c) 2012-2014, Kolab Systems AG * 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; } #datepicker .ui-datepicker-days-cell-over a.ui-state-default { color: #fff; border-color: #2fa0c0; background: rgba(73,180,210,0.6); filter: none; } #datepicker .ui-datepicker-activerange a.ui-state-active { color: #fff; background: #00acd4; } #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; height: auto; 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 a.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 > a.calname { color: #aaa; top: 4px; left: 20px; } #calendars .treelist li.x-birthdays a.calname, #calendars .treelist li.x-invitations a.calname { font-style: italic; } #calendars .treelist.flat li a.calname { left: 24px; right: 42px; } #calendars .treelist li span.handle { display: inline-block; position: absolute; top: 7px; right: 6px; padding: 0; width: 11px; height: 11px; border-radius: 8px; font-size: 0.8em; border: 1px solid rgba(0, 0, 0, 0.4); } #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 #ababab; border-radius: 4px; background: #f1f1f1; } #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 > a.calname { font-weight: bold; } #calendars .treelist div.readonly a.calname { background-position: right -20px; } #calendars .treelist li.user > div > a.calname { background-position: right -38px; } /* #calendars .treelist div.user.readonly a.calname { background-position: right -56px; } #calendars .treelist div.shared a.calname { background-position: right -74px; } #calendars .treelist div.shared.readonly a.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; 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; border-radius: 0; } #calendars .searchresults .listing li { background-color: #c7e3ef; } #fburl, #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; } #eventedit.uidialog, .calendarmain div.uidialog { display: none; } #calendarform { overflow: visible; } #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-decoration: none; white-space: nowrap; line-height: 20px; } #edit-attachments ul li a.filename { padding: 0; } #edit-attachments-form { margin-top: 1em; padding-top: 0.8em; border-top: 2px solid #fafafa; } #edit-attachments-form .buttons { 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: 1px 18px 1px 0; 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; 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 .status-cancelled #event-title, .calendarmain .sensitivity-private #event-title, .calendarmain .sensitivity-confidential #event-title { margin-right: 80px; } .calendarmain .eventdialog div.event-line { margin-bottom: 0.4em; white-space: nowrap; overflow-x: hidden; text-overflow: ellipsis; } .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; } #event-description .event-text, #event-attendees .event-text { padding-top: 0.4em; } .eventdialog .spacer { font-size: 4px; } .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; } .changelog-table .loading { color: #666; margin: 1em 0; padding: 1px 0 2px 24px; background: url(images/loading_blue.gif) top left no-repeat; } .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; } #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; } .dialog-message, .event-update-confirm .message { margin-top: 0.5em; padding: 0.8em; border: 1px solid #ffdf0e; background-color: #fef893; } .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; } .dialog-message span.ui-icon, .event-update-confirm span.ui-icon { float: left; margin: 0 7px 20px 0; } .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: 50px; 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; vertical-align: middle; } .availability img.availabilityicon.loading { background: url(images/loading_blue.gif) center no-repeat; } #schedule-freebusy-times td div.unknown, .availability img.availabilityicon.unknown { background: #ddd; } #schedule-freebusy-times td div.free, .availability img.availabilityicon.free { background: #abd640; } #schedule-freebusy-times td div.busy, .availability img.availabilityicon.busy { background: #e26569; } #schedule-freebusy-times td div.tentative, .availability img.availabilityicon.tentative { background: #8383fc; } #schedule-freebusy-times td div.out-of-office, .availability img.availabilityicon.out-of-office { background: #fbaa68; } #schedule-freebusy-times td div.all-busy, #schedule-freebusy-times td div.all-tentative, #schedule-freebusy-times td div.all-out-of-office { background-image: url(images/freebusy-colors.png); background-position: top right; background-repeat: no-repeat; } #schedule-freebusy-times td div.all-tentative { background-position: right -40px; } #schedule-freebusy-times td div.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-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 { height: 14px; } .edit-attendees-table td.confirmstate span.accepted { background-position: 5px -20px; height: 14px; } .edit-attendees-table td.confirmstate span.declined { background-position: 5px -40px; height: 14px; } .edit-attendees-table td.confirmstate span.tentative { background-position: 5px -60px; height: 14px; } .edit-attendees-table td.confirmstate span.delegated { background-position: 5px -180px; height: 14px; } #attendees-freebusy-table { 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; padding: 0; height: 10px; } #schedule-freebusy-times { border-collapse: collapse; width: 100%; } #schedule-freebusy-times td { padding: 4px; border: 1px solid #ccc; } #schedule-freebusy-times tbody td { padding: 0; height: 20px; } #schedule-freebusy-times tbody td div { height: 100%; } #attendees-freebusy-table div.timesheader, #schedule-freebusy-times tr.times td { min-width: 30px; 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-freebusy-times #fbrowall td { border-bottom: none; } #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: #eaeaea; } #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; } .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; } .calendarmain #calendar .fc-button, .calendarmain #calendar .fc-button.fc-state-default, .calendarmain #calendar .fc-button.fc-state-hover { margin: -2px 0 0 0; height: 24px; line-height: 24px; color: #333; border: 1px solid #ababab; background: #f1f1f1; text-decoration: none; text-shadow: none; } .calendarmain #calendar .fc-button.fc-state-disabled { color: #666; } .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: #f1f1f1; box-shadow: none; } .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; } .fc-needs-action, .fc-declined, .cal-event-status-cancelled { opacity: 0.6; } .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, .fc-widget-content { border-color: #bbd3da !important; } .fc-widget-header .fc-agenda-divider-inner { background: #cad2d9 !important; } .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: #bbd3da; padding: 6px 8px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .calendarmain .fc-view-table tr.fc-event td.fc-event-handle { padding: 6px 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); } .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; } div.calendar-invitebox td.date.modified { font-weight: bold; color: red; } #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.unknown, #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/kolabform.html b/plugins/calendar/skins/larry/templates/kolabform.html deleted file mode 100644 index 77a1c30e..00000000 --- a/plugins/calendar/skins/larry/templates/kolabform.html +++ /dev/null @@ -1,9 +0,0 @@ -
    - -
    - - \ No newline at end of file diff --git a/plugins/kolab_notes/kolab_notes_ui.php b/plugins/kolab_notes/kolab_notes_ui.php index 28e17e8b..41de349c 100644 --- a/plugins/kolab_notes/kolab_notes_ui.php +++ b/plugins/kolab_notes/kolab_notes_ui.php @@ -1,399 +1,400 @@ plugin = $plugin; $this->rc = $plugin->rc; } /** * Calendar UI initialization and requests handlers */ public function init() { if ($this->ready) // already done return; // add taskbar button $this->plugin->add_button(array( 'command' => 'notes', 'class' => 'button-notes', 'classsel' => 'button-notes button-selected', 'innerclass' => 'button-inner', 'label' => 'kolab_notes.navtitle', 'type' => 'link' ), 'taskbar'); $this->plugin->include_stylesheet($this->plugin->local_skin_path() . '/notes.css'); $this->ready = true; } /** * Register handler methods for the template engine */ public function init_templates() { $this->plugin->register_handler('plugin.notebooks', array($this, 'folders')); #$this->plugin->register_handler('plugin.folders_select', array($this, 'folders_select')); $this->plugin->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); $this->plugin->register_handler('plugin.listing', array($this, 'listing')); $this->plugin->register_handler('plugin.editform', array($this, 'editform')); $this->plugin->register_handler('plugin.notetitle', array($this, 'notetitle')); $this->plugin->register_handler('plugin.detailview', array($this, 'detailview')); $this->plugin->register_handler('plugin.attachments_list', array($this, 'attachments_list')); $this->plugin->register_handler('plugin.object_changelog_table', array('libkolab', 'object_changelog_table')); $this->rc->output->include_script('list.js'); $this->rc->output->include_script('treelist.js'); $this->plugin->include_script('notes.js'); $this->plugin->api->include_script('libkolab/libkolab.js'); // load config options and user prefs relevant for the UI $settings = array( 'sort_col' => $this->rc->config->get('kolab_notes_sort_col', 'changed'), ); if ($list = rcube_utils::get_input_value('_list', rcube_utils::INPUT_GPC)) { $settings['selected_list'] = $list; } if ($uid = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC)) { $settings['selected_uid'] = $uid; } $this->rc->html_editor(); $this->rc->output->set_env('kolab_notes_settings', $settings); $this->rc->output->add_label('save','cancel','delete','close','listoptionstitle'); } public function folders($attrib) { $attrib += array('id' => 'rcmkolabnotebooks'); if ($attrib['type'] == 'select') { $attrib['is_escaped'] = true; $select = new html_select($attrib); } $tree = $attrib['type'] != 'select' ? true : null; $lists = $this->plugin->get_lists($tree); $jsenv = array(); if (is_object($tree)) { $html = $this->folder_tree_html($tree, $lists, $jsenv, $attrib); } else { $html = ''; foreach ($lists as $prop) { $id = $prop['id']; if (!$prop['virtual']) { unset($prop['user_id']); $jsenv[$id] = $prop; } if ($attrib['type'] == 'select') { if ($prop['editable'] || strpos($prop['rights'], 'i') !== false) { $select->add($prop['name'], $prop['id']); } } else { $html .= html::tag('li', array('id' => 'rcmliknb' . rcube_utils::html_identifier($id), 'class' => $prop['group']), $this->folder_list_item($id, $prop, $jsenv) ); } } } $this->rc->output->set_env('kolab_notebooks', $jsenv); $this->rc->output->add_gui_object('notebooks', $attrib['id']); return $attrib['type'] == 'select' ? $select->show() : html::tag('ul', $attrib, $html, html::$common_attrib); } /** * Return html for a structured list
      for the folder tree */ public function folder_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->folder_list_item($id, $prop, $jsenv); if (!empty($folder->children)) { $content .= html::tag('ul', array('style' => ($is_collapsed ? "display:none;" : null)), $this->folder_tree_html($folder, $data, $jsenv, $attrib)); } if (strlen($content)) { $out .= html::tag('li', array( 'id' => 'rcmliknb' . rcube_utils::html_identifier($id), 'class' => $prop['group'] . ($prop['virtual'] ? ' virtual' : ''), ), $content); } } return $out; } /** * Helper method to build a tasklist item (HTML content and js data) */ public function folder_list_item($id, $prop, &$jsenv, $checkbox = false) { if (!$prop['virtual']) { unset($prop['user_id']); $jsenv[$id] = $prop; } $classes = array('folder'); if ($prop['virtual']) { $classes[] = 'virtual'; } else if (!$prop['editable']) { $classes[] = 'readonly'; } if ($prop['subscribed']) { $classes[] = 'subscribed'; } if ($prop['class']) { $classes[] = $prop['class']; } $title = $prop['title'] ?: ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ? html_entity_decode($prop['name'], ENT_COMPAT, RCUBE_CHARSET) : ''); $label_id = 'nl:' . $id; $attr = $prop['virtual'] ? array('tabindex' => '0') : array('href' => $this->rc->url(array('_list' => $id))); return html::div(join(' ', $classes), html::a($attr + array('class' => 'listname', 'title' => $title, 'id' => $label_id), $prop['listname'] ?: $prop['name']) . ($prop['virtual'] ? '' : ($checkbox ? html::tag('input', array('type' => 'checkbox', 'name' => '_list[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id)) : '' ) . html::span('handle', '') . html::span('actions', (!$prop['default'] ? html::a(array('href' => '#', 'class' => 'remove', 'title' => $this->plugin->gettext('removelist')), ' ') : '' ) . (isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->plugin->gettext('foldersubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '' ) ) ) ); return ''; } public function listing($attrib) { $attrib += array('id' => 'rcmkolabnoteslist'); $this->rc->output->add_gui_object('noteslist', $attrib['id']); return html::tag('table', $attrib, '', html::$common_attrib); } public function editform($attrib) { $attrib += array('action' => '#', 'id' => 'rcmkolabnoteseditform'); $textarea = new html_textarea(array( 'name' => 'content', 'id' => 'notecontent', 'cols' => 60, 'rows' => 20, 'tabindex' => 0, 'class' => 'mce_editor form-control', )); $this->rc->output->add_gui_object('noteseditform', $attrib['id']); return html::tag('form', $attrib, $textarea->show(), array_merge(html::$common_attrib, array('action'))); } public function detailview($attrib) { $attrib += array('id' => 'rcmkolabnotesdetailview'); $this->rc->output->add_gui_object('notesdetailview', $attrib['id']); return html::div($attrib, ''); } public function notetitle($attrib) { $attrib += array('id' => 'rcmkolabnotestitle'); $this->rc->output->add_gui_object('noteviewtitle', $attrib['id']); $summary = new html_inputfield(array( 'name' => 'summary', 'class' => 'notetitle inline-edit form-control', 'size' => 60, 'id' => 'notetitleinput', 'tabindex' => 0 )); $html = html::div('form-group row', html::label(array('class' => 'col-sm-2 col-form-label', 'for' => 'notetitleinput'), $this->plugin->gettext('kolab_notes.title')) . html::span('col-sm-10', $summary->show()) ) . html::div('form-group row', html::label(array('class' => 'col-sm-2 col-form-label'), $this->plugin->gettext('kolab_notes.tags')) . html::div(array('class' => 'tagline tagedit col-sm-10'), ' ') ) . html::div(array('class' => 'dates text-only', 'style' => 'display:none'), html::div('form-group row', html::label(array('class' => 'col-sm-2 col-form-label'), $this->plugin->gettext('created')) . html::span('col-sm-10', html::span('notecreated form-control-plaintext', '')) ) . html::div('form-group row', html::label(array('class' => 'col-sm-2 col-form-label'), $this->plugin->gettext('changed')) . html::span('col-sm-10', html::span('notechanged form-control-plaintext', '')) ) ); return html::div($attrib, $html); } public function attachments_list($attrib) { $attrib += array('id' => 'rcmkolabnotesattachmentslist'); $this->rc->output->add_gui_object('notesattachmentslist', $attrib['id']); return html::tag('ul', $attrib, '', html::$common_attrib); } /** * Render create/edit form for notes lists (folders) */ public function list_editform($action, $list, $folder) { $this->action = $action; $this->list = $list; $this->folder = is_object($folder) ? $folder->name : ''; // UTF7; - $this->rc->output->add_handler('notebookform', array($this, 'notebookform')); - $this->rc->output->send('kolab_notes.listform'); + $this->rc->output->set_env('pagetitle', $this->plugin->gettext('arialabelnotebookform')); + $this->rc->output->add_handler('folderform', array($this, 'notebookform')); + $this->rc->output->send('libkolab.folderform'); } /** * Render create/edit form for notes lists (folders) */ public function notebookform($attrib) { $folder_name = $this->folder; $hidden_fields[] = array('name' => 'oldname', 'value' => $folder_name); $storage = $this->rc->get_storage(); $delim = $storage->get_hierarchy_delimiter(); $form = array(); if (strlen($folder_name)) { $options = $storage->folder_info($folder_name); $path_imap = explode($delim, $folder_name); array_pop($path_imap); // pop off name part $path_imap = implode($path_imap, $delim); } else { $path_imap = ''; $options = array(); } // General tab $form['properties'] = array( 'name' => $this->rc->gettext('properties'), 'fields' => array(), ); // folder name (default field) $input_name = new html_inputfield(array('name' => 'name', 'id' => 'noteslist-name', 'size' => 20)); $form['properties']['fields']['name'] = array( 'label' => $this->plugin->gettext('listname'), 'value' => $input_name->show($this->list['editname'], array('disabled' => ($options['norename'] || $options['protected']))), 'id' => 'noteslist-name', ); // prevent user from moving folder if (!empty($options) && ($options['norename'] || $options['protected'])) { $hidden_fields[] = array('name' => 'parent', 'value' => $path_imap); } else { $select = kolab_storage::folder_selector('note', array('name' => 'parent', 'id' => 'parent-folder'), $folder_name); $form['properties']['fields']['path'] = array( 'label' => $this->plugin->gettext('parentfolder'), 'value' => $select->show(strlen($folder_name) ? $path_imap : ''), 'id' => 'parent-folder', ); } // add folder ACL tab if ($this->action != 'form-new') { $form['sharing'] = array( 'name' => rcube::Q($this->plugin->gettext('tabsharing')), 'content' => $this->folder_acl_form() ); } $form_html = ''; if (is_array($hidden_fields)) { foreach ($hidden_fields as $field) { $hiddenfield = new html_hiddenfield($field); $form_html .= $hiddenfield->show() . "\n"; } } // create form output foreach ($form as $tab) { if (is_array($tab['fields']) && empty($tab['content'])) { $table = new html_table(array('cols' => 2, 'class' => 'propform')); foreach ($tab['fields'] as $col => $colprop) { $label = !empty($colprop['label']) ? $colprop['label'] : $this->plugin->gettext($col); $table->add('title', html::label($colprop['id'], rcube::Q($label))); $table->add(null, $colprop['value']); } $content = $table->show(); } else { $content = $tab['content']; } if (!empty($content)) { $form_html .= html::tag('fieldset', null, html::tag('legend', null, rcube::Q($tab['name'])) . $content) . "\n"; } } return html::tag('form', $attrib + array('action' => '#', 'method' => 'post', 'id' => 'noteslistpropform'), $form_html); } /** * Returns ACL form */ public function folder_acl_form() { if (strlen($this->folder)) { $this->plugin->require_plugin('acl'); $storage = $this->rc->get_storage(); $options = $storage->folder_info($this->folder); // get sharing UI from acl plugin $acl = $this->rc->plugins->exec_hook('folder_form', array('form' => array(), 'options' => $options, 'name' => $this->folder)); } return $acl['form']['sharing']['content'] ?: html::div('hint', $this->plugin->gettext('aclnorights')); } } diff --git a/plugins/kolab_notes/skins/elastic/templates/listform.html b/plugins/kolab_notes/skins/elastic/templates/listform.html deleted file mode 100644 index 230378ca..00000000 --- a/plugins/kolab_notes/skins/elastic/templates/listform.html +++ /dev/null @@ -1,9 +0,0 @@ - - -

      :

      - -
      - -
      - - diff --git a/plugins/kolab_notes/skins/larry/templates/listform.html b/plugins/kolab_notes/skins/larry/templates/listform.html deleted file mode 100644 index 5fc9ea3b..00000000 --- a/plugins/kolab_notes/skins/larry/templates/listform.html +++ /dev/null @@ -1,18 +0,0 @@ - - - -<roundcube:object name="pagetitle" /> - - - - -

      :

      - -
      - -
      - - - - - diff --git a/plugins/tasklist/skins/larry/templates/listform.html b/plugins/libkolab/skins/larry/templates/folderform.html similarity index 61% rename from plugins/tasklist/skins/larry/templates/listform.html rename to plugins/libkolab/skins/larry/templates/folderform.html index 0fd3b63c..688abe17 100644 --- a/plugins/tasklist/skins/larry/templates/listform.html +++ b/plugins/libkolab/skins/larry/templates/folderform.html @@ -1,18 +1,18 @@ <roundcube:object name="pagetitle" /> -

      :

      +

      - +
      diff --git a/plugins/tasklist/localization/en_US.inc b/plugins/tasklist/localization/en_US.inc index 8c7769b6..9ec5395b 100644 --- a/plugins/tasklist/localization/en_US.inc +++ b/plugins/tasklist/localization/en_US.inc @@ -1,223 +1,223 @@ CalDAV client application (e.g. Evolution or Mozilla Thunderbird) to synchronize this specific tasklist with your computer or mobile device.'; $labels['newtask'] = 'New Task'; $labels['createtask'] = 'Create Task '; $labels['createnewtask'] = 'Create new Task (e.g. Saturday, Mow the lawn)'; $labels['createfrommail'] = 'Save as task'; $labels['printtitle'] = 'Print tasks'; $labels['printdescriptions'] = 'Print descriptions'; $labels['mark'] = 'Mark'; $labels['unmark'] = 'Unmark'; $labels['edit'] = 'Edit'; $labels['delete'] = 'Delete'; $labels['title'] = 'Title'; $labels['description'] = 'Description'; $labels['datetime'] = 'Due'; $labels['duetime'] = 'Due time'; $labels['start'] = 'Start'; $labels['starttime'] = 'Start time'; $labels['alarms'] = 'Reminder'; $labels['repeat'] = 'Repeat'; $labels['links'] = 'Reference'; $labels['status'] = 'Status'; $labels['status-needs-action'] = 'Needs action'; $labels['status-in-process'] = 'In process'; $labels['status-completed'] = 'Completed'; $labels['status-cancelled'] = 'Cancelled'; $labels['assignedto'] = 'Assigned to'; $labels['created'] = 'Created'; $labels['changed'] = 'Last Modified'; $labels['taskoptions'] = 'Options'; $labels['all'] = 'All'; $labels['flagged'] = 'Flagged'; $labels['complete'] = 'Complete'; $labels['completeness'] = 'Progress'; $labels['overdue'] = 'Overdue'; $labels['today'] = 'Today'; $labels['tomorrow'] = 'Tomorrow'; $labels['next7days'] = 'Next 7 days'; $labels['later'] = 'Later'; $labels['assigned'] = 'Assigned'; $labels['assignedtitle'] = 'Tasks you assigned to others'; $labels['mytasks'] = 'My tasks'; $labels['mytaskstitle'] = 'Tasks assigned to you'; $labels['nodate'] = 'no date'; $labels['removetag'] = 'Remove'; $labels['removelink'] = 'Remove email reference'; $labels['auto'] = 'Auto'; $labels['taskdetails'] = 'Task details'; $labels['newtask'] = 'New Task'; $labels['edittask'] = 'Edit Task'; $labels['save'] = 'Save'; $labels['cancel'] = 'Cancel'; $labels['saveandnotify'] = 'Save and Notify'; $labels['addsubtask'] = 'Add subtask'; $labels['deletetask'] = 'Delete task'; $labels['deletethisonly'] = 'Delete this task only'; $labels['deletewithchilds'] = 'Delete with all subtasks'; $labels['taskactions'] = 'Task options...'; $labels['tabsummary'] = 'Summary'; $labels['tabrecurrence'] = 'Recurrence'; $labels['tabassignments'] = 'Assignments'; $labels['tabattachments'] = 'Attachments'; $labels['tabsharing'] = 'Sharing'; $labels['editlist'] = 'Edit list'; $labels['createlist'] = 'Add list'; $labels['listactions'] = 'List options...'; $labels['listname'] = 'Name'; $labels['showalarms'] = 'Show reminders'; $labels['import'] = 'Import'; $labels['importtasks'] = 'Import Tasks'; $labels['viewactions'] = 'View actions'; $labels['focusview'] = 'View only this list'; $labels['activate'] = 'Activate'; // date words $labels['on'] = 'on'; $labels['at'] = 'at'; $labels['this'] = 'this'; $labels['next'] = 'next'; $labels['yes'] = 'yes'; // messages $labels['savingdata'] = 'Saving data...'; $labels['errorsaving'] = 'Failed to save data.'; $labels['notasksfound'] = 'No tasks found for the given criteria'; $labels['invalidstartduedates'] = 'Start date must not be greater than due date.'; $labels['invalidstartduetimes'] = 'Start and due dates must either both or none specify a time.'; $labels['recurrencerequiresdate'] = 'Recurring tasks require either a start or due date.'; $labels['deletetasktconfirm'] = 'Do you really want to delete this task?'; $labels['deleteparenttasktconfirm'] = 'Do you really want to delete this task and all its subtasks?'; $labels['deletelistconfirm'] = 'Do you really want to delete this list with all its tasks?'; $labels['deletelistconfirmrecursive'] = 'Do you really want to delete this list with all its sub-lists and tasks?'; $labels['aclnorights'] = 'You do not have administrator rights on this task list.'; $labels['changetaskconfirm'] = 'Update task'; $labels['changeconfirmnotifications'] = 'Do you want to notify the attendees about the modification?'; $labels['partstatupdatenotification'] = 'Do you want to notify the organizer about the status change?'; // (hidden) titles and labels for accessibility annotations $labels['quickaddinput'] = 'New task date and title'; $labels['arialabelquickaddbox'] = 'Quick add new task'; $labels['arialabelsearchform'] = 'Task search form'; $labels['arialabelquicksearchbox'] = 'Task search input'; $labels['arialabellistsearchform'] = 'Tasklists search form'; $labels['arialabeltaskselector'] = 'List mode'; $labels['arialabeltasklisting'] = 'Tasks listing'; $labels['arialabelsortmenu'] = 'Tasks sorting options'; -$labels['arialabeltasklistform'] = 'Tasks list form'; +$labels['arialabeltasklistform'] = 'Tasks list properties'; // attendees $labels['attendee'] = 'Assignee'; $labels['role'] = 'Role'; $labels['availability'] = 'Avail.'; $labels['confirmstate'] = 'Status'; $labels['addattendee'] = 'Add assignee'; $labels['roleorganizer'] = 'Organizer'; $labels['rolerequired'] = 'Required'; $labels['roleoptional'] = 'Optional'; $labels['rolechair'] = 'Chair'; $labels['rolenonparticipant'] = 'Observer'; $labels['sendinvitations'] = 'Send invitations'; $labels['sendnotifications'] = 'Notify assignees about modifications'; $labels['sendcancellation'] = 'Notify assignees about task cancellation'; $labels['invitationsubject'] = 'You\'ve been assigned to "$title"'; $labels['invitationmailbody'] = "*\$title*\n\nDue: \$date\n\nAssignees: \$attendees\n\n\$description\n\nPlease find attached an iCalendar file with all the task details which you can import to your tasks application."; $labels['itipupdatesubject'] = '"$title" has been updated'; $labels['itipupdatesubjectempty'] = 'A task that concerns you has been updated'; $labels['itipupdatemailbody'] = "*\$title*\n\nDue: \$date\n\nAssignees: \$attendees\n\nPlease find attached an iCalendar file with the updated task details which you can import to your tasks application."; $labels['itipcancelsubject'] = '"$title" has been cancelled'; $labels['itipcancelmailbody'] = "*\$title*\n\nDue: \$date\n\nAssignees: \$attendees\n\nThe task has been cancelled by \$organizer.\n\nPlease find attached an iCalendar file with the updated task details."; $labels['saveintasklist'] = 'save in '; // history dialog $labels['taskhistory'] = 'History'; $labels['objectchangelog'] = 'Change History'; $labels['objectdiff'] = 'Changes from $rev1 to $rev2'; $labels['objectnotfound'] = 'Failed to load task data'; $labels['objectchangelognotavailable'] = 'Change history is not available for this task'; $labels['objectdiffnotavailable'] = 'No comparison possible for the selected revisions'; $labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev of this task? This will replace the current task with the old version.'; $labels['objectrestoresuccess'] = 'Revision $rev successfully restored'; $labels['objectrestoreerror'] = 'Failed to restore the old revision'; // invitation handling (overrides labels from libcalendaring) $labels['itipobjectnotfound'] = 'The task referred by this message was not found in your tasks list.'; $labels['itipmailbodyaccepted'] = "\$sender has accepted the assignment to the following task:\n\n*\$title*\n\nDue: \$date\n\nAssignees: \$attendees"; $labels['itipmailbodytentative'] = "\$sender has tentatively accepted the assignment to the following task:\n\n*\$title*\n\nDue: \$date\n\nAssignees: \$attendees"; $labels['itipmailbodydeclined'] = "\$sender has declined the assignment to the following task:\n\n*\$title*\n\nDue: \$date\n\nAssignees: \$attendees"; $labels['itipmailbodycancel'] = "\$sender has rejected your assignment to the following task:\n\n*\$title*\n\nDue: \$date"; $labels['itipmailbodyin-process'] = "\$sender has set the status of the following task to in-process:\n\n*\$title*\n\nDue: \$date"; $labels['itipmailbodycompleted'] = "\$sender has completed the following task:\n\n*\$title*\n\nDue: \$date"; $labels['itipmailbodydelegated'] = "\$sender has delegated the following task:\n\n*\$title*\n\nDue: \$date"; $labels['itipmailbodydelegatedto'] = "\$sender has delegated the following task to you:\n\n*\$title*\n\nDue: \$date"; $labels['attendeeaccepted'] = 'Assignee has accepted'; $labels['attendeetentative'] = 'Assignee has tentatively accepted'; $labels['attendeedeclined'] = 'Assignee has declined'; $labels['attendeedelegated'] = 'Assignee has delegated to $delegatedto'; $labels['attendeein-process'] = 'Assignee is in-process'; $labels['attendeecompleted'] = 'Assignee has completed'; $labels['acceptinvitation'] = 'Do you accept this assignment?'; $labels['itipdeclinetask'] = 'Decline your assignment to this task to the organizer'; $labels['declinedeleteconfirm'] = 'Do you also want to delete this declined task from your tasks list?'; $labels['itipcomment'] = 'Invitation/notification comment'; $labels['itipcommenttitle'] = 'This comment will be attached to the invitation/notification message sent to assignees'; $labels['itipsendsuccess'] = 'Notification sent to assignees'; $labels['errornotifying'] = 'Failed to send notifications to task assignees'; $labels['removefromcalendar'] = 'Remove from my tasks'; $labels['delegateinvitation'] = 'Delegate assignment'; $labels['importtext'] = 'You can upload tasks in iCalendar format (.ics).'; $labels['andnmore'] = '$nr more...'; $labels['savetotasklist'] = 'Save to tasks'; $labels['comment'] = 'Comment'; $labels['rsvpcomment'] = 'Comment'; $labels['errorimportingtask'] = 'Failed to import task(s)'; $labels['importwarningexists'] = 'A copy of this task already exists in your tasklist.'; $labels['importsuccess'] = 'Successfully imported $nr tasks'; $labels['importnone'] = 'No tasks found to be imported'; $labels['importerror'] = 'An error occured while importing'; $labels['newerversionexists'] = 'A newer version of this task already exists! Aborted.'; $labels['nowritetasklistfound'] = 'No tasklist found to save the task'; $labels['importedsuccessfully'] = 'The task was successfully added to \'$list\''; $labels['updatedsuccessfully'] = 'The task was successfully updated in \'$list\''; $labels['attendeupdateesuccess'] = 'Successfully updated the participant\'s status'; $labels['itipresponseerror'] = 'Failed to send the response to this task assignment'; $labels['itipinvalidrequest'] = 'This invitation is no longer valid'; $labels['sentresponseto'] = 'Successfully sent assignment response to $mailto'; $labels['successremoval'] = 'The task has been deleted successfully.'; $labels['invalidlistproperties'] = 'Invalid list properties! Please set a valid name.'; diff --git a/plugins/tasklist/skins/elastic/templates/listform.html b/plugins/tasklist/skins/elastic/templates/listform.html deleted file mode 100644 index 87d345bb..00000000 --- a/plugins/tasklist/skins/elastic/templates/listform.html +++ /dev/null @@ -1,9 +0,0 @@ - - -

      :

      - -
      - -
      - - diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php index 8554d271..eb5567fc 100644 --- a/plugins/tasklist/tasklist_ui.php +++ b/plugins/tasklist/tasklist_ui.php @@ -1,583 +1,585 @@ * * Copyright (C) 2012-2015, Kolab Systems AG * * 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 . */ class tasklist_ui { private $rc; private $plugin; private $ready = false; private $gui_objects = array(); function __construct($plugin) { $this->plugin = $plugin; $this->rc = $plugin->rc; } /** * Calendar UI initialization and requests handlers */ public function init() { if ($this->ready) { return; } // add taskbar button $this->plugin->add_button(array( 'command' => 'tasks', 'class' => 'button-tasklist', 'classsel' => 'button-tasklist button-selected', 'innerclass' => 'button-inner', 'label' => 'tasklist.navtitle', 'type' => 'link' ), 'taskbar'); $this->plugin->include_stylesheet($this->plugin->local_skin_path() . '/tasklist.css'); if ($this->rc->task == 'mail' || $this->rc->task == 'tasks') { $this->plugin->include_script('tasklist_base.js'); // copy config to client $this->rc->output->set_env('tasklist_settings', $this->load_settings()); // initialize attendees autocompletion $this->rc->autocomplete_init(); } $this->ready = true; } /** * */ function load_settings() { $settings = array(); $settings['invite_shared'] = (int)$this->rc->config->get('calendar_allow_invite_shared', 0); $settings['itip_notify'] = (int)$this->rc->config->get('calendar_itip_send_option', 3); $settings['sort_col'] = $this->rc->config->get('tasklist_sort_col', ''); $settings['sort_order'] = $this->rc->config->get('tasklist_sort_order', 'asc'); // get user identity to create default attendee 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'])) ); if ($list = rcube_utils::get_input_value('_list', rcube_utils::INPUT_GPC)) { $settings['selected_list'] = $list; } if ($list && ($id = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC))) { $settings['selected_id'] = $id; // check if the referenced task is completed $task = $this->plugin->driver->get_task(array('id' => $id, 'list' => $list)); if ($task && $this->plugin->driver->is_complete($task)) { $settings['selected_filter'] = 'complete'; } } else if ($filter = rcube_utils::get_input_value('_filter', rcube_utils::INPUT_GPC)) { $settings['selected_filter'] = $filter; } return $settings; } /** * 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); } /** * Register handler methods for the template engine */ public function init_templates() { $this->plugin->register_handler('plugin.tasklists', array($this, 'tasklists')); $this->plugin->register_handler('plugin.tasklist_select', array($this, 'tasklist_select')); $this->plugin->register_handler('plugin.status_select', array($this, 'status_select')); $this->plugin->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); $this->plugin->register_handler('plugin.quickaddform', array($this, 'quickadd_form')); $this->plugin->register_handler('plugin.tasks', array($this, 'tasks_resultview')); $this->plugin->register_handler('plugin.tags_editline', array($this, 'tags_editline')); $this->plugin->register_handler('plugin.alarm_select', array($this, 'alarm_select')); $this->plugin->register_handler('plugin.recurrence_form', array($this->plugin->lib, 'recurrence_form')); $this->plugin->register_handler('plugin.attendees_list', array($this, 'attendees_list')); $this->plugin->register_handler('plugin.attendees_form', array($this, 'attendees_form')); $this->plugin->register_handler('plugin.identity_select', array($this, 'identity_select')); $this->plugin->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify')); $this->plugin->register_handler('plugin.task_rsvp_buttons', array($this->plugin->itip, 'itip_rsvp_buttons')); $this->plugin->register_handler('plugin.object_changelog_table', array('libkolab', 'object_changelog_table')); $this->plugin->register_handler('plugin.tasks_export_form', array($this, 'tasks_export_form')); $this->plugin->register_handler('plugin.tasks_import_form', array($this, 'tasks_import_form')); kolab_attachments_handler::ui(); $this->plugin->include_script('tasklist.js'); $this->plugin->api->include_script('libkolab/libkolab.js'); } /** * */ public function tasklists($attrib = array()) { $tree = true; $jsenv = array(); $lists = $this->plugin->driver->get_lists(0, $tree); if (empty($attrib['id'])) { $attrib['id'] = 'rcmtasklistslist'; } // walk folder tree if (is_object($tree)) { $html = $this->list_tree_html($tree, $lists, $jsenv, $attrib); } else { // fall-back to flat folder listing $attrib['class'] .= ' flat'; $html = ''; foreach ((array)$lists as $id => $prop) { if ($attrib['activeonly'] && !$prop['active']) continue; $html .= html::tag('li', array( 'id' => 'rcmlitasklist' . rcube_utils::html_identifier($id), 'class' => $prop['group'], ), $this->tasklist_list_item($id, $prop, $jsenv, $attrib['activeonly']) ); } } $this->rc->output->include_script('treelist.js'); $this->rc->output->set_env('source', rcube_utils::get_input_value('source', rcube_utils::INPUT_GET)); $this->rc->output->set_env('tasklists', $jsenv); $this->register_gui_object('tasklistslist', $attrib['id']); return html::tag('ul', $attrib, $html, html::$common_attrib); } /** * Return html for a structured list
        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->tasklist_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' => 'rcmlitasklist' . rcube_utils::html_identifier($id), 'class' => $prop['group'] . ($prop['virtual'] ? ' virtual' : ''), ), $content); } } return $out; } /** * Helper method to build a tasklist item (HTML content and js data) */ public function tasklist_list_item($id, $prop, &$jsenv, $activeonly = false) { // enrich list properties with settings from the driver if (!$prop['virtual']) { unset($prop['user_id']); $prop['alarms'] = $this->plugin->driver->alarms; $prop['undelete'] = $this->plugin->driver->undelete; $prop['sortable'] = $this->plugin->driver->sortable; $prop['attachments'] = $this->plugin->driver->attachments; $prop['attendees'] = $this->plugin->driver->attendees; $prop['caldavurl'] = $this->plugin->driver->tasklist_caldav_url($prop); $jsenv[$id] = $prop; } $classes = array('tasklist'); $title = $prop['title'] ?: ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ? html_entity_decode($prop['name'], ENT_COMPAT, RCUBE_CHARSET) : ''); if ($prop['virtual']) $classes[] = 'virtual'; else if (!$prop['editable']) $classes[] = 'readonly'; if ($prop['subscribed']) $classes[] = 'subscribed'; if ($prop['class']) $classes[] = $prop['class']; if (!$activeonly || $prop['active']) { $label_id = 'tl:' . $id; $chbox = html::tag('input', array( 'type' => 'checkbox', 'name' => '_list[]', 'value' => $id, 'checked' => $prop['active'], 'title' => $this->plugin->gettext('activate'), 'aria-labelledby' => $label_id )); return html::div(join(' ', $classes), html::a(array('class' => 'listname', 'title' => $title, 'href' => '#', 'id' => $label_id), $prop['listname'] ?: $prop['name']) . ($prop['virtual'] ? '' : $chbox . html::span('actions', ($prop['removable'] ? html::a(array('href' => '#', 'class' => 'remove', 'title' => $this->plugin->gettext('removelist')), ' ') : '') . html::a(array('href' => '#', 'class' => 'quickview', 'title' => $this->plugin->gettext('focusview'), 'role' => 'checkbox', 'aria-checked' => 'false'), ' ') . (isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->plugin->gettext('tasklistsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '') ) ) ); } return ''; } /** * Render HTML form for task status selector */ function status_select($attrib = array()) { $attrib['name'] = 'status'; $select = new html_select($attrib); $select->add('---', ''); $select->add($this->plugin->gettext('status-needs-action'), 'NEEDS-ACTION'); $select->add($this->plugin->gettext('status-in-process'), 'IN-PROCESS'); $select->add($this->plugin->gettext('status-completed'), 'COMPLETED'); $select->add($this->plugin->gettext('status-cancelled'), 'CANCELLED'); return $select->show(null); } /** * Render a HTML select box for list selection */ function tasklist_select($attrib = array()) { if (empty($attrib['name'])) { $attrib['name'] = 'list'; } $attrib['is_escaped'] = true; $select = new html_select($attrib); $default = null; foreach ((array) $attrib['extra'] as $id => $name) { $select->add($name, $id); } foreach ((array)$this->plugin->driver->get_lists() as $id => $prop) { if ($prop['editable'] || strpos($prop['rights'], 'i') !== false) { $select->add($prop['name'], $id); if (!$default || $prop['default']) $default = $id; } } return $select->show($default); } function tasklist_editform($action, $list = array()) { $this->action = $action; $this->list = $list; - $this->rc->output->add_handler('tasklistform', array($this, 'tasklistform')); - $this->rc->output->send('tasklist.listform'); + + $this->rc->output->set_env('pagetitle', $this->plugin->gettext('arialabeltasklistform')); + $this->rc->output->add_handler('folderform', array($this, 'tasklistform')); + $this->rc->output->send('libkolab.folderform'); } function tasklistform($attrib) { $fields = array( 'name' => array( 'id' => 'taskedit-tasklistname', 'label' => $this->plugin->gettext('listname'), 'value' => html::tag('input', array('id' => 'taskedit-tasklistname', 'name' => 'name', 'type' => 'text', 'class' => 'text', 'size' => 40)), ), /* 'color' => array( 'id' => 'taskedit-color', 'label' => $this->plugin->gettext('color'), 'value' => html::tag('input', array('id' => 'taskedit-color', 'name' => 'color', 'type' => 'text', 'class' => 'text colorpicker', 'size' => 6)), ), */ 'showalarms' => array( 'id' => 'taskedit-showalarms', 'label' => $this->plugin->gettext('showalarms'), 'value' => html::tag('input', array('id' => 'taskedit-showalarms', 'name' => 'color', 'type' => 'checkbox')), ), ); return html::tag('form', $attrib + array('action' => "#", 'method' => "post", 'id' => 'tasklisteditform'), $this->plugin->driver->tasklist_edit_form($this->action, $this->list, $fields) ); } /** * Render HTML form for alarm configuration */ function alarm_select($attrib = array()) { $attrib['_type'] = 'task'; return $this->plugin->lib->alarm_select($attrib, $this->plugin->driver->alarm_types, $this->plugin->driver->alarm_absolute); } /** * */ function quickadd_form($attrib) { $attrib += array('action' => $this->rc->url('add'), 'method' => 'post', 'id' => 'quickaddform'); $label = html::label(array('for' => 'quickaddinput', 'class' => 'voice'), $this->plugin->gettext('quickaddinput')); $input = new html_inputfield(array('name' => 'text', 'id' => 'quickaddinput')); $button = html::tag('input', array( 'type' => 'submit', 'value' => '+', 'title' => $this->plugin->gettext('createtask'), 'class' => 'button mainaction' )); $this->register_gui_object('quickaddform', $attrib['id']); return html::tag('form', $attrib, $label . $input->show() . $button); } /** * The result view */ function tasks_resultview($attrib) { $attrib += array('id' => 'rcmtaskslist'); $this->register_gui_object('resultlist', $attrib['id']); unset($attrib['name']); return html::tag('ul', $attrib, ''); } /** * Interactive UI element to add/remove tags */ function tags_editline($attrib) { $attrib += array('id' => 'rcmtasktagsedit'); $this->register_gui_object('edittagline', $attrib['id']); $input = new html_inputfield(array('name' => 'tags[]', 'class' => 'tag', 'size' => $attrib['size'], 'tabindex' => $attrib['tabindex'])); unset($attrib['tabindex']); return html::div($attrib, $input->show('')); } /** * */ 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' => 4 + intval($invitations), 'border' => 0, 'cellpadding' => 0, 'class' => 'rectable')); // $table->add_header('role', $this->plugin->gettext('role')); $table->add_header('name', $this->plugin->gettext($attrib['coltitle'] ?: 'attendee')); $table->add_header('confirmstate', $this->plugin->gettext('confirmstate')); if ($invitations) { $table->add_header(array('class' => 'invite', 'title' => $this->plugin->gettext('sendinvitations')), $invite->show(1) . html::label('edit-attendees-invite', html::span('inner', $this->plugin->gettext('sendinvitations')))); } $table->add_header('options', ''); // hide invite column if disabled by config $itip_notify = (int)$this->rc->config->get('calendar_itip_send_option', 3); 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' => $attrib['size'], 'class' => 'form-control')); $textarea = new html_textarea(array('name' => 'comment', 'id' => 'edit-attendees-comment', 'rows' => 4, 'cols' => 55, 'title' => $this->plugin->gettext('itipcommenttitle'), 'class' => 'form-control')); return html::div($attrib, html::div('form-searchbar', $input->show() . " " . html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-add', 'value' => $this->plugin->gettext('addattendee'))) // . " " . html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-schedule', 'value' => $this->plugin->gettext('scheduletime').'...')) ) . html::p('attendees-commentbox', html::label('edit-attendees-comment', $this->plugin->gettext('itipcomment')) . $textarea->show()) ); } /** * */ function edit_attendees_notify($attrib = array()) { $checkbox = new html_checkbox(array('name' => '_notify', 'id' => 'edit-attendees-donotify', 'value' => 1, 'class' => 'pretty-checkbox')); return html::div($attrib, html::label(null, $checkbox->show(1) . ' ' . $this->plugin->gettext('sendnotifications'))); } /** * Form for uploading and importing tasks */ function tasks_import_form($attrib = array()) { if (!$attrib['id']) { $attrib['id'] = 'rcmImportForm'; } // Get max filesize, enable upload progress bar $max_filesize = $this->rc->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 )); $html = html::div('form-section form-group row', html::label(array('class' => 'col-sm-4 col-form-label', 'for' => 'importfile'), rcube::Q($this->rc->gettext('importfromfile'))) . html::div('col-sm-8', $input->show() . html::div('hint', $this->rc->gettext(array('id' => 'importfile', 'name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))))) ); $html .= html::div('form-section form-group row', html::label(array('for' => 'task-import-list', 'class' => 'col-sm-4 col-form-label'), $this->plugin->gettext('list')) . html::div('col-sm-8', $this->tasklist_select(array('name' => 'source', 'id' => 'task-import-list', 'editable' => true))) ); $this->rc->output->add_gui_object('importform', $attrib['id']); $this->rc->output->add_label('import', 'importerror'); return html::tag('p', null, $this->plugin->gettext('importtext')) .html::tag('form', array( 'action' => $this->rc->url(array('task' => 'tasklist', 'action' => 'import')), 'method' => 'post', 'enctype' => 'multipart/form-data', 'id' => $attrib['id'], ), $html ); } /** * Form to select options for exporting tasks */ function tasks_export_form($attrib = array()) { if (!$attrib['id']) { $attrib['id'] = 'rcmTaskExportForm'; } $html .= html::div('form-section form-group row', html::label(array('for' => 'task-export-list', 'class' => 'col-sm-4 col-form-label'), $this->plugin->gettext('list')) . html::div('col-sm-8', $this->tasklist_select(array( 'name' => 'source', 'id' => 'task-export-list', 'extra' => array('' => '- ' . $this->plugin->gettext('currentview') . ' -'), ))) ); $checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'task-export-attachments', 'value' => 1, 'class' => 'form-check-input')); $html .= html::div('form-section form-group row form-check', html::label(array('for' => 'task-export-attachments', 'class' => 'col-sm-4 col-form-label'), $this->plugin->gettext('exportattachments')) . html::div('col-sm-8', $checkbox->show(1)) ); $this->register_gui_object('exportform', $attrib['id']); return html::tag('form', array( 'action' => $this->rc->url(array('task' => 'tasklist', 'action' => 'export')), 'method' => 'post', 'id' => $attrib['id'] ), $html ); } /** * Wrapper for rcube_output_html::add_gui_object() */ function register_gui_object($name, $id) { $this->gui_objects[$name] = $id; $this->rc->output->add_gui_object($name, $id); } /** * Getter for registered gui objects. * (for manual registration when loading the inline UI) */ function get_gui_objects() { return $this->gui_objects; } }