Page MenuHomePhorge

No OneTemporary

diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php
index 15d24d59..f902b77f 100644
--- a/plugins/calendar/lib/calendar_ui.php
+++ b/plugins/calendar/lib/calendar_ui.php
@@ -1,892 +1,892 @@
<?php
/**
* User Interface class for the Calendar plugin
*
* @author Lazlo Westerhof <hello@lazlo.me>
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2010, Lazlo Westerhof <hello@lazlo.me>
* Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class calendar_ui
{
private $rc;
private $cal;
private $ready = false;
public $screen;
function __construct($cal)
{
$this->cal = $cal;
$this->rc = $cal->rc;
$this->screen = $this->rc->task == 'calendar' ? ($this->rc->action ? $this->rc->action: 'calendar') : 'other';
}
/**
* Calendar UI initialization and requests handlers
*/
public function init()
{
if ($this->ready) // already done
return;
// add taskbar button
$this->cal->add_button(array(
'command' => 'calendar',
'class' => 'button-calendar',
'classsel' => 'button-calendar button-selected',
'innerclass' => 'button-inner',
'label' => 'calendar.calendar',
), 'taskbar');
// load basic client script
$this->cal->include_script('calendar_base.js');
$skin_path = $this->cal->local_skin_path();
$this->cal->include_stylesheet($skin_path . '/calendar.css');
$this->ready = true;
}
/**
* Register handler methods for the template engine
*/
public function init_templates()
{
$this->cal->register_handler('plugin.calendar_css', array($this, 'calendar_css'));
$this->cal->register_handler('plugin.calendar_list', array($this, 'calendar_list'));
$this->cal->register_handler('plugin.calendar_select', array($this, 'calendar_select'));
$this->cal->register_handler('plugin.identity_select', array($this, 'identity_select'));
$this->cal->register_handler('plugin.category_select', array($this, 'category_select'));
$this->cal->register_handler('plugin.status_select', array($this, 'status_select'));
$this->cal->register_handler('plugin.freebusy_select', array($this, 'freebusy_select'));
$this->cal->register_handler('plugin.priority_select', array($this, 'priority_select'));
$this->cal->register_handler('plugin.sensitivity_select', array($this, 'sensitivity_select'));
$this->cal->register_handler('plugin.alarm_select', array($this, 'alarm_select'));
$this->cal->register_handler('plugin.recurrence_form', array($this->cal->lib, 'recurrence_form'));
$this->cal->register_handler('plugin.attachments_form', array($this, 'attachments_form'));
$this->cal->register_handler('plugin.attachments_list', array($this, 'attachments_list'));
$this->cal->register_handler('plugin.filedroparea', array($this, 'file_drop_area'));
$this->cal->register_handler('plugin.attendees_list', array($this, 'attendees_list'));
$this->cal->register_handler('plugin.attendees_form', array($this, 'attendees_form'));
$this->cal->register_handler('plugin.resources_form', array($this, 'resources_form'));
$this->cal->register_handler('plugin.resources_list', array($this, 'resources_list'));
$this->cal->register_handler('plugin.resources_searchform', array($this, 'resources_search_form'));
$this->cal->register_handler('plugin.resource_info', array($this, 'resource_info'));
$this->cal->register_handler('plugin.resource_calendar', array($this, 'resource_calendar'));
$this->cal->register_handler('plugin.attendees_freebusy_table', array($this, 'attendees_freebusy_table'));
$this->cal->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify'));
$this->cal->register_handler('plugin.edit_recurring_warning', array($this, 'recurring_event_warning'));
$this->cal->register_handler('plugin.event_rsvp_buttons', array($this, 'event_rsvp_buttons'));
$this->cal->register_handler('plugin.angenda_options', array($this, 'angenda_options'));
$this->cal->register_handler('plugin.events_import_form', array($this, 'events_import_form'));
$this->cal->register_handler('plugin.events_export_form', array($this, 'events_export_form'));
$this->cal->register_handler('plugin.event_changelog_table', array($this, 'event_changelog_table'));
$this->cal->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template
}
/**
* Adds CSS stylesheets to the page header
*/
public function addCSS()
{
$skin_path = $this->cal->local_skin_path();
$this->cal->include_stylesheet($skin_path . '/fullcalendar.css');
}
/**
* Adds JS files to the page header
*/
public function addJS()
{
$this->cal->include_script('calendar_ui.js');
$this->cal->include_script('lib/js/fullcalendar.js');
$this->rc->output->include_script('treelist.js');
// include kolab folderlist widget if available
- if (is_readable($this->cal->api->dir . 'libkolab/js/folderlist.js')) {
+ if (in_array('libkolab', $this->cal->api->loaded_plugins())) {
$this->cal->api->include_script('libkolab/js/folderlist.js');
}
jqueryui::miniColors();
}
/**
*
*/
function calendar_css($attrib = array())
{
$mode = $this->rc->config->get('calendar_event_coloring', $this->cal->defaults['calendar_event_coloring']);
$categories = $this->cal->driver->list_categories();
$css = "\n";
foreach ((array)$categories as $class => $color) {
if (empty($color))
continue;
$class = 'cat-' . asciiwords(strtolower($class), true);
$css .= ".$class { color: #$color }\n";
if ($mode > 0) {
if ($mode == 2) {
$css .= ".fc-event-$class .fc-event-bg {";
$css .= " opacity: 0.9;";
$css .= " filter: alpha(opacity=90);";
}
else {
$css .= ".fc-event-$class.fc-event-skin, ";
$css .= ".fc-event-$class .fc-event-skin, ";
$css .= ".fc-event-$class .fc-event-inner {";
}
$css .= " background-color: #" . $color . ";";
if ($mode % 2)
$css .= " border-color: #$color;";
$css .= "}\n";
}
}
$calendars = $this->cal->driver->list_calendars();
foreach ((array)$calendars as $id => $prop) {
if (!$prop['color'])
continue;
$css .= $this->calendar_css_classes($id, $prop, $mode);
}
return html::tag('style', array('type' => 'text/css'), $css);
}
/**
*
*/
public function calendar_css_classes($id, $prop, $mode)
{
$color = $prop['color'];
$class = 'cal-' . asciiwords($id, true);
$css .= "li.$class, #eventshow .$class { color: #$color }\n";
if ($mode != 1) {
if ($mode == 3) {
$css .= ".fc-event-$class .fc-event-bg {";
$css .= " opacity: 0.9;";
$css .= " filter: alpha(opacity=90);";
}
else {
$css .= ".fc-event-$class, ";
$css .= ".fc-event-$class .fc-event-inner {";
}
if (!$attrib['printmode'])
$css .= " background-color: #$color;";
if ($mode % 2 == 0)
$css .= " border-color: #$color;";
$css .= "}\n";
}
return $css . ".$class .handle { background-color: #$color; }\n";
}
/**
*
*/
function calendar_list($attrib = array())
{
$html = '';
$jsenv = array();
$tree = true;
$calendars = $this->cal->driver->list_calendars(false, false, $tree);
// walk folder tree
if (is_object($tree)) {
$html = $this->list_tree_html($tree, $calendars, $jsenv, $attrib);
// append birthdays calendar which isn't part of $tree
if ($bdaycal = $calendars[calendar_driver::BIRTHDAY_CALENDAR_ID]) {
$calendars = array(calendar_driver::BIRTHDAY_CALENDAR_ID => $bdaycal);
}
else {
$calendars = array(); // clear array for flat listing
}
}
else {
// fall-back to flat folder listing
$attrib['class'] .= ' flat';
}
foreach ((array)$calendars as $id => $prop) {
if ($attrib['activeonly'] && !$prop['active'])
continue;
$html .= html::tag('li', array('id' => 'rcmlical' . $id, 'class' => $prop['group']),
$content = $this->calendar_list_item($id, $prop, $jsenv, $attrib['activeonly'])
);
}
$this->rc->output->set_env('calendars', $jsenv);
$this->rc->output->add_gui_object('calendarslist', $attrib['id']);
return html::tag('ul', $attrib, $html, html::$common_attrib);
}
/**
* Return html for a structured list <ul> for the folder tree
*/
public function list_tree_html($node, $data, &$jsenv, $attrib)
{
$out = '';
foreach ($node->children as $folder) {
$id = $folder->id;
$prop = $data[$id];
$is_collapsed = false; // TODO: determine this somehow?
$content = $this->calendar_list_item($id, $prop, $jsenv, $attrib['activeonly']);
if (!empty($folder->children)) {
$content .= html::tag('ul', array('style' => ($is_collapsed ? "display:none;" : null)),
$this->list_tree_html($folder, $data, $jsenv, $attrib));
}
if (strlen($content)) {
$out .= html::tag('li', array(
'id' => 'rcmlical' . rcube_utils::html_identifier($id),
'class' => $prop['group'] . ($prop['virtual'] ? ' virtual' : ''),
),
$content);
}
}
return $out;
}
/**
* Helper method to build a calendar list item (HTML content and js data)
*/
public function calendar_list_item($id, $prop, &$jsenv, $activeonly = false)
{
// enrich calendar properties with settings from the driver
if (!$prop['virtual']) {
unset($prop['user_id']);
$prop['alarms'] = $this->cal->driver->alarms;
$prop['attendees'] = $this->cal->driver->attendees;
$prop['freebusy'] = $this->cal->driver->freebusy;
$prop['attachments'] = $this->cal->driver->attachments;
$prop['undelete'] = $this->cal->driver->undelete;
$prop['feedurl'] = $this->cal->get_url(array('_cal' => $this->cal->ical_feed_hash($id) . '.ics', 'action' => 'feed'));
$jsenv[$id] = $prop;
}
$classes = array('calendar', 'cal-' . asciiwords($id, true));
$title = $prop['title'] ?: ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ?
html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET) : '');
if ($prop['virtual'])
$classes[] = 'virtual';
else if ($prop['readonly'])
$classes[] = 'readonly';
if ($prop['subscribed'])
$classes[] = 'subscribed';
if ($prop['subscribed'] === 2)
$classes[] = 'partial';
if ($prop['class'])
$classes[] = $prop['class'];
$content = '';
if (!$activeonly || $prop['active']) {
$label_id = 'cl:' . $id;
$content = html::div(join(' ', $classes),
html::span(array('class' => 'calname', 'id' => $label_id, 'title' => $title), $prop['editname'] ? Q($prop['editname']) : $prop['listname']) .
($prop['virtual'] ? '' :
html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id), '') .
html::span('actions',
($prop['removable'] ? html::a(array('href' => '#', 'class' => 'remove', 'title' => $this->cal->gettext('removelist')), ' ') : '') .
html::a(array('href' => '#', 'class' => 'quickview', 'title' => $this->cal->gettext('quickview'), 'role' => 'checkbox', 'aria-checked' => 'false'), '') .
(isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->cal->gettext('calendarsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '')
) .
html::span(array('class' => 'handle', 'style' => "background-color: #" . ($prop['color'] ?: 'f00')), '&nbsp;')
)
);
}
return $content;
}
/**
*
*/
function angenda_options($attrib = array())
{
$attrib += array('id' => 'agendaoptions');
$attrib['style'] .= 'display:none';
$select_range = new html_select(array('name' => 'listrange', 'id' => 'agenda-listrange'));
$select_range->add(1 . ' ' . preg_replace('/\(.+\)/', '', $this->cal->lib->gettext('days')), $days);
foreach (array(2,5,7,14,30,60,90,180,365) as $days)
$select_range->add($days . ' ' . preg_replace('/\(|\)/', '', $this->cal->lib->gettext('days')), $days);
$html .= html::label('agenda-listrange', $this->cal->gettext('listrange'));
$html .= $select_range->show($this->rc->config->get('calendar_agenda_range', $this->cal->defaults['calendar_agenda_range']));
$select_sections = new html_select(array('name' => 'listsections', 'id' => 'agenda-listsections'));
$select_sections->add('---', '');
foreach (array('day' => 'libcalendaring.days', 'week' => 'libcalendaring.weeks', 'month' => 'libcalendaring.months', 'smart' => 'calendar.smartsections') as $val => $label)
$select_sections->add(preg_replace('/\(|\)/', '', ucfirst($this->rc->gettext($label))), $val);
$html .= html::span('spacer', '&nbsp;');
$html .= html::label('agenda-listsections', $this->cal->gettext('listsections'));
$html .= $select_sections->show($this->rc->config->get('calendar_agenda_sections', $this->cal->defaults['calendar_agenda_sections']));
return html::div($attrib, $html);
}
/**
* Render a HTML select box for calendar selection
*/
function calendar_select($attrib = array())
{
$attrib['name'] = 'calendar';
$attrib['is_escaped'] = true;
$select = new html_select($attrib);
foreach ((array)$this->cal->driver->list_calendars() as $id => $prop) {
if (!$prop['readonly'])
$select->add($prop['name'], $id);
}
return $select->show(null);
}
/**
* Render a HTML select box for user identity selection
*/
function identity_select($attrib = array())
{
$attrib['name'] = 'identity';
$select = new html_select($attrib);
$identities = $this->rc->user->list_emails();
foreach ($identities as $ident) {
$select->add(format_email_recipient($ident['email'], $ident['name']), $ident['identity_id']);
}
return $select->show(null);
}
/**
* Render a HTML select box to select an event category
*/
function category_select($attrib = array())
{
$attrib['name'] = 'categories';
$select = new html_select($attrib);
$select->add('---', '');
foreach (array_keys((array)$this->cal->driver->list_categories()) as $cat) {
$select->add($cat, $cat);
}
return $select->show(null);
}
/**
* Render a HTML select box for status property
*/
function status_select($attrib = array())
{
$attrib['name'] = 'status';
$select = new html_select($attrib);
$select->add('---', '');
$select->add($this->cal->gettext('status-confirmed'), 'CONFIRMED');
$select->add($this->cal->gettext('status-cancelled'), 'CANCELLED');
//$select->add($this->cal->gettext('tentative'), 'TENTATIVE');
return $select->show(null);
}
/**
* Render a HTML select box for free/busy/out-of-office property
*/
function freebusy_select($attrib = array())
{
$attrib['name'] = 'freebusy';
$select = new html_select($attrib);
$select->add($this->cal->gettext('free'), 'free');
$select->add($this->cal->gettext('busy'), 'busy');
// out-of-office is not supported by libkolabxml (#3220)
// $select->add($this->cal->gettext('outofoffice'), 'outofoffice');
$select->add($this->cal->gettext('tentative'), 'tentative');
return $select->show(null);
}
/**
* Render a HTML select for event priorities
*/
function priority_select($attrib = array())
{
$attrib['name'] = 'priority';
$select = new html_select($attrib);
$select->add('---', '0');
$select->add('1 '.$this->cal->gettext('highest'), '1');
$select->add('2 '.$this->cal->gettext('high'), '2');
$select->add('3 ', '3');
$select->add('4 ', '4');
$select->add('5 '.$this->cal->gettext('normal'), '5');
$select->add('6 ', '6');
$select->add('7 ', '7');
$select->add('8 '.$this->cal->gettext('low'), '8');
$select->add('9 '.$this->cal->gettext('lowest'), '9');
return $select->show(null);
}
/**
* Render HTML input for sensitivity selection
*/
function sensitivity_select($attrib = array())
{
$attrib['name'] = 'sensitivity';
$select = new html_select($attrib);
$select->add($this->cal->gettext('public'), 'public');
$select->add($this->cal->gettext('private'), 'private');
$select->add($this->cal->gettext('confidential'), 'confidential');
return $select->show(null);
}
/**
* Render HTML form for alarm configuration
*/
function alarm_select($attrib = array())
{
return $this->cal->lib->alarm_select($attrib, $this->cal->driver->alarm_types, $this->cal->driver->alarm_absolute);
}
/**
*
*/
function edit_attendees_notify($attrib = array())
{
$checkbox = new html_checkbox(array('name' => '_notify', 'id' => 'edit-attendees-donotify', 'value' => 1));
return html::div($attrib, html::label(null, $checkbox->show(1) . ' ' . $this->cal->gettext('sendnotifications')));
}
/**
* Generate the form for recurrence settings
*/
function recurring_event_warning($attrib = array())
{
$attrib['id'] = 'edit-recurring-warning';
$radio = new html_radiobutton(array('name' => '_savemode', 'class' => 'edit-recurring-savemode'));
$form = html::label(null, $radio->show('', array('value' => 'current')) . $this->cal->gettext('currentevent')) . ' ' .
html::label(null, $radio->show('', array('value' => 'future')) . $this->cal->gettext('futurevents')) . ' ' .
html::label(null, $radio->show('all', array('value' => 'all')) . $this->cal->gettext('allevents')) . ' ' .
html::label(null, $radio->show('', array('value' => 'new')) . $this->cal->gettext('saveasnew'));
return html::div($attrib, html::div('message', html::span('ui-icon ui-icon-alert', '') . $this->cal->gettext('changerecurringeventwarning')) . html::div('savemode', $form));
}
/**
* Form for uploading and importing events
*/
function events_import_form($attrib = array())
{
if (!$attrib['id'])
$attrib['id'] = 'rcmImportForm';
// Get max filesize, enable upload progress bar
$max_filesize = rcube_upload_init();
$accept = '.ics, text/calendar, text/x-vcalendar, application/ics';
if (class_exists('ZipArchive', false)) {
$accept .= ', .zip, application/zip';
}
$input = new html_inputfield(array(
'type' => 'file', 'name' => '_data', 'size' => $attrib['uploadfieldsize'],
'accept' => $accept));
$select = new html_select(array('name' => '_range', 'id' => 'event-import-range'));
$select->add(array(
$this->cal->gettext('onemonthback'),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>2))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>3))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>6))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>12))),
$this->cal->gettext('all'),
),
array('1','2','3','6','12',0));
$html .= html::div('form-section',
html::div(null, $input->show()) .
html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))))
);
$html .= html::div('form-section',
html::label('event-import-calendar', $this->cal->gettext('calendar')) .
$this->calendar_select(array('name' => 'calendar', 'id' => 'event-import-calendar'))
);
$html .= html::div('form-section',
html::label('event-import-range', $this->cal->gettext('importrange')) .
$select->show(1)
);
$this->rc->output->add_gui_object('importform', $attrib['id']);
$this->rc->output->add_label('import');
return html::tag('form', array('action' => $this->rc->url(array('task' => 'calendar', 'action' => 'import_events')),
'method' => "post", 'enctype' => 'multipart/form-data', 'id' => $attrib['id']),
$html
);
}
/**
* Form to select options for exporting events
*/
function events_export_form($attrib = array())
{
if (!$attrib['id'])
$attrib['id'] = 'rcmExportForm';
$html .= html::div('form-section',
html::label('event-export-calendar', $this->cal->gettext('calendar')) .
$this->calendar_select(array('name' => 'calendar', 'id' => 'event-export-calendar'))
);
$select = new html_select(array('name' => 'range', 'id' => 'event-export-range'));
$select->add(array(
$this->cal->gettext('all'),
$this->cal->gettext('onemonthback'),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>2))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>3))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>6))),
$this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>12))),
$this->cal->gettext('customdate'),
),
array(0,'1','2','3','6','12','custom'));
$startdate = new html_inputfield(array('name' => 'start', 'size' => 11, 'id' => 'event-export-startdate'));
$html .= html::div('form-section',
html::label('event-export-range', $this->cal->gettext('exportrange')) .
$select->show(0) .
html::span(array('style'=>'display:none'), $startdate->show())
);
$checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'event-export-attachments', 'value' => 1));
$html .= html::div('form-section',
html::label('event-export-range', $this->cal->gettext('exportattachments')) .
$checkbox->show(1)
);
$this->rc->output->add_gui_object('exportform', $attrib['id']);
return html::tag('form', array('action' => $this->rc->url(array('task' => 'calendar', 'action' => 'export_events')),
'method' => "post", 'id' => $attrib['id']),
$html
);
}
/**
* Generate the form for event attachments upload
*/
function attachments_form($attrib = array())
{
// add ID if not given
if (!$attrib['id'])
$attrib['id'] = 'rcmUploadForm';
// Get max filesize, enable upload progress bar
$max_filesize = rcube_upload_init();
$button = new html_inputfield(array('type' => 'button'));
$input = new html_inputfield(array(
'type' => 'file', 'name' => '_attachments[]',
'multiple' => 'multiple', 'size' => $attrib['attachmentfieldsize']));
return html::div($attrib,
html::div(null, $input->show()) .
html::div('formbuttons', $button->show(rcube_label('upload'), array('class' => 'button mainaction',
'onclick' => JS_OBJECT_NAME . ".upload_file(this.form)"))) .
html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))))
);
}
/**
* Register UI object for HTML5 drag & drop file upload
*/
function file_drop_area($attrib = array())
{
if ($attrib['id']) {
$this->rc->output->add_gui_object('filedrop', $attrib['id']);
$this->rc->output->set_env('filedrop', array('action' => 'upload', 'fieldname' => '_attachments'));
}
}
/**
* Generate HTML element for attachments list
*/
function attachments_list($attrib = array())
{
if (!$attrib['id'])
$attrib['id'] = 'rcmAttachmentList';
$skin_path = $this->cal->local_skin_path();
if ($attrib['deleteicon']) {
$_SESSION[calendar::SESSION_KEY . '_deleteicon'] = $skin_path . $attrib['deleteicon'];
$this->rc->output->set_env('deleteicon', $skin_path . $attrib['deleteicon']);
}
if ($attrib['cancelicon'])
$this->rc->output->set_env('cancelicon', $skin_path . $attrib['cancelicon']);
if ($attrib['loadingicon'])
$this->rc->output->set_env('loadingicon', $skin_path . $attrib['loadingicon']);
$this->rc->output->add_gui_object('attachmentlist', $attrib['id']);
$this->attachmentlist_id = $attrib['id'];
return html::tag('ul', $attrib, '', html::$common_attrib);
}
/**
* Handler for calendar form template.
* The form content could be overriden by the driver
*/
function calendar_editform($action, $calendar = array())
{
// compose default calendar form fields
$input_name = new html_inputfield(array('name' => 'name', 'id' => 'calendar-name', 'size' => 20));
$input_color = new html_inputfield(array('name' => 'color', 'id' => 'calendar-color', 'size' => 6));
$formfields = array(
'name' => array(
'label' => $this->cal->gettext('name'),
'value' => $input_name->show($calendar['name']),
'id' => 'calendar-name',
),
'color' => array(
'label' => $this->cal->gettext('color'),
'value' => $input_color->show($calendar['color']),
'id' => 'calendar-color',
),
);
if ($this->cal->driver->alarms) {
$checkbox = new html_checkbox(array('name' => 'showalarms', 'id' => 'calendar-showalarms', 'value' => 1));
$formfields['showalarms'] = array(
'label' => $this->cal->gettext('showalarms'),
'value' => $checkbox->show($calendar['showalarms']?1:0),
'id' => 'calendar-showalarms',
);
}
// allow driver to extend or replace the form content
return html::tag('form', array('action' => "#", 'method' => "get", 'id' => 'calendarpropform'),
$this->cal->driver->calendar_form($action, $calendar, $formfields)
);
}
/**
*
*/
function attendees_list($attrib = array())
{
// add "noreply" checkbox to attendees table only
$invitations = strpos($attrib['id'], 'attend') !== false;
$invite = new html_checkbox(array('value' => 1, 'id' => 'edit-attendees-invite'));
$table = new html_table(array('cols' => 5 + intval($invitations), 'border' => 0, 'cellpadding' => 0, 'class' => 'rectable'));
$table->add_header('role', $this->cal->gettext('role'));
$table->add_header('name', $this->cal->gettext($attrib['coltitle'] ?: 'attendee'));
$table->add_header('availability', $this->cal->gettext('availability'));
$table->add_header('confirmstate', $this->cal->gettext('confirmstate'));
if ($invitations) {
$table->add_header(array('class' => 'invite', 'title' => $this->cal->gettext('sendinvitations')),
$invite->show(1) . html::label('edit-attendees-invite', $this->cal->gettext('sendinvitations')));
}
$table->add_header('options', '');
// hide invite column if disabled by config
$itip_notify = (int)$this->rc->config->get('calendar_itip_send_option', $this->cal->defaults['calendar_itip_send_option']);
if ($invitations && !($itip_notify & 2)) {
$css = sprintf('#%s td.invite, #%s th.invite { display:none !important }', $attrib['id'], $attrib['id']);
$this->rc->output->add_footer(html::tag('style', array('type' => 'text/css'), $css));
}
return $table->show($attrib);
}
/**
*
*/
function attendees_form($attrib = array())
{
$input = new html_inputfield(array('name' => 'participant', 'id' => 'edit-attendee-name', 'size' => 30));
$textarea = new html_textarea(array('name' => 'comment', 'id' => 'edit-attendees-comment',
'rows' => 4, 'cols' => 55, 'title' => $this->cal->gettext('itipcommenttitle')));
return html::div($attrib,
html::div(null, $input->show() . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-add', 'value' => $this->cal->gettext('addattendee'))) . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-schedule', 'value' => $this->cal->gettext('scheduletime').'...'))) .
html::p('attendees-commentbox', html::label(null, $this->cal->gettext('itipcomment') . $textarea->show()))
);
}
/**
*
*/
function resources_form($attrib = array())
{
$input = new html_inputfield(array('name' => 'resource', 'id' => 'edit-resource-name', 'size' => 30));
return html::div($attrib,
html::div(null, $input->show() . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-resource-add', 'value' => $this->cal->gettext('addresource'))) . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-resource-find', 'value' => $this->cal->gettext('findresources').'...')))
);
}
/**
*
*/
function resources_list($attrib = array())
{
$attrib += array('id' => 'calendar-resources-list');
$this->rc->output->add_gui_object('resourceslist', $attrib['id']);
return html::tag('ul', $attrib, '', html::$common_attrib);
}
/**
*
*/
public function resource_info($attrib = array())
{
$attrib += array('id' => 'calendar-resources-info');
$this->rc->output->add_gui_object('resourceinfo', $attrib['id']);
$this->rc->output->add_gui_object('resourceownerinfo', $attrib['id'] . '-owner');
// copy address book labels for owner details to client
$this->rc->output->add_label('name','firstname','surname','department','jobtitle','email','phone','address');
$table_attrib = array('id','class','style','width','summary','cellpadding','cellspacing','border');
return html::tag('table', $attrib,
html::tag('tbody', null, ''), $table_attrib) .
html::tag('table', array('id' => $attrib['id'] . '-owner', 'style' => 'display:none') + $attrib,
html::tag('thead', null,
html::tag('tr', null,
html::tag('td', array('colspan' => 2), Q($this->cal->gettext('resourceowner')))
)
) .
html::tag('tbody', null, ''),
$table_attrib);
}
/**
*
*/
public function resource_calendar($attrib = array())
{
$attrib += array('id' => 'calendar-resources-calendar');
$this->rc->output->add_gui_object('resourceinfocalendar', $attrib['id']);
return html::div($attrib, '');
}
/**
* GUI object 'searchform' for the resource finder dialog
*
* @param array Named parameters
* @return string HTML code for the gui object
*/
function resources_search_form($attrib)
{
$attrib += array('command' => 'search-resource', 'id' => 'rcmcalresqsearchbox', 'autocomplete' => 'off');
$attrib['name'] = '_q';
$input_q = new html_inputfield($attrib);
$out = $input_q->show();
// add form tag around text field
$out = $this->rc->output->form_tag(array(
'name' => "rcmcalresoursqsearchform",
'onsubmit' => rcmail_output::JS_OBJECT_NAME . ".command('" . $attrib['command'] . "'); return false",
'style' => "display:inline"),
$out);
return $out;
}
/**
*
*/
function attendees_freebusy_table($attrib = array())
{
$table = new html_table(array('cols' => 2, 'border' => 0, 'cellspacing' => 0));
$table->add('attendees',
html::tag('h3', 'boxtitle', $this->cal->gettext('tabattendees')) .
html::div('timesheader', '&nbsp;') .
html::div(array('id' => 'schedule-attendees-list', 'class' => 'attendees-list'), '')
);
$table->add('times',
html::div('scroll',
html::tag('table', array('id' => 'schedule-freebusy-times', 'border' => 0, 'cellspacing' => 0), html::tag('thead') . html::tag('tbody')) .
html::div(array('id' => 'schedule-event-time', 'style' => 'display:none'), '&nbsp;')
)
);
return $table->show($attrib);
}
/**
* Table oultine for event changelog display
*/
function event_changelog_table($attrib = array())
{
$table = new html_table(array('cols' => 5, 'border' => 0, 'cellspacing' => 0));
$table->add_header('diff', '');
$table->add_header('revision', $this->cal->gettext('revision'));
$table->add_header('date', $this->cal->gettext('date'));
$table->add_header('user', $this->cal->gettext('user'));
$table->add_header('operation', $this->cal->gettext('operation'));
$table->add_header('actions', '&nbsp;');
return $table->show($attrib);
}
/**
*
*/
function event_invitebox($attrib = array())
{
if ($this->cal->event) {
return html::div($attrib,
$this->cal->itip->itip_object_details_table($this->cal->event, $this->cal->itip->gettext('itipinvitation')) .
$this->cal->invitestatus
);
}
return '';
}
function event_rsvp_buttons($attrib = array())
{
return $this->cal->itip->itip_rsvp_buttons($attrib, array('accepted','tentative','declined','delegated'));
}
}
diff --git a/plugins/kolab_addressbook/lib/kolab_addressbook_ui.php b/plugins/kolab_addressbook/lib/kolab_addressbook_ui.php
index e8115322..65476488 100644
--- a/plugins/kolab_addressbook/lib/kolab_addressbook_ui.php
+++ b/plugins/kolab_addressbook/lib/kolab_addressbook_ui.php
@@ -1,303 +1,303 @@
<?php
/**
* Kolab address book UI
*
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class kolab_addressbook_ui
{
private $plugin;
private $rc;
/**
* Class constructor
*
* @param kolab_addressbook $plugin Plugin object
*/
public function __construct($plugin)
{
$this->rc = rcube::get_instance();
$this->plugin = $plugin;
$this->init_ui();
}
/**
* Adds folders management functionality to Addressbook UI
*/
private function init_ui()
{
if (!empty($this->rc->action) && !preg_match('/^plugin\.book/', $this->rc->action)) {
return;
}
// Include script
$this->plugin->include_script('kolab_addressbook.js');
if (empty($this->rc->action)) {
// Include stylesheet (for directorylist)
$this->plugin->include_stylesheet($this->plugin->local_skin_path().'/kolab_addressbook.css');
// include kolab folderlist widget if available
- if (is_readable($this->plugin->api->dir . 'libkolab/js/folderlist.js')) {
+ if (in_array('libkolab', $this->plugin->api->loaded_plugins())) {
$this->plugin->api->include_script('libkolab/js/folderlist.js');
}
// Add actions on address books
$options = array('book-create', 'book-edit', 'book-delete', 'book-remove');
$idx = 0;
if ($this->rc->config->get('kolab_addressbook_carddav_url')) {
$options[] = 'book-showurl';
$this->rc->output->set_env('kolab_addressbook_carddav_url', true);
}
foreach ($options as $command) {
$content = html::tag('li', $idx ? null : array('class' => 'separator_above'),
$this->plugin->api->output->button(array(
'label' => 'kolab_addressbook.'.str_replace('-', '', $command),
'domain' => $this->ID,
'classact' => 'active',
'command' => $command
)));
$this->plugin->api->add_content($content, 'groupoptions');
$idx++;
}
// Link to Settings/Folders
$content = html::tag('li', array('class' => 'separator_above'),
$this->plugin->api->output->button(array(
'label' => 'managefolders',
'type' => 'link',
'classact' => 'active',
'command' => 'folders',
'task' => 'settings',
)));
$this->plugin->api->add_content($content, 'groupoptions');
$this->rc->output->add_label('kolab_addressbook.bookdeleteconfirm',
'kolab_addressbook.bookdeleting', 'kolab_addressbook.bookshowurl',
'kolab_addressbook.carddavurldescription',
'kolab_addressbook.bookedit',
'kolab_addressbook.bookdelete',
'kolab_addressbook.bookshowurl',
'kolab_addressbook.findaddressbooks',
'kolab_addressbook.searchterms',
'kolab_addressbook.foldersearchform',
'kolab_addressbook.listsearchresults',
'kolab_addressbook.nraddressbooksfound',
'kolab_addressbook.noaddressbooksfound',
'kolab_addressbook.foldersubscribe',
'resetsearch');
}
// book create/edit form
else {
$this->rc->output->add_label('kolab_addressbook.nobooknamewarning',
'kolab_addressbook.booksaving');
}
}
/**
* Handler for address book create/edit action
*/
public function book_edit()
{
$this->rc->output->add_handler('bookdetails', array($this, 'book_form'));
$this->rc->output->send('kolab_addressbook.bookedit');
}
/**
* Handler for 'bookdetails' object returning form content for book create/edit
*
* @param array $attr Object attributes
*
* @return string HTML output
*/
public function book_form($attrib)
{
$action = trim(rcube_utils::get_input_value('_act', rcube_utils::INPUT_GPC));
$folder = trim(rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC, true)); // UTF8
$hidden_fields[] = array('name' => '_source', 'value' => $folder);
$folder = rcube_charset::convert($folder, RCMAIL_CHARSET, 'UTF7-IMAP');
$storage = $this->rc->get_storage();
$delim = $storage->get_hierarchy_delimiter();
if ($this->rc->action == 'plugin.book-save') {
// save error
$name = trim(rcube_utils::get_input_value('_name', rcube_utils::INPUT_GPC, true)); // UTF8
$old = trim(rcube_utils::get_input_value('_oldname', rcube_utils::INPUT_GPC, true)); // UTF7-IMAP
$path_imap = trim(rcube_utils::get_input_value('_parent', rcube_utils::INPUT_GPC, true)); // UTF7-IMAP
$hidden_fields[] = array('name' => '_oldname', 'value' => $old);
$folder = $old;
}
else if ($action == 'edit') {
$path_imap = explode($delim, $folder);
$name = rcube_charset::convert(array_pop($path_imap), 'UTF7-IMAP');
$path_imap = implode($path_imap, $delim);
}
else { // create
$path_imap = $folder;
$name = '';
$folder = '';
}
// Store old name, get folder options
if (strlen($folder)) {
$hidden_fields[] = array('name' => '_oldname', 'value' => $folder);
$options = $storage->folder_info($folder);
}
$form = array();
// General tab
$form['props'] = array(
'name' => $this->rc->gettext('properties'),
);
if (!empty($options) && ($options['norename'] || $options['protected'])) {
$foldername = Q(str_replace($delim, ' &raquo; ', kolab_storage::object_name($folder)));
}
else {
$foldername = new html_inputfield(array('name' => '_name', 'id' => '_name', 'size' => 30));
$foldername = $foldername->show($name);
}
$form['props']['fieldsets']['location'] = array(
'name' => $this->rc->gettext('location'),
'content' => array(
'name' => array(
'label' => $this->plugin->gettext('bookname'),
'value' => $foldername,
),
),
);
if (!empty($options) && ($options['norename'] || $options['protected'])) {
// prevent user from moving folder
$hidden_fields[] = array('name' => '_parent', 'value' => $path_imap);
}
else {
$select = kolab_storage::folder_selector('contact', array('name' => '_parent'), $folder);
$form['props']['fieldsets']['location']['content']['path'] = array(
'label' => $this->plugin->gettext('parentbook'),
'value' => $select->show(strlen($folder) ? $path_imap : ''),
);
}
// Allow plugins to modify address book form content (e.g. with ACL form)
$plugin = $this->rc->plugins->exec_hook('addressbook_form',
array('form' => $form, 'options' => $options, 'name' => $folder));
$form = $plugin['form'];
// Set form tags and hidden fields
list($form_start, $form_end) = $this->get_form_tags($attrib, 'plugin.book-save', null, $hidden_fields);
unset($attrib['form']);
// return the complete edit form as table
$out = "$form_start\n";
// Create form output
foreach ($form as $tab) {
if (!empty($tab['fieldsets']) && is_array($tab['fieldsets'])) {
$content = '';
foreach ($tab['fieldsets'] as $fieldset) {
$subcontent = $this->get_form_part($fieldset);
if ($subcontent) {
$content .= html::tag('fieldset', null, html::tag('legend', null, Q($fieldset['name'])) . $subcontent) ."\n";
}
}
}
else {
$content = $this->get_form_part($tab);
}
if ($content) {
$out .= html::tag('fieldset', null, html::tag('legend', null, Q($tab['name'])) . $content) ."\n";
}
}
$out .= "\n$form_end";
return $out;
}
private function get_form_part($form)
{
$content = '';
if (is_array($form['content']) && !empty($form['content'])) {
$table = new html_table(array('cols' => 2, 'class' => 'propform'));
foreach ($form['content'] as $col => $colprop) {
$colprop['id'] = '_'.$col;
$label = !empty($colprop['label']) ? $colprop['label'] : rcube_label($col);
$table->add('title', sprintf('<label for="%s">%s</label>', $colprop['id'], Q($label)));
$table->add(null, $colprop['value']);
}
$content = $table->show();
}
else {
$content = $form['content'];
}
return $content;
}
private function get_form_tags($attrib, $action, $id = null, $hidden = null)
{
$form_start = $form_end = '';
$request_key = $action . (isset($id) ? '.'.$id : '');
$form_start = $this->rc->output->request_form(array(
'name' => 'form',
'method' => 'post',
'task' => $this->rc->task,
'action' => $action,
'request' => $request_key,
'noclose' => true,
) + $attrib);
if (is_array($hidden)) {
foreach ($hidden as $field) {
$hiddenfield = new html_hiddenfield($field);
$form_start .= $hiddenfield->show();
}
}
$form_end = !strlen($attrib['form']) ? '</form>' : '';
$EDIT_FORM = !empty($attrib['form']) ? $attrib['form'] : 'form';
$this->rc->output->add_gui_object('editform', $EDIT_FORM);
return array($form_start, $form_end);
}
}
diff --git a/plugins/kolab_notes/kolab_notes_ui.php b/plugins/kolab_notes/kolab_notes_ui.php
index 8c099898..c03ea2db 100644
--- a/plugins/kolab_notes/kolab_notes_ui.php
+++ b/plugins/kolab_notes/kolab_notes_ui.php
@@ -1,438 +1,438 @@
<?php
class kolab_notes_ui
{
private $rc;
private $plugin;
private $ready = false;
function __construct($plugin)
{
$this->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',
), 'taskbar');
$this->plugin->include_stylesheet($this->plugin->local_skin_path() . '/notes.css');
$this->plugin->register_action('print', array($this, 'print_template'));
$this->plugin->register_action('folder-acl', array($this, 'folder_acl'));
$this->ready = true;
}
/**
* Register handler methods for the template engine
*/
public function init_templates()
{
$this->plugin->register_handler('plugin.tagslist', array($this, 'tagslist'));
$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->rc->output->include_script('list.js');
$this->rc->output->include_script('treelist.js');
$this->plugin->include_script('notes.js');
$this->plugin->include_script('jquery.tagedit.js');
// include kolab folderlist widget if available
- if (is_readable($this->plugin->api->dir . 'libkolab/js/folderlist.js')) {
+ if (in_array('libkolab', $this->plugin->api->loaded_plugins())) {
$this->plugin->api->include_script('libkolab/js/folderlist.js');
}
$this->plugin->include_stylesheet($this->plugin->local_skin_path() . '/tagedit.css');
// load config options and user prefs relevant for the UI
$settings = array(
'sort_col' => $this->rc->config->get('kolab_notes_sort_col', 'changed'),
'print_template' => $this->rc->url('print'),
);
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;
}
$lang_codes = array($_SESSION['language']);
if ($pos = strpos($_SESSION['language'], '_')) {
$lang_codes[] = substr($_SESSION['language'], 0, $pos);
}
foreach ($lang_codes as $code) {
if (file_exists(INSTALL_PATH . "program/js/tinymce/langs/$code.js")) {
$lang = $code;
break;
}
}
if (empty($lang)) {
$lang = 'en';
}
$settings['editor'] = array(
'lang' => $lang,
'spellcheck' => intval($this->rc->config->get('enable_spellcheck')),
'spelldict' => intval($this->rc->config->get('spellcheck_dictionary'))
);
$this->rc->output->set_env('kolab_notes_settings', $settings);
$this->rc->output->add_label('save','cancel','delete');
}
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']) {
$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 <ul> 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, RCMAIL_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('ul', $attrib, '', html::$common_attrib);
}
public function tagslist($attrib)
{
$attrib += array('id' => 'rcmkolabnotestagslist');
$this->rc->output->add_gui_object('notestagslist', $attrib['id']);
return html::tag('ul', $attrib, '', html::$common_attrib);
}
public function editform($attrib)
{
$attrib += array('action' => '#', 'id' => 'rcmkolabnoteseditform');
$this->rc->output->add_gui_object('noteseditform', $attrib['id']);
$this->rc->output->include_script('tinymce/tinymce.min.js');
$textarea = new html_textarea(array('name' => 'content', 'id' => 'notecontent', 'cols' => 60, 'rows' => 20, 'tabindex' => 0));
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', 'size' => 60, 'tabindex' => 0));
$html = $summary->show();
$html .= html::div(array('class' => 'tagline tagedit', 'style' => 'display:none'), '&nbsp;');
$html .= html::div(array('class' => 'dates', 'style' => 'display:none'),
html::label(array(), $this->plugin->gettext('created')) .
html::span('notecreated', '') .
html::label(array(), $this->plugin->gettext('changed')) .
html::span('notechanged', '')
);
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 edit for notes lists (folders)
*/
public function list_editform($action, $list, $folder)
{
if (is_object($folder)) {
$folder_name = $folder->name; // UTF7
}
else {
$folder_name = '';
}
$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($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 ($action != 'form-new') {
$form['sharing'] = array(
'name' => Q($this->plugin->gettext('tabsharing')),
'content' => html::tag('iframe', array(
'src' => $this->rc->url(array('_action' => 'folder-acl', '_folder' => $folder_name, 'framed' => 1)),
'width' => '100%',
'height' => 280,
'border' => 0,
'style' => 'border:0'),
'')
);
}
$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));
foreach ($tab['fields'] as $col => $colprop) {
$label = !empty($colprop['label']) ? $colprop['label'] : $this->plugin->gettext($col);
$table->add('title', html::label($colprop['id'], 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, Q($tab['name'])) . $content) . "\n";
}
}
return html::tag('form', array('action' => "#", 'method' => "post", 'id' => "noteslistpropform"), $form_html);
}
/**
* Handler to render ACL form for a notes folder
*/
public function folder_acl()
{
$this->plugin->require_plugin('acl');
$this->rc->output->add_handler('folderacl', array($this, 'folder_acl_form'));
$this->rc->output->send('kolab_notes.kolabacl');
}
/**
* Handler for ACL form template object
*/
public function folder_acl_form()
{
$folder = rcube_utils::get_input_value('_folder', rcube_utils::INPUT_GPC);
if (strlen($folder)) {
$storage = $this->rc->get_storage();
$options = $storage->folder_info($folder);
// get sharing UI from acl plugin
$acl = $this->rc->plugins->exec_hook('folder_form',
array('form' => array(), 'options' => $options, 'name' => $folder));
}
return $acl['form']['sharing']['content'] ?: html::div('hint', $this->plugin->gettext('aclnorights'));
}
/**
* Render the template for printing with placeholders
*/
public function print_template()
{
header('Content-Type: text/html; charset=' . RCUBE_CHARSET);
$this->rc->output->reset(true);
echo $this->rc->output->parse('kolab_notes.print', false, false);
exit;
}
}
diff --git a/plugins/tasklist/tasklist_ui.php b/plugins/tasklist/tasklist_ui.php
index 32584184..922f2954 100644
--- a/plugins/tasklist/tasklist_ui.php
+++ b/plugins/tasklist/tasklist_ui.php
@@ -1,532 +1,532 @@
<?php
/**
* User Interface class for the Tasklist plugin
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class 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) // already done
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',
), 'taskbar');
$this->plugin->include_stylesheet($this->plugin->local_skin_path() . '/tasklist.css');
$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.tagslist', array($this, 'tagslist'));
$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.attachments_form', array($this, 'attachments_form'));
$this->plugin->register_handler('plugin.attachments_list', array($this, 'attachments_list'));
$this->plugin->register_handler('plugin.filedroparea', array($this, 'file_drop_area'));
$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->include_script('jquery.tagedit.js');
$this->plugin->include_script('tasklist.js');
$this->rc->output->include_script('treelist.js');
// include kolab folderlist widget if available
- if (is_readable($this->plugin->api->dir . 'libkolab/js/folderlist.js')) {
+ if (in_array('libkolab', $this->plugin->api->loaded_plugins())) {
$this->plugin->api->include_script('libkolab/js/folderlist.js');
}
$this->plugin->include_stylesheet($this->plugin->local_skin_path() . '/tagedit.css');
}
/**
*
*/
public function tasklists($attrib = array())
{
$tree = true;
$jsenv = array();
$lists = $this->plugin->driver->get_lists($tree);
// 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->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 <ul> for the folder tree
*/
public function list_tree_html($node, $data, &$jsenv, $attrib)
{
$out = '';
foreach ($node->children as $folder) {
$id = $folder->id;
$prop = $data[$id];
$is_collapsed = false; // TODO: determine this somehow?
$content = $this->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;
$jsenv[$id] = $prop;
}
$classes = array('tasklist');
$title = $prop['title'] ?: ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ?
html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET) : '');
if ($prop['virtual'])
$classes[] = 'virtual';
else if (!$prop['editable'])
$classes[] = 'readonly';
if ($prop['subscribed'])
$classes[] = 'subscribed';
if ($prop['class'])
$classes[] = $prop['class'];
if (!$activeonly || $prop['active']) {
$label_id = 'tl:' . $id;
return html::div(join(' ', $classes),
html::span(array('class' => 'listname', 'title' => $title, 'id' => $label_id), $prop['listname'] ?: $prop['name']) .
($prop['virtual'] ? '' :
html::tag('input', array('type' => 'checkbox', 'name' => '_list[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id)) .
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())
{
$attrib['name'] = 'list';
$attrib['is_escaped'] = true;
$select = new html_select($attrib);
$default = null;
foreach ((array)$this->plugin->driver->get_lists() as $id => $prop) {
if ($prop['editable']) {
$select->add($prop['name'], $id);
if (!$default || $prop['default'])
$default = $id;
}
}
return $select->show($default);
}
function tasklist_editform($action, $list = array())
{
$fields = array(
'name' => array(
'id' => 'taskedit-tasklistame',
'label' => $this->plugin->gettext('listname'),
'value' => html::tag('input', array('id' => 'taskedit-tasklistame', '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', array('action' => "#", 'method' => "post", 'id' => 'tasklisteditform'),
$this->plugin->driver->tasklist_edit_form($action, $list, $fields)
);
}
/**
* Render HTML form for alarm configuration
*/
function alarm_select($attrib = array())
{
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, '');
}
/**
* Container for a tags cloud
*/
function tagslist($attrib)
{
$attrib += array('id' => 'rcmtasktagslist');
unset($attrib['name']);
$this->register_gui_object('tagslist', $attrib['id']);
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(''));
}
/**
* Generate HTML element for attachments list
*/
function attachments_list($attrib = array())
{
if (!$attrib['id'])
$attrib['id'] = 'rcmtaskattachmentlist';
$this->register_gui_object('attachmentlist', $attrib['id']);
return html::tag('ul', $attrib, '', html::$common_attrib);
}
/**
* Generate the form for event attachments upload
*/
function attachments_form($attrib = array())
{
// add ID if not given
if (!$attrib['id'])
$attrib['id'] = 'rcmtaskuploadform';
// Get max filesize, enable upload progress bar
$max_filesize = rcube_upload_init();
$button = new html_inputfield(array('type' => 'button'));
$input = new html_inputfield(array(
'type' => 'file',
'name' => '_attachments[]',
'multiple' => 'multiple',
'size' => $attrib['attachmentfieldsize'],
));
return html::div($attrib,
html::div(null, $input->show()) .
html::div('formbuttons', $button->show(rcube_label('upload'), array('class' => 'button mainaction',
'onclick' => JS_OBJECT_NAME . ".upload_file(this.form)"))) .
html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))))
);
}
/**
* Register UI object for HTML5 drag & drop file upload
*/
function file_drop_area($attrib = array())
{
if ($attrib['id']) {
$this->register_gui_object('filedrop', $attrib['id']);
$this->rc->output->set_env('filedrop', array('action' => 'upload', 'fieldname' => '_attachments'));
}
}
/**
*
*/
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', $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' => 30));
$textarea = new html_textarea(array('name' => 'comment', 'id' => 'edit-attendees-comment',
'rows' => 4, 'cols' => 55, 'title' => $this->plugin->gettext('itipcommenttitle')));
return html::div($attrib,
html::div(null, $input->show() . " " .
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-add', 'value' => $this->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(null, $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));
return html::div($attrib, html::label(null, $checkbox->show(1) . ' ' . $this->plugin->gettext('sendnotifications')));
}
/**
* 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;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jun 9, 7:01 PM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
196835
Default Alt Text
(82 KB)

Event Timeline