Mercurial > hg > rc1
comparison plugins/calendar/lib/calendar_ui.php @ 3:f6fe4b6ae66a
calendar plugin nearly as distributed
| author | Charlie Root |
|---|---|
| date | Sat, 13 Jan 2018 08:56:12 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 2:c828b0fd4a6e | 3:f6fe4b6ae66a |
|---|---|
| 1 <?php | |
| 2 /** | |
| 3 * User Interface class for the Calendar plugin | |
| 4 * | |
| 5 * @author Lazlo Westerhof <hello@lazlo.me> | |
| 6 * @author Thomas Bruederli <bruederli@kolabsys.com> | |
| 7 * | |
| 8 * Copyright (C) 2010, Lazlo Westerhof <hello@lazlo.me> | |
| 9 * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com> | |
| 10 * | |
| 11 * This program is free software: you can redistribute it and/or modify | |
| 12 * it under the terms of the GNU Affero General Public License as | |
| 13 * published by the Free Software Foundation, either version 3 of the | |
| 14 * License, or (at your option) any later version. | |
| 15 * | |
| 16 * This program is distributed in the hope that it will be useful, | |
| 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 19 * GNU Affero General Public License for more details. | |
| 20 * | |
| 21 * You should have received a copy of the GNU Affero General Public License | |
| 22 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 23 */ | |
| 24 | |
| 25 | |
| 26 class calendar_ui | |
| 27 { | |
| 28 private $rc; | |
| 29 private $cal; | |
| 30 private $ready = false; | |
| 31 public $screen; | |
| 32 | |
| 33 function __construct($cal) | |
| 34 { | |
| 35 $this->cal = $cal; | |
| 36 $this->rc = $cal->rc; | |
| 37 $this->screen = $this->rc->task == 'calendar' ? ($this->rc->action ? $this->rc->action: 'calendar') : 'other'; | |
| 38 } | |
| 39 | |
| 40 /** | |
| 41 * Calendar UI initialization and requests handlers | |
| 42 */ | |
| 43 public function init() | |
| 44 { | |
| 45 if ($this->ready) // already done | |
| 46 return; | |
| 47 | |
| 48 // add taskbar button | |
| 49 $this->cal->add_button(array( | |
| 50 'command' => 'calendar', | |
| 51 'class' => 'button-calendar', | |
| 52 'classsel' => 'button-calendar button-selected', | |
| 53 'innerclass' => 'button-inner', | |
| 54 'label' => 'calendar.calendar', | |
| 55 'type' => 'link' | |
| 56 ), 'taskbar'); | |
| 57 | |
| 58 // load basic client script | |
| 59 $this->cal->include_script('calendar_base.js'); | |
| 60 | |
| 61 $skin_path = $this->cal->local_skin_path(); | |
| 62 $this->cal->include_stylesheet($skin_path . '/calendar.css'); | |
| 63 | |
| 64 $this->ready = true; | |
| 65 } | |
| 66 | |
| 67 /** | |
| 68 * Register handler methods for the template engine | |
| 69 */ | |
| 70 public function init_templates() | |
| 71 { | |
| 72 $this->cal->register_handler('plugin.calendar_css', array($this, 'calendar_css')); | |
| 73 $this->cal->register_handler('plugin.calendar_list', array($this, 'calendar_list')); | |
| 74 $this->cal->register_handler('plugin.calendar_select', array($this, 'calendar_select')); | |
| 75 $this->cal->register_handler('plugin.identity_select', array($this, 'identity_select')); | |
| 76 $this->cal->register_handler('plugin.category_select', array($this, 'category_select')); | |
| 77 $this->cal->register_handler('plugin.status_select', array($this, 'status_select')); | |
| 78 $this->cal->register_handler('plugin.freebusy_select', array($this, 'freebusy_select')); | |
| 79 $this->cal->register_handler('plugin.priority_select', array($this, 'priority_select')); | |
| 80 $this->cal->register_handler('plugin.sensitivity_select', array($this, 'sensitivity_select')); | |
| 81 $this->cal->register_handler('plugin.alarm_select', array($this, 'alarm_select')); | |
| 82 $this->cal->register_handler('plugin.recurrence_form', array($this->cal->lib, 'recurrence_form')); | |
| 83 $this->cal->register_handler('plugin.attachments_form', array($this, 'attachments_form')); | |
| 84 $this->cal->register_handler('plugin.attachments_list', array($this, 'attachments_list')); | |
| 85 $this->cal->register_handler('plugin.filedroparea', array($this, 'file_drop_area')); | |
| 86 $this->cal->register_handler('plugin.attendees_list', array($this, 'attendees_list')); | |
| 87 $this->cal->register_handler('plugin.attendees_form', array($this, 'attendees_form')); | |
| 88 $this->cal->register_handler('plugin.resources_form', array($this, 'resources_form')); | |
| 89 $this->cal->register_handler('plugin.resources_list', array($this, 'resources_list')); | |
| 90 $this->cal->register_handler('plugin.resources_searchform', array($this, 'resources_search_form')); | |
| 91 $this->cal->register_handler('plugin.resource_info', array($this, 'resource_info')); | |
| 92 $this->cal->register_handler('plugin.resource_calendar', array($this, 'resource_calendar')); | |
| 93 $this->cal->register_handler('plugin.attendees_freebusy_table', array($this, 'attendees_freebusy_table')); | |
| 94 $this->cal->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify')); | |
| 95 $this->cal->register_handler('plugin.edit_recurring_warning', array($this, 'recurring_event_warning')); | |
| 96 $this->cal->register_handler('plugin.event_rsvp_buttons', array($this, 'event_rsvp_buttons')); | |
| 97 $this->cal->register_handler('plugin.angenda_options', array($this, 'angenda_options')); | |
| 98 $this->cal->register_handler('plugin.events_import_form', array($this, 'events_import_form')); | |
| 99 $this->cal->register_handler('plugin.events_export_form', array($this, 'events_export_form')); | |
| 100 $this->cal->register_handler('plugin.object_changelog_table', array('libkolab', 'object_changelog_table')); | |
| 101 $this->cal->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template | |
| 102 } | |
| 103 | |
| 104 /** | |
| 105 * Adds CSS stylesheets to the page header | |
| 106 */ | |
| 107 public function addCSS() | |
| 108 { | |
| 109 $skin_path = $this->cal->local_skin_path(); | |
| 110 $this->cal->include_stylesheet($skin_path . '/fullcalendar.css'); | |
| 111 } | |
| 112 | |
| 113 /** | |
| 114 * Adds JS files to the page header | |
| 115 */ | |
| 116 public function addJS() | |
| 117 { | |
| 118 $this->cal->include_script('calendar_ui.js'); | |
| 119 $this->cal->include_script('lib/js/fullcalendar.js'); | |
| 120 $this->rc->output->include_script('treelist.js'); | |
| 121 | |
| 122 // include kolab folderlist widget if available | |
| 123 if (in_array('libkolab', $this->cal->api->loaded_plugins())) { | |
| 124 $this->cal->api->include_script('libkolab/js/folderlist.js'); | |
| 125 $this->cal->api->include_script('libkolab/js/audittrail.js'); | |
| 126 } | |
| 127 | |
| 128 jqueryui::miniColors(); | |
| 129 } | |
| 130 | |
| 131 /** | |
| 132 * | |
| 133 */ | |
| 134 function calendar_css($attrib = array()) | |
| 135 { | |
| 136 $mode = $this->rc->config->get('calendar_event_coloring', $this->cal->defaults['calendar_event_coloring']); | |
| 137 $categories = $this->cal->driver->list_categories(); | |
| 138 $css = "\n"; | |
| 139 | |
| 140 foreach ((array)$categories as $class => $color) { | |
| 141 if (empty($color)) | |
| 142 continue; | |
| 143 | |
| 144 $class = 'cat-' . asciiwords(strtolower($class), true); | |
| 145 $css .= ".$class { color: #$color }\n"; | |
| 146 if ($mode > 0) { | |
| 147 if ($mode == 2) { | |
| 148 $css .= ".fc-event-$class .fc-event-bg {"; | |
| 149 $css .= " opacity: 0.9;"; | |
| 150 $css .= " filter: alpha(opacity=90);"; | |
| 151 } | |
| 152 else { | |
| 153 $css .= ".fc-event-$class.fc-event-skin, "; | |
| 154 $css .= ".fc-event-$class .fc-event-skin, "; | |
| 155 $css .= ".fc-event-$class .fc-event-inner {"; | |
| 156 } | |
| 157 $css .= " background-color: #" . $color . ";"; | |
| 158 if ($mode % 2) | |
| 159 $css .= " border-color: #$color;"; | |
| 160 $css .= "}\n"; | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 $calendars = $this->cal->driver->list_calendars(); | |
| 165 foreach ((array)$calendars as $id => $prop) { | |
| 166 if (!$prop['color']) | |
| 167 continue; | |
| 168 $css .= $this->calendar_css_classes($id, $prop, $mode); | |
| 169 } | |
| 170 | |
| 171 return html::tag('style', array('type' => 'text/css'), $css); | |
| 172 } | |
| 173 | |
| 174 /** | |
| 175 * | |
| 176 */ | |
| 177 public function calendar_css_classes($id, $prop, $mode) | |
| 178 { | |
| 179 $color = $prop['color']; | |
| 180 $class = 'cal-' . asciiwords($id, true); | |
| 181 $css .= "li .$class, #eventshow .$class { color: #$color; }\n"; | |
| 182 | |
| 183 if ($mode != 1) { | |
| 184 if ($mode == 3) { | |
| 185 $css .= ".fc-event-$class .fc-event-bg {"; | |
| 186 $css .= " opacity: 0.9;"; | |
| 187 $css .= " filter: alpha(opacity=90);"; | |
| 188 } | |
| 189 else { | |
| 190 $css .= ".fc-event-$class, "; | |
| 191 $css .= ".fc-event-$class .fc-event-inner {"; | |
| 192 } | |
| 193 if (!$prop['printmode']) | |
| 194 $css .= " background-color: #$color;"; | |
| 195 if ($mode % 2 == 0) | |
| 196 $css .= " border-color: #$color;"; | |
| 197 $css .= "}\n"; | |
| 198 } | |
| 199 | |
| 200 return $css . ".$class .handle { background-color: #$color; }\n"; | |
| 201 } | |
| 202 | |
| 203 /** | |
| 204 * | |
| 205 */ | |
| 206 function calendar_list($attrib = array()) | |
| 207 { | |
| 208 $html = ''; | |
| 209 $jsenv = array(); | |
| 210 $tree = true; | |
| 211 $calendars = $this->cal->driver->list_calendars(0, $tree); | |
| 212 | |
| 213 // walk folder tree | |
| 214 if (is_object($tree)) { | |
| 215 $html = $this->list_tree_html($tree, $calendars, $jsenv, $attrib); | |
| 216 | |
| 217 // append birthdays calendar which isn't part of $tree | |
| 218 if ($bdaycal = $calendars[calendar_driver::BIRTHDAY_CALENDAR_ID]) { | |
| 219 $calendars = array(calendar_driver::BIRTHDAY_CALENDAR_ID => $bdaycal); | |
| 220 } | |
| 221 else { | |
| 222 $calendars = array(); // clear array for flat listing | |
| 223 } | |
| 224 } | |
| 225 else { | |
| 226 // fall-back to flat folder listing | |
| 227 $attrib['class'] .= ' flat'; | |
| 228 } | |
| 229 | |
| 230 foreach ((array)$calendars as $id => $prop) { | |
| 231 if ($attrib['activeonly'] && !$prop['active']) | |
| 232 continue; | |
| 233 | |
| 234 $html .= html::tag('li', array('id' => 'rcmlical' . $id, 'class' => $prop['group']), | |
| 235 $content = $this->calendar_list_item($id, $prop, $jsenv, $attrib['activeonly']) | |
| 236 ); | |
| 237 } | |
| 238 | |
| 239 $this->rc->output->set_env('source', rcube_utils::get_input_value('source', rcube_utils::INPUT_GET)); | |
| 240 $this->rc->output->set_env('calendars', $jsenv); | |
| 241 $this->rc->output->add_gui_object('calendarslist', $attrib['id']); | |
| 242 | |
| 243 return html::tag('ul', $attrib, $html, html::$common_attrib); | |
| 244 } | |
| 245 | |
| 246 /** | |
| 247 * Return html for a structured list <ul> for the folder tree | |
| 248 */ | |
| 249 public function list_tree_html($node, $data, &$jsenv, $attrib) | |
| 250 { | |
| 251 $out = ''; | |
| 252 foreach ($node->children as $folder) { | |
| 253 $id = $folder->id; | |
| 254 $prop = $data[$id]; | |
| 255 $is_collapsed = false; // TODO: determine this somehow? | |
| 256 | |
| 257 $content = $this->calendar_list_item($id, $prop, $jsenv, $attrib['activeonly']); | |
| 258 | |
| 259 if (!empty($folder->children)) { | |
| 260 $content .= html::tag('ul', array('style' => ($is_collapsed ? "display:none;" : null)), | |
| 261 $this->list_tree_html($folder, $data, $jsenv, $attrib)); | |
| 262 } | |
| 263 | |
| 264 if (strlen($content)) { | |
| 265 $out .= html::tag('li', array( | |
| 266 'id' => 'rcmlical' . rcube_utils::html_identifier($id), | |
| 267 'class' => $prop['group'] . ($prop['virtual'] ? ' virtual' : ''), | |
| 268 ), | |
| 269 $content); | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 return $out; | |
| 274 } | |
| 275 | |
| 276 /** | |
| 277 * Helper method to build a calendar list item (HTML content and js data) | |
| 278 */ | |
| 279 public function calendar_list_item($id, $prop, &$jsenv, $activeonly = false) | |
| 280 { | |
| 281 // enrich calendar properties with settings from the driver | |
| 282 if (!$prop['virtual']) { | |
| 283 unset($prop['user_id']); | |
| 284 $prop['alarms'] = $this->cal->driver->alarms; | |
| 285 $prop['attendees'] = $this->cal->driver->attendees; | |
| 286 $prop['freebusy'] = $this->cal->driver->freebusy; | |
| 287 $prop['attachments'] = $this->cal->driver->attachments; | |
| 288 $prop['undelete'] = $this->cal->driver->undelete; | |
| 289 $prop['feedurl'] = $this->cal->get_url(array('_cal' => $this->cal->ical_feed_hash($id) . '.ics', 'action' => 'feed')); | |
| 290 | |
| 291 $jsenv[$id] = $prop; | |
| 292 } | |
| 293 | |
| 294 $classes = array('calendar', 'cal-' . asciiwords($id, true)); | |
| 295 $title = $prop['title'] ?: ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ? | |
| 296 html_entity_decode($prop['name'], ENT_COMPAT, RCUBE_CHARSET) : ''); | |
| 297 | |
| 298 if ($prop['virtual']) | |
| 299 $classes[] = 'virtual'; | |
| 300 else if (!$prop['editable']) | |
| 301 $classes[] = 'readonly'; | |
| 302 if ($prop['subscribed']) | |
| 303 $classes[] = 'subscribed'; | |
| 304 if ($prop['subscribed'] === 2) | |
| 305 $classes[] = 'partial'; | |
| 306 if ($prop['class']) | |
| 307 $classes[] = $prop['class']; | |
| 308 | |
| 309 $content = ''; | |
| 310 if (!$activeonly || $prop['active']) { | |
| 311 $label_id = 'cl:' . $id; | |
| 312 $content = html::div(join(' ', $classes), | |
| 313 html::span(array('class' => 'calname', 'id' => $label_id, 'title' => $title), $prop['editname'] ? rcube::Q($prop['editname']) : $prop['listname']) . | |
| 314 ($prop['virtual'] ? '' : | |
| 315 html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id), '') . | |
| 316 html::span('actions', | |
| 317 ($prop['removable'] ? html::a(array('href' => '#', 'class' => 'remove', 'title' => $this->cal->gettext('removelist')), ' ') : '') . | |
| 318 html::a(array('href' => '#', 'class' => 'quickview', 'title' => $this->cal->gettext('quickview'), 'role' => 'checkbox', 'aria-checked' => 'false'), '') . | |
| 319 (isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->cal->gettext('calendarsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '') | |
| 320 ) . | |
| 321 html::span(array('class' => 'handle', 'style' => "background-color: #" . ($prop['color'] ?: 'f00')), ' ') | |
| 322 ) | |
| 323 ); | |
| 324 } | |
| 325 | |
| 326 return $content; | |
| 327 } | |
| 328 | |
| 329 /** | |
| 330 * | |
| 331 */ | |
| 332 function angenda_options($attrib = array()) | |
| 333 { | |
| 334 $attrib += array('id' => 'agendaoptions'); | |
| 335 $attrib['style'] .= 'display:none'; | |
| 336 | |
| 337 $select_range = new html_select(array('name' => 'listrange', 'id' => 'agenda-listrange')); | |
| 338 $select_range->add(1 . ' ' . preg_replace('/\(.+\)/', '', $this->cal->lib->gettext('days')), $days); | |
| 339 foreach (array(2,5,7,14,30,60,90,180,365) as $days) | |
| 340 $select_range->add($days . ' ' . preg_replace('/\(|\)/', '', $this->cal->lib->gettext('days')), $days); | |
| 341 | |
| 342 $html .= html::label('agenda-listrange', $this->cal->gettext('listrange')); | |
| 343 $html .= $select_range->show($this->rc->config->get('calendar_agenda_range', $this->cal->defaults['calendar_agenda_range'])); | |
| 344 | |
| 345 $select_sections = new html_select(array('name' => 'listsections', 'id' => 'agenda-listsections')); | |
| 346 $select_sections->add('---', ''); | |
| 347 foreach (array('day' => 'libcalendaring.days', 'week' => 'libcalendaring.weeks', 'month' => 'libcalendaring.months', 'smart' => 'calendar.smartsections') as $val => $label) | |
| 348 $select_sections->add(preg_replace('/\(|\)/', '', ucfirst($this->rc->gettext($label))), $val); | |
| 349 | |
| 350 $html .= html::span('spacer', ' '); | |
| 351 $html .= html::label('agenda-listsections', $this->cal->gettext('listsections')); | |
| 352 $html .= $select_sections->show($this->rc->config->get('calendar_agenda_sections', $this->cal->defaults['calendar_agenda_sections'])); | |
| 353 | |
| 354 return html::div($attrib, $html); | |
| 355 } | |
| 356 | |
| 357 /** | |
| 358 * Render a HTML select box for calendar selection | |
| 359 */ | |
| 360 function calendar_select($attrib = array()) | |
| 361 { | |
| 362 $attrib['name'] = 'calendar'; | |
| 363 $attrib['is_escaped'] = true; | |
| 364 $select = new html_select($attrib); | |
| 365 | |
| 366 foreach ((array)$this->cal->driver->list_calendars() as $id => $prop) { | |
| 367 if ($prop['editable'] || strpos($prop['rights'], 'i') !== false) | |
| 368 $select->add($prop['name'], $id); | |
| 369 } | |
| 370 | |
| 371 return $select->show(null); | |
| 372 } | |
| 373 | |
| 374 /** | |
| 375 * Render a HTML select box for user identity selection | |
| 376 */ | |
| 377 function identity_select($attrib = array()) | |
| 378 { | |
| 379 $attrib['name'] = 'identity'; | |
| 380 $select = new html_select($attrib); | |
| 381 $identities = $this->rc->user->list_emails(); | |
| 382 | |
| 383 foreach ($identities as $ident) { | |
| 384 $select->add(format_email_recipient($ident['email'], $ident['name']), $ident['identity_id']); | |
| 385 } | |
| 386 | |
| 387 return $select->show(null); | |
| 388 } | |
| 389 | |
| 390 /** | |
| 391 * Render a HTML select box to select an event category | |
| 392 */ | |
| 393 function category_select($attrib = array()) | |
| 394 { | |
| 395 $attrib['name'] = 'categories'; | |
| 396 $select = new html_select($attrib); | |
| 397 $select->add('---', ''); | |
| 398 foreach (array_keys((array)$this->cal->driver->list_categories()) as $cat) { | |
| 399 $select->add($cat, $cat); | |
| 400 } | |
| 401 | |
| 402 return $select->show(null); | |
| 403 } | |
| 404 | |
| 405 /** | |
| 406 * Render a HTML select box for status property | |
| 407 */ | |
| 408 function status_select($attrib = array()) | |
| 409 { | |
| 410 $attrib['name'] = 'status'; | |
| 411 $select = new html_select($attrib); | |
| 412 $select->add('---', ''); | |
| 413 $select->add($this->cal->gettext('status-confirmed'), 'CONFIRMED'); | |
| 414 $select->add($this->cal->gettext('status-cancelled'), 'CANCELLED'); | |
| 415 $select->add($this->cal->gettext('status-tentative'), 'TENTATIVE'); | |
| 416 return $select->show(null); | |
| 417 } | |
| 418 | |
| 419 /** | |
| 420 * Render a HTML select box for free/busy/out-of-office property | |
| 421 */ | |
| 422 function freebusy_select($attrib = array()) | |
| 423 { | |
| 424 $attrib['name'] = 'freebusy'; | |
| 425 $select = new html_select($attrib); | |
| 426 $select->add($this->cal->gettext('free'), 'free'); | |
| 427 $select->add($this->cal->gettext('busy'), 'busy'); | |
| 428 // out-of-office is not supported by libkolabxml (#3220) | |
| 429 // $select->add($this->cal->gettext('outofoffice'), 'outofoffice'); | |
| 430 $select->add($this->cal->gettext('tentative'), 'tentative'); | |
| 431 return $select->show(null); | |
| 432 } | |
| 433 | |
| 434 /** | |
| 435 * Render a HTML select for event priorities | |
| 436 */ | |
| 437 function priority_select($attrib = array()) | |
| 438 { | |
| 439 $attrib['name'] = 'priority'; | |
| 440 $select = new html_select($attrib); | |
| 441 $select->add('---', '0'); | |
| 442 $select->add('1 '.$this->cal->gettext('highest'), '1'); | |
| 443 $select->add('2 '.$this->cal->gettext('high'), '2'); | |
| 444 $select->add('3 ', '3'); | |
| 445 $select->add('4 ', '4'); | |
| 446 $select->add('5 '.$this->cal->gettext('normal'), '5'); | |
| 447 $select->add('6 ', '6'); | |
| 448 $select->add('7 ', '7'); | |
| 449 $select->add('8 '.$this->cal->gettext('low'), '8'); | |
| 450 $select->add('9 '.$this->cal->gettext('lowest'), '9'); | |
| 451 return $select->show(null); | |
| 452 } | |
| 453 | |
| 454 /** | |
| 455 * Render HTML input for sensitivity selection | |
| 456 */ | |
| 457 function sensitivity_select($attrib = array()) | |
| 458 { | |
| 459 $attrib['name'] = 'sensitivity'; | |
| 460 $select = new html_select($attrib); | |
| 461 $select->add($this->cal->gettext('public'), 'public'); | |
| 462 $select->add($this->cal->gettext('private'), 'private'); | |
| 463 $select->add($this->cal->gettext('confidential'), 'confidential'); | |
| 464 return $select->show(null); | |
| 465 } | |
| 466 | |
| 467 /** | |
| 468 * Render HTML form for alarm configuration | |
| 469 */ | |
| 470 function alarm_select($attrib = array()) | |
| 471 { | |
| 472 return $this->cal->lib->alarm_select($attrib, $this->cal->driver->alarm_types, $this->cal->driver->alarm_absolute); | |
| 473 } | |
| 474 | |
| 475 /** | |
| 476 * | |
| 477 */ | |
| 478 function edit_attendees_notify($attrib = array()) | |
| 479 { | |
| 480 $checkbox = new html_checkbox(array('name' => '_notify', 'id' => 'edit-attendees-donotify', 'value' => 1)); | |
| 481 return html::div($attrib, html::label(null, $checkbox->show(1) . ' ' . $this->cal->gettext('sendnotifications'))); | |
| 482 } | |
| 483 | |
| 484 /** | |
| 485 * Generate the form for recurrence settings | |
| 486 */ | |
| 487 function recurring_event_warning($attrib = array()) | |
| 488 { | |
| 489 $attrib['id'] = 'edit-recurring-warning'; | |
| 490 | |
| 491 $radio = new html_radiobutton(array('name' => '_savemode', 'class' => 'edit-recurring-savemode')); | |
| 492 $form = html::label(null, $radio->show('', array('value' => 'current')) . $this->cal->gettext('currentevent')) . ' ' . | |
| 493 html::label(null, $radio->show('', array('value' => 'future')) . $this->cal->gettext('futurevents')) . ' ' . | |
| 494 html::label(null, $radio->show('all', array('value' => 'all')) . $this->cal->gettext('allevents')) . ' ' . | |
| 495 html::label(null, $radio->show('', array('value' => 'new')) . $this->cal->gettext('saveasnew')); | |
| 496 | |
| 497 return html::div($attrib, html::div('message', html::span('ui-icon ui-icon-alert', '') . $this->cal->gettext('changerecurringeventwarning')) . html::div('savemode', $form)); | |
| 498 } | |
| 499 | |
| 500 /** | |
| 501 * Form for uploading and importing events | |
| 502 */ | |
| 503 function events_import_form($attrib = array()) | |
| 504 { | |
| 505 if (!$attrib['id']) | |
| 506 $attrib['id'] = 'rcmImportForm'; | |
| 507 | |
| 508 // Get max filesize, enable upload progress bar | |
| 509 $max_filesize = $this->rc->upload_init(); | |
| 510 | |
| 511 $accept = '.ics, text/calendar, text/x-vcalendar, application/ics'; | |
| 512 if (class_exists('ZipArchive', false)) { | |
| 513 $accept .= ', .zip, application/zip'; | |
| 514 } | |
| 515 | |
| 516 $input = new html_inputfield(array( | |
| 517 'type' => 'file', 'name' => '_data', 'size' => $attrib['uploadfieldsize'], | |
| 518 'accept' => $accept)); | |
| 519 | |
| 520 $select = new html_select(array('name' => '_range', 'id' => 'event-import-range')); | |
| 521 $select->add(array( | |
| 522 $this->cal->gettext('onemonthback'), | |
| 523 $this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>2))), | |
| 524 $this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>3))), | |
| 525 $this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>6))), | |
| 526 $this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>12))), | |
| 527 $this->cal->gettext('all'), | |
| 528 ), | |
| 529 array('1','2','3','6','12',0)); | |
| 530 | |
| 531 $html .= html::div('form-section', | |
| 532 html::div(null, $input->show()) . | |
| 533 html::div('hint', $this->rc->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) | |
| 534 ); | |
| 535 | |
| 536 $html .= html::div('form-section', | |
| 537 html::label('event-import-calendar', $this->cal->gettext('calendar')) . | |
| 538 $this->calendar_select(array('name' => 'calendar', 'id' => 'event-import-calendar')) | |
| 539 ); | |
| 540 | |
| 541 $html .= html::div('form-section', | |
| 542 html::label('event-import-range', $this->cal->gettext('importrange')) . | |
| 543 $select->show(1) | |
| 544 ); | |
| 545 | |
| 546 $this->rc->output->add_gui_object('importform', $attrib['id']); | |
| 547 $this->rc->output->add_label('import'); | |
| 548 | |
| 549 return html::tag('form', array('action' => $this->rc->url(array('task' => 'calendar', 'action' => 'import_events')), | |
| 550 'method' => "post", 'enctype' => 'multipart/form-data', 'id' => $attrib['id']), | |
| 551 $html | |
| 552 ); | |
| 553 } | |
| 554 | |
| 555 /** | |
| 556 * Form to select options for exporting events | |
| 557 */ | |
| 558 function events_export_form($attrib = array()) | |
| 559 { | |
| 560 if (!$attrib['id']) | |
| 561 $attrib['id'] = 'rcmExportForm'; | |
| 562 | |
| 563 $html .= html::div('form-section', | |
| 564 html::label('event-export-calendar', $this->cal->gettext('calendar')) . | |
| 565 $this->calendar_select(array('name' => 'calendar', 'id' => 'event-export-calendar')) | |
| 566 ); | |
| 567 | |
| 568 $select = new html_select(array('name' => 'range', 'id' => 'event-export-range')); | |
| 569 $select->add(array( | |
| 570 $this->cal->gettext('all'), | |
| 571 $this->cal->gettext('onemonthback'), | |
| 572 $this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>2))), | |
| 573 $this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>3))), | |
| 574 $this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>6))), | |
| 575 $this->cal->gettext(array('name' => 'nmonthsback', 'vars' => array('nr'=>12))), | |
| 576 $this->cal->gettext('customdate'), | |
| 577 ), | |
| 578 array(0,'1','2','3','6','12','custom')); | |
| 579 | |
| 580 $startdate = new html_inputfield(array('name' => 'start', 'size' => 11, 'id' => 'event-export-startdate')); | |
| 581 | |
| 582 $html .= html::div('form-section', | |
| 583 html::label('event-export-range', $this->cal->gettext('exportrange')) . | |
| 584 $select->show(0) . | |
| 585 html::span(array('style'=>'display:none'), $startdate->show()) | |
| 586 ); | |
| 587 | |
| 588 $checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'event-export-attachments', 'value' => 1)); | |
| 589 $html .= html::div('form-section', | |
| 590 html::label('event-export-attachments', $this->cal->gettext('exportattachments')) . | |
| 591 $checkbox->show(1) | |
| 592 ); | |
| 593 | |
| 594 $this->rc->output->add_gui_object('exportform', $attrib['id']); | |
| 595 | |
| 596 return html::tag('form', array('action' => $this->rc->url(array('task' => 'calendar', 'action' => 'export_events')), | |
| 597 'method' => "post", 'id' => $attrib['id']), | |
| 598 $html | |
| 599 ); | |
| 600 } | |
| 601 | |
| 602 /** | |
| 603 * Generate the form for event attachments upload | |
| 604 */ | |
| 605 function attachments_form($attrib = array()) | |
| 606 { | |
| 607 // add ID if not given | |
| 608 if (!$attrib['id']) | |
| 609 $attrib['id'] = 'rcmUploadForm'; | |
| 610 | |
| 611 // Get max filesize, enable upload progress bar | |
| 612 $max_filesize = $this->rc->upload_init(); | |
| 613 | |
| 614 $button = new html_inputfield(array('type' => 'button')); | |
| 615 $input = new html_inputfield(array( | |
| 616 'type' => 'file', 'name' => '_attachments[]', | |
| 617 'multiple' => 'multiple', 'size' => $attrib['attachmentfieldsize'])); | |
| 618 | |
| 619 return html::div($attrib, | |
| 620 html::div(null, $input->show()) . | |
| 621 html::div('buttons', $button->show($this->rc->gettext('upload'), array('class' => 'button mainaction', | |
| 622 'onclick' => rcmail_output::JS_OBJECT_NAME . ".upload_file(this.form)"))) . | |
| 623 html::div('hint', $this->rc->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) | |
| 624 ); | |
| 625 } | |
| 626 | |
| 627 /** | |
| 628 * Register UI object for HTML5 drag & drop file upload | |
| 629 */ | |
| 630 function file_drop_area($attrib = array()) | |
| 631 { | |
| 632 if ($attrib['id']) { | |
| 633 $this->rc->output->add_gui_object('filedrop', $attrib['id']); | |
| 634 $this->rc->output->set_env('filedrop', array('action' => 'upload', 'fieldname' => '_attachments')); | |
| 635 } | |
| 636 } | |
| 637 | |
| 638 /** | |
| 639 * Generate HTML element for attachments list | |
| 640 */ | |
| 641 function attachments_list($attrib = array()) | |
| 642 { | |
| 643 if (!$attrib['id']) | |
| 644 $attrib['id'] = 'rcmAttachmentList'; | |
| 645 | |
| 646 $skin_path = $this->cal->local_skin_path(); | |
| 647 if ($attrib['deleteicon']) { | |
| 648 $_SESSION[calendar::SESSION_KEY . '_deleteicon'] = $skin_path . $attrib['deleteicon']; | |
| 649 $this->rc->output->set_env('deleteicon', $skin_path . $attrib['deleteicon']); | |
| 650 } | |
| 651 if ($attrib['cancelicon']) | |
| 652 $this->rc->output->set_env('cancelicon', $skin_path . $attrib['cancelicon']); | |
| 653 if ($attrib['loadingicon']) | |
| 654 $this->rc->output->set_env('loadingicon', $skin_path . $attrib['loadingicon']); | |
| 655 | |
| 656 $this->rc->output->add_gui_object('attachmentlist', $attrib['id']); | |
| 657 $this->attachmentlist_id = $attrib['id']; | |
| 658 | |
| 659 return html::tag('ul', $attrib, '', html::$common_attrib); | |
| 660 } | |
| 661 | |
| 662 /** | |
| 663 * Handler for calendar form template. | |
| 664 * The form content could be overriden by the driver | |
| 665 */ | |
| 666 function calendar_editform($action, $calendar = array()) | |
| 667 { | |
| 668 // compose default calendar form fields | |
| 669 $input_name = new html_inputfield(array('name' => 'name', 'id' => 'calendar-name', 'size' => 20)); | |
| 670 $input_color = new html_inputfield(array('name' => 'color', 'id' => 'calendar-color', 'size' => 6)); | |
| 671 | |
| 672 $formfields = array( | |
| 673 'name' => array( | |
| 674 'label' => $this->cal->gettext('name'), | |
| 675 'value' => $input_name->show($calendar['name']), | |
| 676 'id' => 'calendar-name', | |
| 677 ), | |
| 678 'color' => array( | |
| 679 'label' => $this->cal->gettext('color'), | |
| 680 'value' => $input_color->show($calendar['color']), | |
| 681 'id' => 'calendar-color', | |
| 682 ), | |
| 683 ); | |
| 684 | |
| 685 if ($this->cal->driver->alarms) { | |
| 686 $checkbox = new html_checkbox(array('name' => 'showalarms', 'id' => 'calendar-showalarms', 'value' => 1)); | |
| 687 $formfields['showalarms'] = array( | |
| 688 'label' => $this->cal->gettext('showalarms'), | |
| 689 'value' => $checkbox->show($calendar['showalarms']?1:0), | |
| 690 'id' => 'calendar-showalarms', | |
| 691 ); | |
| 692 } | |
| 693 | |
| 694 // allow driver to extend or replace the form content | |
| 695 return html::tag('form', array('action' => "#", 'method' => "get", 'id' => 'calendarpropform'), | |
| 696 $this->cal->driver->calendar_form($action, $calendar, $formfields) | |
| 697 ); | |
| 698 } | |
| 699 | |
| 700 /** | |
| 701 * | |
| 702 */ | |
| 703 function attendees_list($attrib = array()) | |
| 704 { | |
| 705 // add "noreply" checkbox to attendees table only | |
| 706 $invitations = strpos($attrib['id'], 'attend') !== false; | |
| 707 | |
| 708 $invite = new html_checkbox(array('value' => 1, 'id' => 'edit-attendees-invite')); | |
| 709 $table = new html_table(array('cols' => 5 + intval($invitations), 'border' => 0, 'cellpadding' => 0, 'class' => 'rectable')); | |
| 710 | |
| 711 $table->add_header('role', $this->cal->gettext('role')); | |
| 712 $table->add_header('name', $this->cal->gettext($attrib['coltitle'] ?: 'attendee')); | |
| 713 $table->add_header('availability', $this->cal->gettext('availability')); | |
| 714 $table->add_header('confirmstate', $this->cal->gettext('confirmstate')); | |
| 715 if ($invitations) { | |
| 716 $table->add_header(array('class' => 'invite', 'title' => $this->cal->gettext('sendinvitations')), | |
| 717 $invite->show(1) . html::label('edit-attendees-invite', $this->cal->gettext('sendinvitations'))); | |
| 718 } | |
| 719 $table->add_header('options', ''); | |
| 720 | |
| 721 // hide invite column if disabled by config | |
| 722 $itip_notify = (int)$this->rc->config->get('calendar_itip_send_option', $this->cal->defaults['calendar_itip_send_option']); | |
| 723 if ($invitations && !($itip_notify & 2)) { | |
| 724 $css = sprintf('#%s td.invite, #%s th.invite { display:none !important }', $attrib['id'], $attrib['id']); | |
| 725 $this->rc->output->add_footer(html::tag('style', array('type' => 'text/css'), $css)); | |
| 726 } | |
| 727 | |
| 728 return $table->show($attrib); | |
| 729 } | |
| 730 | |
| 731 /** | |
| 732 * | |
| 733 */ | |
| 734 function attendees_form($attrib = array()) | |
| 735 { | |
| 736 $input = new html_inputfield(array('name' => 'participant', 'id' => 'edit-attendee-name', 'size' => 30)); | |
| 737 $textarea = new html_textarea(array('name' => 'comment', 'id' => 'edit-attendees-comment', | |
| 738 'rows' => 4, 'cols' => 55, 'title' => $this->cal->gettext('itipcommenttitle'))); | |
| 739 | |
| 740 return html::div($attrib, | |
| 741 html::div(null, $input->show() . " " . | |
| 742 html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-add', 'value' => $this->cal->gettext('addattendee'))) . " " . | |
| 743 html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-schedule', 'value' => $this->cal->gettext('scheduletime').'...'))) . | |
| 744 html::p('attendees-commentbox', html::label(null, $this->cal->gettext('itipcomment') . $textarea->show())) | |
| 745 ); | |
| 746 } | |
| 747 | |
| 748 /** | |
| 749 * | |
| 750 */ | |
| 751 function resources_form($attrib = array()) | |
| 752 { | |
| 753 $input = new html_inputfield(array('name' => 'resource', 'id' => 'edit-resource-name', 'size' => 30)); | |
| 754 | |
| 755 return html::div($attrib, | |
| 756 html::div(null, $input->show() . " " . | |
| 757 html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-resource-add', 'value' => $this->cal->gettext('addresource'))) . " " . | |
| 758 html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-resource-find', 'value' => $this->cal->gettext('findresources').'...'))) | |
| 759 ); | |
| 760 } | |
| 761 | |
| 762 /** | |
| 763 * | |
| 764 */ | |
| 765 function resources_list($attrib = array()) | |
| 766 { | |
| 767 $attrib += array('id' => 'calendar-resources-list'); | |
| 768 | |
| 769 $this->rc->output->add_gui_object('resourceslist', $attrib['id']); | |
| 770 | |
| 771 return html::tag('ul', $attrib, '', html::$common_attrib); | |
| 772 } | |
| 773 | |
| 774 /** | |
| 775 * | |
| 776 */ | |
| 777 public function resource_info($attrib = array()) | |
| 778 { | |
| 779 $attrib += array('id' => 'calendar-resources-info'); | |
| 780 | |
| 781 $this->rc->output->add_gui_object('resourceinfo', $attrib['id']); | |
| 782 $this->rc->output->add_gui_object('resourceownerinfo', $attrib['id'] . '-owner'); | |
| 783 | |
| 784 // copy address book labels for owner details to client | |
| 785 $this->rc->output->add_label('name','firstname','surname','department','jobtitle','email','phone','address'); | |
| 786 | |
| 787 $table_attrib = array('id','class','style','width','summary','cellpadding','cellspacing','border'); | |
| 788 | |
| 789 return html::tag('table', $attrib, | |
| 790 html::tag('tbody', null, ''), $table_attrib) . | |
| 791 | |
| 792 html::tag('table', array('id' => $attrib['id'] . '-owner', 'style' => 'display:none') + $attrib, | |
| 793 html::tag('thead', null, | |
| 794 html::tag('tr', null, | |
| 795 html::tag('td', array('colspan' => 2), rcube::Q($this->cal->gettext('resourceowner'))) | |
| 796 ) | |
| 797 ) . | |
| 798 html::tag('tbody', null, ''), | |
| 799 $table_attrib); | |
| 800 } | |
| 801 | |
| 802 /** | |
| 803 * | |
| 804 */ | |
| 805 public function resource_calendar($attrib = array()) | |
| 806 { | |
| 807 $attrib += array('id' => 'calendar-resources-calendar'); | |
| 808 | |
| 809 $this->rc->output->add_gui_object('resourceinfocalendar', $attrib['id']); | |
| 810 | |
| 811 return html::div($attrib, ''); | |
| 812 } | |
| 813 | |
| 814 /** | |
| 815 * GUI object 'searchform' for the resource finder dialog | |
| 816 * | |
| 817 * @param array Named parameters | |
| 818 * @return string HTML code for the gui object | |
| 819 */ | |
| 820 function resources_search_form($attrib) | |
| 821 { | |
| 822 $attrib += array('command' => 'search-resource', 'id' => 'rcmcalresqsearchbox', 'autocomplete' => 'off'); | |
| 823 $attrib['name'] = '_q'; | |
| 824 | |
| 825 $input_q = new html_inputfield($attrib); | |
| 826 $out = $input_q->show(); | |
| 827 | |
| 828 // add form tag around text field | |
| 829 $out = $this->rc->output->form_tag(array( | |
| 830 'name' => "rcmcalresoursqsearchform", | |
| 831 'onsubmit' => rcmail_output::JS_OBJECT_NAME . ".command('" . $attrib['command'] . "'); return false", | |
| 832 'style' => "display:inline"), | |
| 833 $out); | |
| 834 | |
| 835 return $out; | |
| 836 } | |
| 837 | |
| 838 /** | |
| 839 * | |
| 840 */ | |
| 841 function attendees_freebusy_table($attrib = array()) | |
| 842 { | |
| 843 $table = new html_table(array('cols' => 2, 'border' => 0, 'cellspacing' => 0)); | |
| 844 $table->add('attendees', | |
| 845 html::tag('h3', 'boxtitle', $this->cal->gettext('tabattendees')) . | |
| 846 html::div('timesheader', ' ') . | |
| 847 html::div(array('id' => 'schedule-attendees-list', 'class' => 'attendees-list'), '') | |
| 848 ); | |
| 849 $table->add('times', | |
| 850 html::div('scroll', | |
| 851 html::tag('table', array('id' => 'schedule-freebusy-times', 'border' => 0, 'cellspacing' => 0), html::tag('thead') . html::tag('tbody')) . | |
| 852 html::div(array('id' => 'schedule-event-time', 'style' => 'display:none'), ' ') | |
| 853 ) | |
| 854 ); | |
| 855 | |
| 856 return $table->show($attrib); | |
| 857 } | |
| 858 | |
| 859 /** | |
| 860 * | |
| 861 */ | |
| 862 function event_invitebox($attrib = array()) | |
| 863 { | |
| 864 if ($this->cal->event) { | |
| 865 return html::div($attrib, | |
| 866 $this->cal->itip->itip_object_details_table($this->cal->event, $this->cal->itip->gettext('itipinvitation')) . | |
| 867 $this->cal->invitestatus | |
| 868 ); | |
| 869 } | |
| 870 | |
| 871 return ''; | |
| 872 } | |
| 873 | |
| 874 function event_rsvp_buttons($attrib = array()) | |
| 875 { | |
| 876 $actions = array('accepted','tentative','declined'); | |
| 877 if ($attrib['delegate'] !== 'false') | |
| 878 $actions[] = 'delegated'; | |
| 879 | |
| 880 return $this->cal->itip->itip_rsvp_buttons($attrib, $actions); | |
| 881 } | |
| 882 | |
| 883 } |
