From: Michael M Slusarz Date: Wed, 16 Sep 2009 05:10:11 +0000 (-0600) Subject: Request #6875: More work on advanced search screen X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=1251a946dbf56697aba3d675fb9c1ae9f1596b39;p=horde.git Request #6875: More work on advanced search screen Add ability to search by a custom defined header. Add documentation for criteria UI object Clean up the way we store flag searches in criteria UI object to be more consistent with other criteria Cleanup the way we output gettext strings on search page Move dimp quicksearch folder ID to IMP_Search::DIMP_QUICKSEARCH --- diff --git a/imp/docs/CHANGES b/imp/docs/CHANGES index 84bfcad83..2c6b25477 100644 --- a/imp/docs/CHANGES +++ b/imp/docs/CHANGES @@ -2,6 +2,7 @@ v5.0-git -------- +[mms] Add ability to search by a custom defined header (Request #6875). [mms] Improved advanced search query interface (Request #6875). [mms] More intelligent ordering of autocomplete search results. [mms] Add a mini search query interface (Request #6875). diff --git a/imp/js/search.js b/imp/js/search.js index 8a494270a..705387e57 100644 --- a/imp/js/search.js +++ b/imp/js/search.js @@ -7,8 +7,7 @@ var ImpSearch = { // The following variables are defined in search.php: - // loading, months, need_criteria, need_folder, need_vfolder_label, - // types + // months, text, types criteria: {}, saved_searches: {}, show_unsub: false, @@ -68,6 +67,10 @@ var ImpSearch = { this.insertText(c.t, c.v, c.n); break; + case 'customhdr': + this.insertCustomHdr(c.v, c.n); + break; + case 'size': this.insertSize(c.t, c.v); break; @@ -77,7 +80,7 @@ var ImpSearch = { break; case 'flag': - this.insertFlag(c.t); + this.insertFlag(c.v); break; } }, this); @@ -118,6 +121,10 @@ var ImpSearch = { this.insertText(val); break; + case 'customhdr': + this.insertCustomHdr(); + break; + case 'size': this.insertSize(val); break; @@ -158,11 +165,24 @@ var ImpSearch = { var tmp = [ new Element('EM').insert(this.getLabel(id)), new Element('INPUT', { type: 'text', size: 25 }), - new Element('SPAN').insert(new Element('INPUT', { checked: Boolean(not), className: 'checkbox', type: 'checkbox' })).insert(this.not_match) + new Element('SPAN').insert(new Element('INPUT', { checked: Boolean(not), className: 'checkbox', type: 'checkbox' })).insert(this.text.not_match) ]; this.criteria[this.insertCriteria(tmp)] = { t: id }; }, + insertCustomHdr: function(text, not) + { + text = text || { h: '', s: '' }; + + var tmp = [ + new Element('EM').insert(this.text.customhdr), + new Element('INPUT', { type: 'text', size: 25 }).setValue(text.h), + new Element('SPAN').insert(new Element('EM').insert(this.text.search_term + ' ')).insert(new Element('INPUT', { type: 'text', size: 25 }).setValue(text.s)), + new Element('SPAN').insert(new Element('INPUT', { checked: Boolean(not), className: 'checkbox', type: 'checkbox' })).insert(this.text.not_match) + ]; + this.criteria[this.insertCriteria(tmp)] = { t: 'customhdr' }; + }, + insertSize: function(id, size) { var tmp = [ @@ -178,7 +198,7 @@ var ImpSearch = { var d = (data ? new Date(data.y, data.m, data.d) : new Date()), tmp = [ new Element('EM').insert(this.getLabel(id)), - new Element('SPAN').insert(new Element('SPAN')).insert(new Element('A', { href: '#', className: 'calendarPopup', title: this.dateselection }).insert(new Element('SPAN', { className: 'searchuiImg searchuiCalendar' }))) + new Element('SPAN').insert(new Element('SPAN')).insert(new Element('A', { href: '#', className: 'calendarPopup', title: this.text.dateselection }).insert(new Element('SPAN', { className: 'searchuiImg searchuiCalendar' }))) ]; this.replaceDate(this.insertCriteria(tmp), id, { y: d.getFullYear(), m: d.getMonth(), d: d.getDate() }); }, @@ -195,7 +215,7 @@ var ImpSearch = { insertFlag: function(id) { var tmp = [ - new Element('EM').insert(this.flag), + new Element('EM').insert(this.text.flag), this.getLabel(id).slice(0, -2) ]; this.criteria[this.insertCriteria(tmp)] = { t: id }; @@ -206,7 +226,9 @@ var ImpSearch = { var data = [], tmp; if (!this._getAll().findAll(function(i) { return i.checked; }).size()) { - alert(this.need_folder); + alert(this.text.need_folder); + } else if ($F('vfolder_save') && $F('vfolder_label').empty()) { + alert(this.text.need_vfolder_label); } else { tmp = $('search_criteria_table').childElements().pluck('id'); if (tmp.size()) { @@ -222,6 +244,11 @@ var ImpSearch = { data.push(this.criteria[c]); break; + case 'customhdr': + this.criteria[c].v = { h: $F($(c).down('INPUT')), s: $F($(c).down('INPUT', 1)) }; + data.push(this.criteria[c]); + break; + case 'size': tmp2 = Number($F($(c).down('INPUT'))); if (!isNaN(tmp2)) { @@ -243,7 +270,7 @@ var ImpSearch = { $('criteria_form').setValue(data.toJSON()); $('search_form').submit(); } else { - alert(this.need_criteria); + alert(this.text.need_criteria); } } }, @@ -280,7 +307,7 @@ var ImpSearch = { case 'link_sub': tmp = this._getAll(); this.show_unsub = !this.show_unsub; - $('search_folders_hdr').next('DIV').update(this.loading); + $('search_folders_hdr').next('DIV').update(this.text.loading); new Ajax.Request($('search_form').readAttribute('action'), { parameters: { show_unsub: Number(this.show_unsub) }, onComplete: this._showFoldersCallback.bind(this, tmp) diff --git a/imp/lib/Search.php b/imp/lib/Search.php index 33e35f1fa..07f9b76f7 100644 --- a/imp/lib/Search.php +++ b/imp/lib/Search.php @@ -8,16 +8,45 @@ * * $_SESSION['imp']['search'] = array( * 'id_1' => array( - * 'c' => (array) List of search criteria. For virtual folders, this - * data is stored in the preferences, + * 'c' => (array) List of search criteria (the IMP-specific data + * structure that allows recreation of the search query on the + * search page). For virtual folders, this data is stored in + * the preferences, * 'f' => (array) List of folders to search, - * 'l' => (string) Description of search, + * 'l' => (string) Description (label) of search, * 'q' => (Horde_Imap_Client_Search_Query) [serialized], * 'v' => (boolean) True if this is a Virtual Folder * ), * .... * ); * + * The format of the 'c' (search criteria) array is as folows: + * array( + * stdClass object { + * 't' => (string) 'Type' - The criteria type + * Values: header, customhdr, body, text, date, size, flag + * 'v' => (mixed) 'Value' - The data used to build the search + * 'header' - (string) The value to search for in the header + * 'customhdr' - (stdClass object) Contains 2 elements: + * 'h' - (string) The header name + * 's' - (string) The search string + * 'body' - (string) The value to search for in the body + * 'text' - (string) The value to search for in the entire + * message + * 'date' - (stdClass object) Contains 3 elements: + * 'y' - (integer) The search year + * 'm' - (integer) The search month (is 1 less than + * the actual month) + * 'd' - (integer) The search day + * 'size' - (integer) The search size in bytes + * 'flag' - (string) The flag to search for + * 'n' => (boolean) 'Not' - Should we do a not search? + * Only used for the following types: header, customhdr, body, + * text + * }, + * ... + * ) + * * Copyright 2002-2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (GPL). If you @@ -31,8 +60,9 @@ class IMP_Search /* The mailbox search prefix. */ const MBOX_PREFIX = 'impsearch\0'; - /* The basic search mailbox name. */ + /* The special search mailbox names. */ const BASIC_SEARCH = 'impbsearch'; + const DIMP_QUICKSEARCH = 'dimpqsearch'; /* Bitmask constants for listQueries(). */ const LIST_SEARCH = 1; @@ -130,7 +160,7 @@ class IMP_Search 'type' => 'header', 'not' => true ), - 'custom' => array( + 'customhdr' => array( 'label' => _("Custom Header"), 'type' => 'customhdr', 'not' => true @@ -629,23 +659,32 @@ class IMP_Search $text_array = array(); foreach ($criteria as $rule) { $field = $rule->t; - - if (isset($flagfields[$field])) { - $text_array[] = sprintf(_("flagged \"%s\""), $flagfields[$field]); - } else { - switch ($searchfields[$field]['type']) { - case 'date': - $text_array[] = sprintf("%s '%s'", $searchfields[$field]['label'], strftime("%x", mktime(0, 0, 0, $rule->v->m + 1, $rule->v->d, $rule->v->y))); - break; - - case 'size': - $text_array[] = $searchfields[$field]['label'] . ' ' . ($rule->v / 1024); - break; - - default: - $text_array[] = sprintf("%s for '%s'", $searchfields[$field]['label'], ((!empty($rule->n)) ? _("not") . ' ' : '') . $rule->v); - break; + $type = isset($searchfields[$field]['type']) + ? $searchfields[$field]['type'] + : $field; + + switch ($searchfields[$field]['type']) { + case 'flag': + if (isset($flagfields[$rule->v])) { + $text_array[] = sprintf(_("flagged \"%s\""), $flagfields[$field]); } + break; + + case 'date': + $text_array[] = sprintf("%s '%s'", $searchfields[$field]['label'], strftime("%x", mktime(0, 0, 0, $rule->v->m + 1, $rule->v->d, $rule->v->y))); + break; + + case 'size': + $text_array[] = $searchfields[$field]['label'] . ' ' . ($rule->v / 1024); + break; + + case 'customhdr': + $text_array[] = sprintf("%s for '%s'", $rule->v->h, ((!empty($rule->n)) ? _("not") . ' ' : '') . $rule->v->s); + break; + + default: + $text_array[] = sprintf("%s for '%s'", $searchfields[$field]['label'], ((!empty($rule->n)) ? _("not") . ' ' : '') . $rule->v); + break; } } diff --git a/imp/lib/UI/Search.php b/imp/lib/UI/Search.php index 34feb3a06..79891728a 100644 --- a/imp/lib/UI/Search.php +++ b/imp/lib/UI/Search.php @@ -32,43 +32,55 @@ class IMP_UI_Search foreach ($search as $rule) { $ob = new Horde_Imap_Client_Search_Query(); - if (isset($flag_fields[$rule->t])) { - $val = $imp_flags->parseFormId($rule->t); - $ob->flag($val['flag'], $val['set']); - $search_array[] = $ob; - } else { - /* Ignore unknown types. */ - switch ($search_fields[$rule->t]['type']) { - case 'header': - if (!empty($rule->v)) { - $ob->headerText($rule->t, $rule->v, !empty($rule->n)); - $search_array[] = $ob; - } - break; - - case 'body': - case 'text': - if (!empty($rule->v)) { - $ob->text($rule->c, $search_fields[$rule->t]['type'] == 'body', !empty($rule->n)); - $search_array[] = $ob; - } - break; - - case 'date': - if (!empty($rule->v)) { - $date = new Horde_Date(array('year' => $rule->v->y, 'month' => $rule->v->m + 1, 'mday' => $rule->v->d)); - $ob->dateSearch($date, ($rule->t == 'date_on') ? Horde_Imap_Client_Search_Query::DATE_ON : (($rule->t == 'date_until') ? Horde_Imap_Client_Search_Query::DATE_BEFORE : Horde_Imap_Client_Search_Query::DATE_SINCE)); - $search_array[] = $ob; - } - break; - - case 'size': - if (!empty($rule->v)) { - $ob->size(intval($rule->v), $rule->t == 'size_larger'); - $search_array[] = $ob; - } - break; + $type = isset($search_fields[$rule->t]['type']) + ? $search_fields[$rule->t]['type'] + : $rule->t; + + switch ($type) { + case 'flag': + if (isset($flag_fields[$rule->v])) { + $val = $imp_flags->parseFormId($rule->t); + $ob->flag($val['flag'], $val['set']); + $search_array[] = $ob; + } + break; + + case 'header': + if (!empty($rule->v)) { + $ob->headerText($rule->t, $rule->v, !empty($rule->n)); + $search_array[] = $ob; + } + break; + + case 'customhdr': + if (!empty($rule->v)) { + $ob->headerText($rule->v->h, $rule->v->s, !empty($rule->n)); + $search_array[] = $ob; + } + break; + + case 'body': + case 'text': + if (!empty($rule->v)) { + $ob->text($rule->c, $search_fields[$rule->t]['type'] == 'body', !empty($rule->n)); + $search_array[] = $ob; + } + break; + + case 'date': + if (!empty($rule->v)) { + $date = new Horde_Date(array('year' => $rule->v->y, 'month' => $rule->v->m + 1, 'mday' => $rule->v->d)); + $ob->dateSearch($date, ($rule->t == 'date_on') ? Horde_Imap_Client_Search_Query::DATE_ON : (($rule->t == 'date_until') ? Horde_Imap_Client_Search_Query::DATE_BEFORE : Horde_Imap_Client_Search_Query::DATE_SINCE)); + $search_array[] = $ob; + } + break; + + case 'size': + if (!empty($rule->v)) { + $ob->size(intval($rule->v), $rule->t == 'size_larger'); + $search_array[] = $ob; } + break; } } @@ -108,7 +120,8 @@ class IMP_UI_Search if ($flag) { $tmp = new stdClass; - $tmp->t = $flag; + $tmp->t = 'flag'; + $tmp->v = $flag; $c_list[] = $tmp; } diff --git a/imp/search.php b/imp/search.php index 54f45e0be..a9b8a0aab 100644 --- a/imp/search.php +++ b/imp/search.php @@ -151,15 +151,22 @@ $t->set('f_fields', $f_fields); Horde_UI_JsCalendar::init(); +/* Gettext strings for this page. */ +$gettext_strings = array( + 'customhdr' => _("Custom Header:"), + 'dateselection' => _("Date Selection"), + 'flag' => _("Flag:"), + 'loading' => _("Loading..."), + 'need_criteria' => _("Please select at least one search criteria."), + 'need_folder' => _("Please select at least one folder to search."), + 'need_vfolder_label' => _("Virtual Folders require a label."), + 'not_match' => _("Do NOT Match"), + 'search_term' => _("Search Term:") +); + Horde::addInlineScript(array( - 'ImpSearch.dateselection = ' . Horde_Serialize::serialize(_("Date Selection"), Horde_Serialize::JSON, $charset), - 'ImpSearch.flag = ' . Horde_Serialize::serialize(_("Flag:"), Horde_Serialize::JSON, $charset), - 'ImpSearch.loading = ' . Horde_Serialize::serialize(_("Loading..."), Horde_Serialize::JSON, $charset), 'ImpSearch.months = ' . Horde_Serialize::serialize(Horde_UI_JsCalendar::months(), Horde_Serialize::JSON, $charset), - 'ImpSearch.need_criteria = ' . Horde_Serialize::serialize(_("Please select at least one search criteria."), Horde_Serialize::JSON, $charset), - 'ImpSearch.need_folder = ' . Horde_Serialize::serialize(_("Please select at least one folder to search."), Horde_Serialize::JSON, $charset), - 'ImpSearch.need_vfolder_label = ' . Horde_Serialize::serialize(_("Virtual Folders require a label."), Horde_Serialize::JSON, $charset), - 'ImpSearch.not_match = ' . Horde_Serialize::serialize(_("Do NOT Match"), Horde_Serialize::JSON, $charset), + 'ImpSearch.text = ' . Horde_Serialize::serialize($gettext_strings, Horde_Serialize::JSON, $charset), 'ImpSearch.types = ' . Horde_Serialize::serialize($types, Horde_Serialize::JSON, $charset) )); Horde::addInlineScript($on_domload, 'dom'); diff --git a/imp/templates/javascript_defs_dimp.php b/imp/templates/javascript_defs_dimp.php index 2de28ce59..e1ae82abe 100644 --- a/imp/templates/javascript_defs_dimp.php +++ b/imp/templates/javascript_defs_dimp.php @@ -71,7 +71,7 @@ $code['conf'] = array_filter(array( 'popup_height' => 610, 'popup_width' => 820, 'preview_pref' => intval($GLOBALS['prefs']->getValue('dimp_show_preview')), - 'qsearchid' => IMP_Search::MBOX_PREFIX . 'dimpqsearch', + 'qsearchid' => IMP_Search::MBOX_PREFIX . IMP_Search::DIMP_QUICKSEARCH, 'qsearchfield' => $GLOBALS['prefs']->getValue('dimp_qsearch_field'), 'refresh_time' => intval($GLOBALS['prefs']->getValue('refresh_time')), 'searchprefix' => IMP_Search::MBOX_PREFIX,