diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
index 1d40efe5..fc0069d4 100644
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -725,9 +725,29 @@ class calendar extends rcube_plugin
$this->rc->output->command('plugin.destroy_source', array('id' => $cal['id']));
break;
case "subscribe":
- if (!$this->driver->subscribe_calendar($cal))
+ if (!$this->driver->subscribe_calendar($cal, intval(get_input_value('perm', RCUBE_INPUT_GPC))))
$this->rc->output->show_message($this->gettext('errorsaving'), 'error');
return;
+ case "search":
+ $results = array();
+ $color_mode = $this->rc->config->get('calendar_event_coloring', $this->defaults['calendar_event_coloring']);
+ foreach ((array)$this->driver->search_calendars(get_input_value('q', RCUBE_INPUT_GPC), get_input_value('source', RCUBE_INPUT_GPC)) as $id => $prop) {
+ $editname = $prop['editname'];
+ unset($prop['editname']); // force full name to be displayed
+ $prop['active'] = false;
+
+ // let the UI generate HTML and CSS representation for this calendar
+ $html = $this->ui->calendar_list_item($id, $prop, $jsenv);
+ $cal = $jsenv[$id];
+ $cal['editname'] = $editname;
+ $cal['html'] = $html;
+ if (!empty($prop['color']))
+ $cal['css'] = $this->ui->calendar_css_classes($id, $prop, $color_mode);
+
+ $results[] = $cal;
+ }
+ $this->rc->output->command('multi_thread_http_response', $results, get_input_value('_reqid', RCUBE_INPUT_GPC));
+ return;
}
if ($success)
diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index 2a8a8d2b..4db85937 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -39,6 +39,7 @@ function rcube_calendar_ui(settings)
this.selected_calendar = null;
this.search_request = null;
this.saving_lock;
+ this.calendars = {};
/*** private vars ***/
@@ -52,6 +53,9 @@ function rcube_calendar_ui(settings)
var event_defaults = { free_busy:'busy', alarms:'' };
var event_attendees = [];
var calendars_list;
+ var calenders_search_list;
+ var calenders_search_container;
+ var search_calendars = {};
var attendees_list;
var resources_list;
var resources_treelist;
@@ -2667,16 +2671,79 @@ function rcube_calendar_ui(settings)
this.selected_calendar = id;
};
+ // render the results for calendar list search
+ var calendar_search_results = function(results)
+ {
+ if (results.length) {
+ // create treelist widget to present the search results
+ if (!calenders_search_list) {
+ calenders_search_container = $('
')
+ .html('' + rcmail.gettext('calsearchresults','calendar') + '
')
+ .insertAfter(rcmail.gui_objects.calendarslist);
- /*** startup code ***/
+ calenders_search_list = new rcube_treelist_widget('', {
+ id_prefix: 'rcmlical',
+ selectable: false
+ });
- // create list of event sources AKA calendars
- this.calendars = {};
- var id, li, cal, active, color, brightness, event_sources = [];
- for (id in rcmail.env.calendars) {
- cal = rcmail.env.calendars[id];
- this.calendars[id] = $.extend({
- url: "./?_task=calendar&_action=load_events&source="+escape(id),
+ // register click handler on search result's checkboxes to select the given calendar for listing
+ calenders_search_list.container
+ .appendTo(calenders_search_container)
+ .on('click', 'input[type=checkbox]', function(e){
+ var li = $(this).closest('li'),
+ id = li.attr('id').replace(/^rcmlical/, ''),
+ prop = search_calendars[id],
+ parent_id = prop.parent || null;
+
+ if (!this.checked)
+ return;
+
+ // find parent node and insert at the right place
+ if (parent_id && $('#rcmlical'+parent_id, rcmail.gui_objects.calendarslist).length) {
+ prop.listname = prop.editname;
+ li.children().first().find('.calname').html(Q(prop.listname));
+ }
+
+ // move this calendar to the calendars_list widget
+ calendars_list.insert({
+ id: id,
+ classes: [],
+ html: li.children().first()
+ }, parent_id, parent_id ? true : false);
+
+ search_calendars[id].active = true;
+ add_calendar_source(prop);
+ li.remove();
+
+ // add css classes related to this calendar to document
+ if (cal.css) {
+ $('')
+ .html(cal.css)
+ .appendTo('head');
+ }
+ });
+ }
+
+ for (var cal, i=0; i < results.length; i++) {
+ cal = results[i];
+ search_calendars[cal.id] = cal;
+ $('')
+ .attr('id', 'rcmlical' + cal.id)
+ .html(cal.html)
+ .appendTo(calenders_search_list.container);
+ }
+
+ calenders_search_container.show();
+ }
+ };
+
+ // register the given calendar to the current view
+ var add_calendar_source = function(cal)
+ {
+ var color, brightness, select, id = cal.id;
+
+ me.calendars[id] = $.extend({
+ url: rcmail.url('calendar/load_events', { source: id }),
editable: !cal.readonly,
className: 'fc-event-cal-'+id,
id: id
@@ -2689,18 +2756,40 @@ function rcube_calendar_ui(settings)
// http://javascriptrules.com/2009/08/05/css-color-brightness-contrast-using-javascript/
brightness = (parseInt(RegExp.$1, 16) * 299 + parseInt(RegExp.$2, 16) * 587 + parseInt(RegExp.$3, 16) * 114) / 1000;
if (brightness > 125)
- this.calendars[id].textColor = 'black';
+ me.calendars[id].textColor = 'black';
}
+
+ me.calendars[id].color = color;
}
- this.calendars[id].color = color;
-
- if ((active = cal.active || false)) {
- event_sources.push(this.calendars[id]);
+ if (fc && cal.active) {
+ fc.fullCalendar('addEventSource', me.calendars[id]);
+ rcmail.http_post('calendar', { action:'subscribe', c:{ id:id, active:cal.active?1:0 } });
}
+ // insert to #calendar-select options if writeable
+ select = $('#edit-calendar');
+ if (fc && !cal.readonly && select.length && !select.find('option[value="'+id+'"]').length) {
+ $('