var DimpBase = {
// Vars used and defaulting to null/false:
- // cfolderaction, filter_on, filtertoggle, fl_visible, folder,
- // folderswitch, fspecial, isvisible, message_list_template, offset,
- // pollPE, pp, uid, viewport
+ // cfolderaction, fl_visible, folder, folderswitch, isvisible,
+ // message_list_template, offset, pollPE, pp, sfolder, uid, viewport
bcache: $H(),
cacheids: {},
lastrow: -1,
pivotrow: -1,
ppcache: {},
ppfifo: [],
+ searchid: 'dimp\x00qsearch',
tcache: {},
- sfiltersfolder: $H({
- sf_all: 'all',
- sf_current: 'current'
- }),
-
- sfilters: $H({
- sf_msgall: 'msgall',
- sf_from: 'from',
- sf_to: 'to',
- sf_subject: 'subject'
- }),
-
// Message selection functions
// vs = (ViewPort_Selection) A ViewPort_Selection object.
// from the search input, because the user may immediately start
// keyboard navigation after that. Thus, we need to ensure that a
// message click loses focus on the search input.
- $('msgList_filter').blur();
+ $('quicksearch').blur();
if (opts.shift) {
if (selcount) {
this._addHistory(loc);
}
}
- this.loadFolder(f);
+ this.loadMailbox(f);
return;
}
});
},
- loadFolder: function(f, background)
+ loadMailbox: function(f, opts)
{
+ opts = opts || {};
+
if (!this.viewport) {
this._createViewPort();
}
- if (!background) {
+ if (!opts.background) {
this.resetSelected();
+ this.quicksearchClear(true);
if (this.folder == f) {
- this.searchfilterClear(false);
return;
}
- this.searchfilterClear(true);
$('folderName').update(DIMP.text.loading);
$('msgHeader').update();
this.folderswitch = true;
this.folder = f;
}
- this.viewport.loadView(f, this.uid ? { imapuid: this.uid, view: f } : null, background);
+ this.viewport.loadView(f, this.uid ? { imapuid: this.uid, view: f } : null, opts.background);
},
_createViewPort: function()
{
- var mf = $('msgList_filter'),
- // No need to cache - this function only called once.
- settitle = this.setMessageListTitle.bind(this);
+ // No need to cache - this function only called once.
+ var settitle = this.setMessageListTitle.bind(this);
this.viewport = new ViewPort({
content_container: 'msgList',
onScrollIdle: settitle,
onSlide: settitle,
onContent: function(row) {
- var bg, search, u,
+ var bg, re, search, u,
thread = ((this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) && this.viewport.getMetaData('thread'));
- if (this.viewport.isFiltering()) {
- search = this.sfilters.get(this._getSearchfilterField());
- }
-
row.subjectdata = row.status = '';
+ row.subjecttitle = row.subject;
// Add thread graphics
if (thread && thread.get(row.imapuid)) {
row.style = 'background:' + bg;
}
- // Highlight search terms
- if (search == 'from' || search == 'subject') {
- row[search] = row[search].gsub(new RegExp("(" + $F('msgList_filter') + ")", "i"), '<span class="searchMatch">#{1}</span>');
+ // Check for search strings
+ if (this.isSearch()) {
+ re = new RegExp("(" + $F('quicksearch') + ")", "i");
+ [ 'from', 'subject' ].each(function(h) {
+ row[h] = row[h].gsub(re, '<span class="quicksearchMatch">#{1}</span>');
+ });
}
- // If null, invalid string was scrubbed by JSON encode.
+ // If these fields are null, invalid string was scrubbed by
+ // JSON encode.
if (row.from === null) {
row.from = '[' + DIMP.text.badaddr + ']';
}
if (row.subject === null) {
- row.subject = '[' + DIMP.text.badsubject + ']';
+ row.subject = row.subjecttitle = '[' + DIMP.text.badsubject + ']';
}
}.bind(this),
onContentComplete: function(rows) {
// retrieving data from the server.
l = this.viewport.getMetaData('label');
if (l) {
+ if (this.isSearch()) {
+ l += ' (' + this.sfolder + ')';
+ }
$('folderName').update(l);
}
tmp.compact().invoke('show');
$('folderName').next().hide();
}
- } else if (this.filtertoggle) {
- if (this.filtertoggle == 1 &&
- this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) {
- ssc = DIMP.conf.sortdate;
- }
- this.filtertoggle = 0;
+ } else if (this.filtertoggle &&
+ this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) {
+ ssc = DIMP.conf.sortdate;
}
this.setSortColumns(ssc);
- if (this.viewport.isFiltering()) {
+ if (this.isSearch()) {
this.resetSelected();
} else {
this.setFolderLabel(this.folder, this.viewport.getMetaData('unseen') || 0);
}
return this.cacheids[id];
}.bind(this),
+ requestParams: function(id) {
+ return this.isSearch(id)
+ ? $H({
+ qsearch: $F('quicksearch'),
+ qsearchmbox: this.sfolder
+ })
+ : $H();
+ }.bind(this),
onSplitBarChange: function() {
this._updatePrefs('dimp_splitbar', this.viewport.getPageSize());
}.bind(this),
if (!DIMP.conf.preview_pref) {
$('msgList').addClassName('msglistNoPreview');
}
-
- // Set up viewport filter events.
- this.viewport.addFilter('ListMessages', this._addSearchfilterParams.bind(this));
- mf.observe('focus', this._searchfilterOnFocus.bind(this));
- mf.observe('blur', this._searchfilterOnBlur.bind(this));
- mf.addClassName('msgFilterDefault');
},
_addMouseEvents: function(p, popdown)
updateTitle: function()
{
- var elt, label, unseen;
+ var elt, unseen,
+ label = this.viewport.getMetaData('label');
- if (this.viewport.isFiltering()) {
- label = DIMP.text.search + ' :: ' + (this.viewport.getMetaData('total_rows') || 0) + ' ' + DIMP.text.resfound;
+ if (this.isSearch()) {
+ label += ' (' + this.sfolder + ')';
} else {
- label = this.viewport.getMetaData('label');
elt = $(this.getFolderId(this.folder));
if (elt) {
unseen = elt.readAttribute('u');
}
tmp = m.down('div.msgFrom a');
- if ((this.viewport.isFiltering() && this.fspecial) ||
- this.viewport.getMetaData('special')) {
+ if (this.viewport.getMetaData('special')) {
tmp.hide().next().show();
} else {
tmp.show().next().hide();
}
tmp = m.down('div.msgSubject a');
- if (this.viewport.isFiltering() ||
+ if (this.isSearch() ||
this.viewport.getMetaData('nothread') ||
this.viewport.getMetaData('sortlimit')) {
tmp.show().next().hide();
$('dimpmain_portal').update(r.response.portal);
},
- /* Search filter functions. */
- searchfilterRun: function()
+ /* Search functions. */
+ isSearch: function(id)
{
- if (!this.viewport.isFiltering()) {
- this.filtertoggle = 1;
- this.fspecial = this.viewport.getMetaData('special');
- }
- this.viewport.runFilter($F('msgList_filter'));
+ return (id ? id : this.folder) == this.searchid;
},
- _searchfilterOnFocus: function()
+ _quicksearchOnFocus: function()
{
- var q = $('qoptions').up();
-
- if ($('msgList_filter').hasClassName('msgFilterDefault')) {
+ if ($('quicksearch').hasClassName('quicksearchDefault')) {
this._setFilterText(false);
}
-
- if (!this.filter_on) {
- this.filter_on = true;
- $('sf_current').update(this.viewport.getMetaData('label'));
- this._setSearchfilterParams(this.viewport.getMetaData('special') ? 'to' : 'from', 'msg');
- this._setSearchfilterParams('current', 'folder');
- $(document.documentElement).setStyle({ overflowY: 'hidden' });
- Effect.SlideDown(q, { duration: 0.5, afterFinish: function() { this.onResize(false, true); $(document.documentElement).setStyle({ overflowY: 'auto' }); }.bind(this) });
- }
},
- _searchfilterOnBlur: function()
+ _quicksearchOnBlur: function()
{
- if (!$F('msgList_filter')) {
+ if (!$F('quicksearch')) {
this._setFilterText(true);
}
},
- // reset = (boolean) TODO
- searchfilterClear: function(reset)
- {
- if (!this.filter_on) {
- return;
- }
-
- this.filter_on = false;
- this._setFilterText(true);
- Effect.SlideUp($('qoptions').up(), { duration: 0.5, afterFinish: this.onResize.bind(this, reset) });
- this.filtertoggle = 2;
- this.resetSelected();
- this.viewport.stopFilter(reset);
- },
-
- // d = (boolean) Deactivate filter input?
- _setFilterText: function(d)
+ quicksearchRun: function()
{
- var mf = $('msgList_filter');
- if (d) {
- mf.setValue(DIMP.text.search);
- mf.addClassName('msgFilterDefault');
+ if (this.isSearch()) {
+ this.viewport.reload();
} else {
- mf.setValue('');
- mf.removeClassName('msgFilterDefault');
+ this.sfolder = this.folder;
+ $('quicksearch_close').show();
+ this.loadMailbox(this.searchid);
}
},
- // type = 'folder' or 'msg'
- _setSearchfilterParams: function(id, type)
- {
- var c = (type == 'folder') ? this.sfiltersfolder : this.sfilters;
- c.keys().each(function(i) {
- $(i).writeAttribute('className', (id == c.get(i)) ? 'qselected' : '');
- });
- },
-
- updateSearchfilter: function(id, type)
+ // 'noload' = (boolean) If true, don't load the mailbox
+ quicksearchClear: function(noload)
{
- this._setSearchfilterParams(id, type);
- if ($F('msgList_filter')) {
- this.viewport.runFilter();
+ if (this.isSearch()) {
+ this._setFilterText(true);
+ $('quicksearch_close').hide();
+ this.resetSelected();
+ if (!noload) {
+ this.loadMailbox(this.sfolder);
+ }
+ this.viewport.deleteView(this.searchid);
}
},
- _addSearchfilterParams: function()
- {
- var sf = this.sfiltersfolder.keys().find(function(s) {
- return $(s).hasClassName('qselected');
- });
- return $H({ searchfolder: this.sfiltersfolder.get(sf), searchmsg: this.sfilters.get(this._getSearchfilterField()) });
- },
-
- _getSearchfilterField: function()
+ // d = (boolean) Deactivate filter input?
+ _setFilterText: function(d)
{
- return this.sfilters.keys().find(function(s) {
- return $(s).hasClassName('qselected');
- });
+ var qs = $('quicksearch');
+ qs.setValue(d ? DIMP.text.search : '');
+ [ qs ].invoke(d ? 'addClassName' : 'removeClassName', 'quicksearchDefault');
},
/* Enable/Disable DIMP action buttons as needed. */
case Event.KEY_ESC:
case Event.KEY_TAB:
// Catch escapes in search box
- if (elt.readAttribute('id') == 'msgList_filter') {
+ if (elt.readAttribute('id') == 'quicksearch') {
if (kc == Event.KEY_ESC || !elt.getValue()) {
- this.searchfilterClear(false);
+ this.quicksearchClear();
}
elt.blur();
e.stop();
if (form.readAttribute('id') == 'RB_folder') {
this.cfolderaction(e);
e.stop();
- } else if (elt.readAttribute('id') == 'msgList_filter') {
- this.searchfilterRun();
+ } else if (elt.readAttribute('id') == 'quicksearch') {
+ if ($F('quicksearch')) {
+ this.quicksearchRun();
+ } else {
+ this.quicksearchClear();
+ }
e.stop();
}
break;
e.stop();
return;
- case 'sf_all':
- case 'sf_current':
- this.updateSearchfilter(id.substring(3), 'folder');
- e.stop();
- return;
-
- case 'sf_msgall':
- case 'sf_from':
- case 'sf_to':
- case 'sf_subject':
- this.updateSearchfilter(id.substring(3), 'msg');
- e.stop();
- return;
-
case 'msglistHeader':
this.sort(e);
e.stop();
e.stop();
return;
- case 'qclose':
- this.searchfilterClear(false);
- e.stop();
- return;
-
case 'applicationfolders':
tmp = e.element();
if (!tmp.hasClassName('custom')) {
return;
}
break;
+
+ case 'quicksearch_close':
+ this.quicksearchClear();
+ break;
}
elt = elt.up();
{
DimpCore.init();
- var DM = DimpCore.DMenu;
+ var DM = DimpCore.DMenu,
+ qs = $('quicksearch');
/* Register global handlers now. */
document.observe('keydown', this.keydownHandler.bindAsEventListener(this));
} else {
this.go('portal');
if (DIMP.conf.background_inbox) {
- this.loadFolder('INBOX', true);
+ this.loadMailbox('INBOX', { background: true });
}
}
}
this._resizeIE6();
- /* Remove unneeded search folders. */
- if (!DIMP.conf.search_all) {
- this.sfiltersfolder.unset('sf_all');
- }
-
/* Remove unavailable menu items. */
if (!$('GrowlerLog')) {
$('alertsloglink').remove();
/* Check for new mail. */
this.setPollFolders();
+ /* Init quicksearch. */
+ qs.observe('focus', this._quicksearchOnFocus.bind(this));
+ qs.observe('blur', this._quicksearchOnBlur.bind(this));
+
if (DIMP.conf.is_ie6) {
/* Disable text selection in preview pane for IE 6. */
document.observe('selectstart', Event.stop);
// Required: content_container, fetch_action, template,
// cachecheck_action, ajaxRequest, buffer_pages,
// limit_factor, content_class, row_class, selected_class
- // Optional: show_split_pane, page_size
+ // Optional: requestParams, show_split_pane, page_size
initialize: function(opts)
{
opts.content = $(opts.content_container);
this.request_num = 1;
},
- // view = ID of view. Can not contain a '%' character.
+ // view = ID of view.
// search = (object) Search parameters
// background = Load view in background?
loadView: function(view, search, background)
// params = TODO
reload: function(params)
{
- if (this.isFiltering()) {
- this.filter.filter(null, params);
- } else {
- this._fetchBuffer({ offset: this.currentOffset(), purge: true, params: params });
- }
+ this._fetchBuffer({ offset: this.currentOffset(), purge: true, params: params });
},
// vs = (Viewport_Selection) A Viewport_Selection object.
this.isbusy = false;
},
- // action = TODO
- // callback = TODO
- addFilter: function(action, callback)
- {
- this.filter = new ViewPort_Filter(this, action, callback);
- },
-
- // val = TODO
- // params = TODO
- runFilter: function(val, params)
- {
- if (this.filter) {
- this.filter.filter(Object.isUndefined(val) ? null : val, params);
- }
- },
-
- // Return: (boolean) Is filtering currently active?
- isFiltering: function()
- {
- return this.filter ? this.filter.isFiltering() : false;
- },
-
- // reset = (boolean) If true, don't update the viewport
- stopFilter: function(reset)
- {
- if (this.filter) {
- this.filter.clear(reset);
- }
- },
-
// noupdate = (boolean) TODO
// nowait = (boolean) TODO
onResize: function(noupdate, nowait)
}
params.set(type, Object.toJSON(value));
- // Are we currently filtering results?
- if (this.isFiltering()) {
- action = this.filter.getAction();
- }
-
// Generate a unique request ID value based on the search params.
// Since javascript does not have a native hashing function, use a
// local lookup table instead.
var cid = this.getMetaData('cacheid', opts.view),
cached, params, rowlist;
- if (this.isFiltering()) {
- params = this.filter.addFilterParams().merge({ view: this.isFiltering() });
- } else {
- params = this.opts.additionalParams ? this.opts.additionalParams(opts.view || this.view) : $H();
- params.update({ view: opts.view || this.view });
- }
+ params = this.opts.requestParams
+ ? this.opts.requestParams(opts.view || this.view)
+ : $H();
+
+ params.update({ view: opts.view || this.view });
if (cid) {
params.update({ cacheid: cid });
? cached.toJSON()
: '';
}
+
if (cached.length) {
params.update({ cached: cached });
}
}),
/**
- * ViewPort_Filter
- */
-ViewPort_Filter = Class.create({
-
- initialize: function(vp, action, callback)
- {
- this.vp = vp;
- this.action = action;
- this.callback = callback;
-
- this.filtering = this.last_filter = this.last_folder = null;
- },
-
- // val = (string) The string to filter on. if null, will use the last
- // filter string.
- filter: function(val, params)
- {
- params = params || {};
-
- if (val === null) {
- val = this.last_filter;
- } else {
- val = val.toLowerCase();
- if (val == this.last_filter) {
- return;
- }
- }
-
- if (!val) {
- this.clear();
- return;
- }
-
- this.last_filter = val;
-
- if (this.filtering) {
- this.vp._fetchBuffer({ offset: 0, params: params });
- return;
- }
-
- this.filtering = true;
- this.last_folder = this.vp.view;
-
- // Filter visible rows immediately.
- var c = this.vp.opts.content, delrows;
- delrows = c.childElements().findAll(function(n) {
- return n.collectTextNodes().toLowerCase().indexOf(val) == -1;
- });
- if (this.vp.opts.onClearRows) {
- this.vp.opts.onClearRows(delrows);
- }
- delrows.invoke('remove');
- this.vp.scroller.clear();
- if (this.vp.opts.empty && !c.childElements().size()) {
- c.update(this.vp.opts.empty.innerHTML);
- }
-
- this.vp.loadView('%%filter%%');
- },
-
- isFiltering: function()
- {
- return this.filtering ? this.last_folder : false;
- },
-
- getAction: function()
- {
- return this.action;
- },
-
- addFilterParams: function()
- {
- if (!this.filtering) {
- return $H();
- }
-
- var params = $H({ filter: this.last_filter });
-
- // Get parameters from a callback function, if defined.
- if (this.callback) {
- params.update(this.callback());
- }
-
- return params;
- },
-
- clear: function(reset)
- {
- if (this.filtering) {
- this.filtering = null;
- if (!reset) {
- this.vp.loadView(this.last_folder);
- }
- this.vp.deleteView('%%filter%%');
- this.last_filter = this.last_folder = null;
- }
- }
-
-}),
-
-/**
* ViewPort_Selection
*/
ViewPort_Selection = Class.create({
public function ListMessages($args)
{
$mbox = $args['mbox'];
- $search_id = null;
+ $is_search = false;
$sortpref = IMP::getSort($mbox);
- /* If we're searching, do search. */
- if (!empty($args['filter']) &&
- !empty($args['searchfolder']) &&
- !empty($args['searchmsg'])) {
+ /* Check for quicksearch request. */
+ if (strlen($args['qsearch']) &&
+ strlen($args['qsearchmbox'])) {
/* Create the search query. */
$query = new Horde_Imap_Client_Search_Query();
-
- /* Create message search list. */
- switch ($args['searchmsg']) {
- case 'msgall':
- $query->text($args['filter'], false);
- break;
-
- case 'from':
- $query->headerText('From', $args['filter']);
- break;
-
- case 'to':
- $query->headerText('To', $args['filter']);
- break;
-
- case 'subject':
- $query->headerText('Subject', $args['filter']);
- break;
- }
-
- /* Create folder search list. */
- switch ($args['searchfolder']) {
- case 'all':
- $imptree = &IMP_Imap_Tree::singleton();
- $folder_list = $imptree->folderList();
- break;
-
- case 'current':
- $folder_list = array($mbox);
- break;
- }
+ $query->text($args['qsearch'], false);
/* Set the search in the IMP session. */
- $c_ptr = &$_SESSION['imp']['cache'];
- $search_id = $GLOBALS['imp_search']->createSearchQuery($query, $folder_list, array(), _("Search Results"), isset($c_ptr['dimp_searchquery']) ? $c_ptr['dimp_searchquery'] : null);
-
- /* Folder is now the search folder. */
- $mbox = $c_ptr['dimp_searchquery'] = $GLOBALS['imp_search']->createSearchID($search_id);
+ $GLOBALS['imp_search']->createSearchQuery($query, array($args['qsearchmbox']), array(), _("Search Results"), $mbox);
+ $is_search = true;
}
$label = IMP::getLabel($mbox);
if (IMP::isSpecialFolder($mbox)) {
$md->special = 1;
}
- if ($GLOBALS['imp_search']->isSearchMbox($mbox)) {
+ if ($is_search || $GLOBALS['imp_search']->isSearchMbox($mbox)) {
$md->search = 1;
}
if ($GLOBALS['imp_imap']->isReadOnly($mbox)) {
/* Check for mailbox existence now. If there are no messages, there
* is a chance that the mailbox doesn't exist. If there is at least
* 1 message, we don't need this check. */
- if (empty($msgcount) && is_null($search_id)) {
+ if (empty($msgcount) && !$is_search) {
$imp_folder = &IMP_Folder::singleton();
if (!$imp_folder->exists($mbox)) {
$GLOBALS['notification']->push(sprintf(_("Mailbox %s does not exist."), $label), 'horde.error');
$result->data = $this->_getOverviewData($imp_mailbox, $mbox, $data, isset($md->search));
/* Get unseen/thread information. */
- if (is_null($search_id)) {
+ if (!$is_search) {
$imptree = &IMP_Imap_Tree::singleton();
$info = $imptree->getElementInfo($mbox);
if (!empty($info)) {