Implemented basic search functionality; to be completed...

This commit is contained in:
Thomas Bruederli 2011-06-13 18:41:32 -06:00
parent d17ca4a5ca
commit 79439a8934
8 changed files with 122 additions and 21 deletions

View file

@ -33,6 +33,8 @@ function rcube_calendar(settings)
this.dismiss_link = null;
this.selected_event = null;
this.selected_calendar = null;
this.search_request = null;
this.search_source = null;
this.eventcount = [];
@ -684,6 +686,76 @@ function rcube_calendar(settings)
}
};
/*** event searching ***/
// execute search
this.quicksearch = function()
{
if (rcmail.gui_objects.qsearchbox) {
var q = rcmail.gui_objects.qsearchbox.value;
if (q != '') {
var id = 'search-'+q;
var fc = $(fcselector);
var sources = [];
for (var sid in this.calendars) {
if (this.calendars[sid] && this.calendars[sid].active) {
fc.fullCalendar('removeEventSource', this.calendars[sid]);
sources.push(sid);
}
}
id += '@'+sources.join(',');
// just refetch events 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 {
this.default_view = fc.fullCalendar('getView').name;
}
// replace event source from fullcalendar
this.search_request = id;
this.search_source = {
url: "./?_task=calendar&_action=search_events&q="+escape(q)+'&source='+escape(sources.join(',')),
editable: false
};
fc.fullCalendar('option', 'smartSections', false);
fc.fullCalendar('addEventSource', this.search_source);
fc.fullCalendar('changeView', 'list');
}
}
};
// reset search and get back to normal event listing
this.reset_quicksearch = function()
{
$(rcmail.gui_objects.qsearchbox).val('');
if (this.search_request) {
// restore original event sources and view mode from fullcalendar
var fc = $(fcselector);
fc.fullCalendar('option', 'smartSections', true);
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]);
}
console.log(this.default_view);
if (this.default_view)
fc.fullCalendar('changeView', this.default_view);
this.search_request = this.search_source = null;
}
};
/*** startup code ***/
// create list of event sources AKA calendars
@ -698,8 +770,10 @@ function rcube_calendar(settings)
id: id
}, cal);
if ((active = ($.inArray(String(id), settings.hidden_calendars) < 0)))
if ((active = ($.inArray(String(id), settings.hidden_calendars) < 0))) {
this.calendars[id].active = true;
event_sources.push(this.calendars[id]);
}
// init event handler on calendar list checkbox
if ((li = rcmail.get_folder_li(id, 'rcmlical'))) {
@ -709,21 +783,29 @@ function rcube_calendar(settings)
var action;
if (this.checked) {
action = 'addEventSource';
me.calendars[id].active = true;
settings.hidden_calendars = $.map(settings.hidden_calendars, function(v){ return v == id ? null : v; });
}
else {
action = 'removeEventSource';
me.calendars[id].active = false;
settings.hidden_calendars.push(id);
}
$(fcselector).fullCalendar(action, me.calendars[id]);
rcmail.save_pref({ name:'hidden_calendars', value:settings.hidden_calendars.join(',') });
// just trigger search again (don't save prefs?)
if (me.search_request) {
me.quicksearch();
}
else { // add/remove event source
$(fcselector).fullCalendar(action, me.calendars[id]);
rcmail.save_pref({ name:'hidden_calendars', value:settings.hidden_calendars.join(',') });
}
}
}).data('id', id).get(0).checked = active;
$(li).click(function(e){
var id = $(this).data('id');
rcmail.select_folder(id, me.selected_calendar, 'rcmlical');
rcmail.enable_command('calendar-edit','calendar-remove', true);
rcmail.enable_command('calendar-edit','calendar-remove', !me.calendars[id].readonly);
me.selected_calendar = id;
}).data('id', id);
}
@ -1046,8 +1128,10 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
rcmail.register_command('calendar-edit', function(){ cal.calendar_edit_dialog(cal.calendars[cal.selected_calendar]); }, false);
rcmail.register_command('calendar-remove', function(){ cal.calendar_remove(cal.calendars[cal.selected_calendar]); }, false);
// export events
// search and export events
rcmail.register_command('export', function(){ rcmail.goto_url('export_events', { source:cal.selected_calendar }); }, true);
rcmail.register_command('search', function(){ cal.quicksearch(); }, true);
rcmail.register_command('reset-search', function(){ cal.reset_quicksearch(); }, true);
// register callback commands
rcmail.addEventListener('plugin.display_alarms', function(alarms){ cal.display_alarms(alarms); });

View file

@ -138,6 +138,7 @@ class calendar extends rcube_plugin
$this->register_handler('plugin.snooze_select', array($this->ui, 'snooze_select'));
$this->register_handler('plugin.recurrence_form', array($this->ui, 'recurrence_form'));
$this->register_handler('plugin.edit_recurring_warning', array($this->ui, 'recurring_event_warning'));
$this->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template
$this->rc->output->set_env('calendar_settings', $this->load_settings());
$this->rc->output->add_label('low','normal','high');
@ -457,12 +458,13 @@ class calendar extends rcube_plugin
*/
function search_events()
{
$events = $this->driver->load_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);
echo $this->encode($events, true);
exit;
}
@ -586,7 +588,7 @@ class calendar extends rcube_plugin
* @param array Events as array
* @return string JSON encoded events
*/
function encode($events)
function encode($events, $addcss = false)
{
$json = array();
foreach ($events as $event) {
@ -601,7 +603,7 @@ class calendar extends rcube_plugin
'end' => date('c', $event['end']), // ISO 8601 date (added in PHP 5)
'description' => $event['description'],
'location' => $event['location'],
'className' => 'cat-' . asciiwords($event['categories'], true),
'className' => ($addcss ? 'fc-event-cal-'.asciiwords($event['calendar'], true).' ' : '') . 'cat-' . asciiwords($event['categories'], true),
'allDay' => ($event['all_day'] == 1)?true:false,
) + $event;
}

View file

@ -597,7 +597,7 @@ class database_driver extends calendar_driver
*
* @see Driver:load_events()
*/
public function load_events($start, $end, $calendars = null)
public function load_events($start, $end, $calendars = null, $sql_add = '')
{
if (empty($calendars))
$calendars = array_keys($this->calendars);
@ -613,10 +613,12 @@ class database_driver extends calendar_driver
$result = $this->rc->db->query(sprintf(
"SELECT * FROM " . $this->db_events . "
WHERE calendar_id IN (%s)
AND start <= %s AND end >= %s",
AND start <= %s AND end >= %s
%s",
join(',', $calendar_ids),
$this->rc->db->fromunixtime($end),
$this->rc->db->fromunixtime($start)
$this->rc->db->fromunixtime($start),
$sql_add
));
while ($result && ($event = $this->rc->db->fetch_assoc($result))) {
@ -665,7 +667,13 @@ class database_driver extends calendar_driver
*/
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) . ')');
}
/**

View file

@ -106,18 +106,23 @@ class kolab_calendar
/**
* @param integer Event's new start (unix timestamp)
* @param integer Event's new end (unix timestamp)
* @param string Search query (optional)
* @return array A list of event records
*/
public function list_events($start, $end)
public function list_events($start, $end, $search = null)
{
// use Horde classes to compute recurring instances
require_once 'Horde/Date/Recurrence.php';
$this->_fetch_events();
$events = array();
foreach ($this->events as $id => $event) {
// TODO: filter events by search query
if (!empty($search)) {
}
// list events in requested time window
if ($event['start'] <= $end && $event['end'] >= $start) {
$events[] = $event;

View file

@ -216,9 +216,10 @@ 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)
* @return array A list of event records
*/
public function load_events($start, $end, $calendars = null)
public function load_events($start, $end, $calendars = null, $search = null)
{
if ($calendars && is_string($calendars))
$calendars = explode(',', $calendars);
@ -228,7 +229,7 @@ class kolab_driver extends calendar_driver
if ($calendars && !in_array($cid, $calendars))
continue;
$events = array_merge($this->folders[$cid]->list_events($start, $end));
$events = array_merge($this->folders[$cid]->list_events($start, $end, $search));
}
return $events;
@ -242,7 +243,8 @@ class kolab_driver extends calendar_driver
*/
public function search_events($start, $end, $query, $calendars = null)
{
return array();
// delegate request to load_events()
return $this->load_events($start, $end, $calendars, $query);
}
/**

View file

@ -650,8 +650,8 @@ function Calendar(element, options, eventSources) {
if (value === undefined) {
return options[name];
}
options[name] = value;
if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') {
options[name] = value;
updateSize();
}
}

View file

@ -622,7 +622,7 @@ table.fc-border-separate {
.fc-view-list,
.fc-view-table {
border: 1px solid #ccc;
width: 99%;
width: auto;
}
.fc-view-list .fc-list-header,

View file

@ -197,7 +197,7 @@
<div id="quicksearchbar">
<roundcube:button name="searchmenulink" id="searchmenulink" image="/images/icons/glass.png" />
<roundcube:object name="searchform" id="quicksearchbox" />
<roundcube:object name="plugin.searchform" id="quicksearchbox" />
<roundcube:button command="reset-search" id="searchreset" image="/images/icons/reset.gif" title="resetsearch" />
</div>