Parallelize search requests + simplify backend API
This commit is contained in:
parent
299c8bdd68
commit
171408672f
6 changed files with 42 additions and 98 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue