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 } |