diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index f618f5b3..49c3a493 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -102,7 +102,6 @@ class calendar extends rcube_plugin $this->register_action('event', array($this, 'event_action')); $this->register_action('calendar', array($this, 'calendar_action')); $this->register_action('load_events', array($this, 'load_events')); - $this->register_action('search_events', array($this, 'search_events')); $this->register_action('export_events', array($this, 'export_events')); $this->register_action('upload', array($this, 'attachment_upload')); $this->register_action('get-attachment', array($this, 'attachment_get')); @@ -510,25 +509,10 @@ class calendar extends rcube_plugin $events = $this->driver->load_events( get_input_value('start', RCUBE_INPUT_GET), get_input_value('end', RCUBE_INPUT_GET), + ($query = get_input_value('q', RCUBE_INPUT_GET)), get_input_value('source', RCUBE_INPUT_GET) ); - echo $this->encode($events); - exit; - } - - /** - * Handler for search-requests from client - * This will return pure JSON formatted output for fullcalendar - */ - function search_events() - { - $events = $this->driver->search_events( - get_input_value('start', RCUBE_INPUT_GET), - get_input_value('end', RCUBE_INPUT_GET), - get_input_value('q', RCUBE_INPUT_GET), - get_input_value('source', RCUBE_INPUT_GET) - ); - echo $this->encode($events, true); + echo $this->encode($events, !empty($query)); exit; } @@ -642,6 +626,7 @@ class calendar extends rcube_plugin * Encode events as JSON * * @param array Events as array + * @param boolean Add CSS class names according to calendar and categories * @return string JSON encoded events */ function encode($events, $addcss = false) diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index 7576e8d8..5af8c94a 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -29,10 +29,10 @@ function rcube_calendar_ui(settings) rcube_calendar.call(this, settings); /*** member vars ***/ + this.is_loading = false; this.selected_event = null; this.selected_calendar = null; this.search_request = null; - this.search_source = null; this.eventcount = []; this.saving_lock = null; @@ -975,37 +975,32 @@ function rcube_calendar_ui(settings) rcmail.hide_message(this._search_message); for (var sid in this.calendars) { - if (this.calendars[sid] && this.calendars[sid].active) { - fc.fullCalendar('removeEventSource', this.calendars[sid]); + if (this.calendars[sid]) { + this.calendars[sid].url = this.calendars[sid].url.replace(/&q=.+/, '') + '&q='+escape(q); sources.push(sid); } } id += '@'+sources.join(','); - // just refetch events if query didn't change + // ignore if query didn't change if (this.search_request == id) { - fc.fullCalendar('refetchEvents'); return; } - // remove old search results - else if (this.search_source) { - fc.fullCalendar('removeEventSource', this.search_source); - } - else { + // remember current view + else if (!this.search_request) { this.default_view = fc.fullCalendar('getView').name; } - // replace event source from fullcalendar this.search_request = id; this.search_query = q; - this.search_source = { - url: "./?_task=calendar&_action=search_events&q="+escape(q)+'&source='+escape(sources.join(',')), - editable: false - }; + // change to list view fc.fullCalendar('option', 'listSections', 'month'); - fc.fullCalendar('addEventSource', this.search_source); fc.fullCalendar('changeView', 'table'); + + // refetch events with new url (if not already triggered by changeView) + if (!this.is_loading) + fc.fullCalendar('refetchEvents'); } else // empty search input equals reset this.reset_quicksearch(); @@ -1023,15 +1018,17 @@ function rcube_calendar_ui(settings) if (this.search_request) { // restore original event sources and view mode from fullcalendar fc.fullCalendar('option', 'listSections', 'smart'); - fc.fullCalendar('removeEventSource', this.search_source); for (var sid in this.calendars) { - if (this.calendars[sid] && this.calendars[sid].active) - fc.fullCalendar('addEventSource', this.calendars[sid]); + if (this.calendars[sid]) + this.calendars[sid].url = this.calendars[sid].url.replace(/&q=.+/, ''); } if (this.default_view) fc.fullCalendar('changeView', this.default_view); - this.search_request = this.search_source = this.search_query = null; + if (!this.is_loading) + fc.fullCalendar('refetchEvents'); + + this.search_request = this.search_query = null; } }; @@ -1078,14 +1075,10 @@ function rcube_calendar_ui(settings) me.calendars[id].active = false; settings.hidden_calendars.push(id); } - // just trigger search again (don't save prefs?) - if (me.search_request) { - me.quicksearch(); - } - else { // add/remove event source - fc.fullCalendar(action, me.calendars[id]); - rcmail.save_pref({ name:'hidden_calendars', value:settings.hidden_calendars.join(',') }); - } + + // add/remove event source + fc.fullCalendar(action, me.calendars[id]); + rcmail.save_pref({ name:'hidden_calendars', value:settings.hidden_calendars.join(',') }); } }).data('id', id).get(0).checked = active; @@ -1159,6 +1152,7 @@ function rcube_calendar_ui(settings) selectable: true, selectHelper: true, loading: function(isLoading) { + me.is_loading = isLoading; this._rc_loading = rcmail.set_busy(isLoading, 'loading', this._rc_loading); // trigger callback if (!isLoading && me.search_request) diff --git a/plugins/calendar/drivers/calendar_driver.php b/plugins/calendar/drivers/calendar_driver.php index 8775279d..876fe52f 100644 --- a/plugins/calendar/drivers/calendar_driver.php +++ b/plugins/calendar/drivers/calendar_driver.php @@ -167,21 +167,11 @@ abstract class calendar_driver * * @param integer Event's new start (unix timestamp) * @param integer Event's new end (unix timestamp) + * @param string Search query (optional) * @param mixed List of calendar IDs to load events from (either as array or comma-separated string) * @return array A list of event objects (see header of this file for struct of an event) */ - abstract function load_events($start, $end, $calendars = null); - - /** - * Search events using the given query - * - * @param integer Event's new start (unix timestamp) - * @param integer Event's new end (unix timestamp) - * @param string Search query - * @param mixed List of calendar IDs to load events from (either as array or comma-separated string) - * @return array A list of event objects (see header of this file for struct of an event) - */ - abstract function search_events($start, $end, $query, $calendars = null); + abstract function load_events($start, $end, $query = null, $calendars = null); /** * Get a list of pending alarms to be displayed to the user diff --git a/plugins/calendar/drivers/database/database_driver.php b/plugins/calendar/drivers/database/database_driver.php index b4d35905..0a7b1889 100644 --- a/plugins/calendar/drivers/database/database_driver.php +++ b/plugins/calendar/drivers/database/database_driver.php @@ -618,16 +618,24 @@ class database_driver extends calendar_driver * * @see Driver:load_events() */ - public function load_events($start, $end, $calendars = null, $sql_add = '') + public function load_events($start, $end, $query = null, $calendars = null) { if (empty($calendars)) $calendars = array_keys($this->calendars); else if (is_string($calendars)) $calendars = explode(',', $calendars); - + // only allow to select from calendars of this use $calendar_ids = array_map(array($this->rc->db, 'quote'), array_intersect($calendars, array_keys($this->calendars))); + // compose (slow) SQL query for searching + // FIXME: improve searching using a dedicated col and normalized values + if ($query) { + foreach (array('title','location','description','categories','attendees') as $col) + $sql_query[] = $this->rc->db->ilike($col, '%'.$query.'%'); + $sql_add = 'AND (' . join(' OR ', $sql_query) . ')'; + } + $events = array(); if (!empty($calendar_ids)) { $result = $this->rc->db->query(sprintf( @@ -687,22 +695,6 @@ class database_driver extends calendar_driver return $event; } - /** - * Search events - * - * @see Driver:search_events() - */ - public function search_events($start, $end, $query, $calendars = null) - { - // compose (slow) SQL query for searching - // FIXME: improve searching using a dedicated col and normalized values - foreach (array('title','location','description','categories','attendees') as $col) { - $sql_query[] = $this->rc->db->ilike($col, '%'.$query.'%'); - } - - return $this->load_events($start, $end, $calendars, 'AND (' . join(' OR ', $sql_query) . ')'); - } - /** * Get a list of pending alarms to be displayed to the user * diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php index 2b78b06d..39da2732 100644 --- a/plugins/calendar/drivers/kolab/kolab_driver.php +++ b/plugins/calendar/drivers/kolab/kolab_driver.php @@ -485,11 +485,11 @@ class kolab_driver extends calendar_driver * * @param integer Event's new start (unix timestamp) * @param integer Event's new end (unix timestamp) - * @param mixed List of calendar IDs to load events from (either as array or comma-separated string) * @param string Search query (optional) + * @param mixed List of calendar IDs to load events from (either as array or comma-separated string) * @return array A list of event records */ - public function load_events($start, $end, $calendars = null, $search = null) + public function load_events($start, $end, $search = null, $calendars = null) { if ($calendars && is_string($calendars)) $calendars = explode(',', $calendars); @@ -505,18 +505,6 @@ class kolab_driver extends calendar_driver return $events; } - /** - * Search events using the given query - * - * @see Driver::search_events() - * @return array A list of event records - */ - public function search_events($start, $end, $query, $calendars = null) - { - // delegate request to load_events() - return $this->load_events($start, $end, $calendars, $query); - } - /** * Get a list of pending alarms to be displayed to the user * diff --git a/plugins/calendar/print.js b/plugins/calendar/print.js index 90515254..03cd8860 100644 --- a/plugins/calendar/print.js +++ b/plugins/calendar/print.js @@ -27,23 +27,18 @@ window.rcmail && rcmail.addEventListener('init', function(evt) { var settings = rcmail.env.calendar_settings; // create list of event sources AKA calendars - var src, calendars = [], event_sources = []; + var src, event_sources = []; + var add_url = (rcmail.env.search ? '&q='+escape(rcmail.env.search) : ''); for (var id in rcmail.env.calendars) { source = $.extend({ - url: "./?_task=calendar&_action=load_events&source="+escape(id), + url: "./?_task=calendar&_action=load_events&source=" + escape(id) + add_url, className: 'fc-event-cal-'+id, id: id }, rcmail.env.calendars[id]); event_sources.push(source); - calendars.push(id); } - // search query is active - if (rcmail.env.search) { - event_sources = [{ url: "./?_task=calendar&_action=search_events&q="+escape(rcmail.env.search)+'&source='+escape(calendars.join(',')) }]; - } - var viewdate = new Date(); if (rcmail.env.date) viewdate.setTime(rcmail.env.date * 1000);