Bug #6875: Implement "basic" search UI
authorMichael M Slusarz <slusarz@curecanti.org>
Mon, 10 Aug 2009 23:46:14 +0000 (17:46 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Tue, 25 Aug 2009 05:24:18 +0000 (23:24 -0600)
imp/ajax.php
imp/docs/CHANGES
imp/js/DimpBase.js
imp/lib/Search.php
imp/lib/UI/Search.php [new file with mode: 0644]
imp/mailbox.php
imp/search-basic.php [new file with mode: 0644]
imp/search.php
imp/templates/javascript_defs_dimp.php
imp/templates/search/search-basic.html [new file with mode: 0644]

index a819db0..11aa25f 100644 (file)
@@ -769,6 +769,13 @@ case 'SMIMEPersonal':
     }
 
     break;
+
+case 'BasicSearch':
+    $result = new stdClass;
+    $imp_ui_search = new IMP_UI_Search();
+    parse_str(Horde_Util::getPost('query'), $query);
+    $result->view = $imp_search->createSearchID($imp_ui_search->processBasicSearch($query['search_basic_mbox'], $query['search_criteria'], $query['search_criteria_text'], !empty($query['search_criteria_not']), $query['search_flags']));
+    break;
 }
 
 // Clear the output buffer that we started above, and log any unexpected
index 3ee992f..30ac347 100644 (file)
@@ -2,6 +2,7 @@
 v5.0-git
 --------
 
+[mms] Add a mini search query interface (Request #6875).
 [mms] Make DIMP quicksearch field selection persist across sessions.
 [mms] Move JS/CSS caching to Horde framework.
 [mms] Add simple search function to MIMP.
index 453ab3c..ea25826 100644 (file)
@@ -393,7 +393,7 @@ var DimpBase = {
 
             // Callbacks
             onAjaxRequest: function(id) {
-                var p = this.isSearch(id)
+                var p = this.isSearch(id) && $('qsearch_input').visible()
                     ? $H({
                         qsearch: $F('qsearch_input'),
                         qsearchmbox: this.sfolder
@@ -762,7 +762,9 @@ var DimpBase = {
             break;
 
         case 'ctx_qsearchopts_basic':
-            alert('Placeholder for basic search');
+            RedBox.overlay = true;
+            RedBox.loading();
+            new Ajax.Request(DIMP.conf.URI_SEARCH_BASIC, { parameters: DimpCore.addRequestParams($H({ search_mailbox: this.folder })), onComplete: function(r) { RedBox.showHtml(r.responseText); } });
             break;
 
         case 'ctx_qsearchopts_advanced':
@@ -1301,7 +1303,8 @@ var DimpBase = {
     /* Search functions. */
     isSearch: function(id)
     {
-        return (id ? id : this.folder) == DIMP.conf.qsearchid;
+        id = id ? id : this.folder;
+        return id && id.startsWith(DIMP.conf.searchprefix);
     },
 
     _quicksearchOnBlur: function()
@@ -1326,16 +1329,19 @@ var DimpBase = {
     // 'noload' = (boolean) If true, don't load the mailbox
     quicksearchClear: function(noload)
     {
+        var f = this.folder;
+
         if (this.isSearch()) {
             $('qsearch_close').hide();
             if (!$('qsearch').hasClassName('qsearchFocus')) {
                 this._setFilterText(true);
             }
             this.resetSelected();
+            $('qsearch_input').show();
             if (!noload) {
                 this.loadMailbox(this.sfolder);
             }
-            this.viewport.deleteView(DIMP.conf.qsearchid);
+            this.viewport.deleteView(f);
         }
     },
 
@@ -1346,6 +1352,16 @@ var DimpBase = {
         [ $('qsearch') ].invoke(d ? 'removeClassName' : 'addClassName', 'qsearchActive');
     },
 
+    _basicSearchCallback: function(r)
+    {
+        r = r.response;
+        RedBox.close();
+        this.sfolder = this.folder;
+        $('qsearch_close').show();
+        $('qsearch_input').hide();
+        this.go('folder:' + r.view);
+    },
+
     /* Enable/Disable DIMP action buttons as needed. */
     toggleButtons: function()
     {
@@ -1733,6 +1749,15 @@ var DimpBase = {
                     this._closeRedBox();
                     e.stop();
                     return;
+                } else if (elt.hasClassName('basicSearchCancel')) {
+                    RedBox.close();
+                    e.stop();
+                    return;
+                } else if (elt.hasClassName('basicSearchSubmit')) {
+                    elt.disable();
+                    DimpCore.doAction('BasicSearch', { query: $('RB_window').down().serialize() }, null, this._basicSearchCallback.bind(this));
+                    e.stop();
+                    return;
                 }
             }
 
index a8b0736..ef4405d 100644 (file)
  */
 class IMP_Search
 {
-    /* Defines used to determine what kind of field query we are dealing
-     * with. */
-    const HEADER = 1;
-    const BODY = 2;
-    const DATE = 3;
-    const TEXT = 4;
-    const SIZE = 5;
-
-    /* Defines used to identify the flag input. */
-    const FLAG_NOT = 0;
-    const FLAG_HAS = 1;
-
-    /* Defines used to identify whether to show unsubscribed folders. */
-    const SHOW_UNSUBSCRIBED = 0;
-    const SHOW_SUBSCRIBED_ONLY = 1;
-
     /* The mailbox search prefix. */
     const MBOX_PREFIX = 'impsearch\0';
 
@@ -533,37 +517,40 @@ class IMP_Search
             return $_SESSION['imp']['search'][$id]['label'];
         }
 
-        $flagfields = $this->flagFields();
-        $searchfields = $this->searchFields();
+        $imp_ui_search = new IMP_UI_Search();
+
+        $flagfields = $imp_ui_search->flagFields();
+        $searchfields = $imp_ui_search->searchFields();
         $text = '';
         $uiinfo = $this->retrieveUIQuery($id);
 
-        if (!empty($uiinfo['field'])) {
-            $text = _("Search") . ' ';
-            $text_array = array();
-            foreach ($uiinfo['field'] as $key2 => $val2) {
-                if (isset($flagfields[$val2])) {
-                    $text_array[] = $flagfields[$val2]['label'];
-                } else {
-                    switch ($searchfields[$val2]['type']) {
-                    case self::DATE:
-                        $text_array[] = sprintf("%s '%s'", $searchfields[$val2]['label'], strftime("%x", mktime(0, 0, 0, $uiinfo['date'][$key2]['month'], $uiinfo['date'][$key2]['day'], $uiinfo['date'][$key2]['year'])));
-                        break;
-
-                    case self::SIZE:
-                        $text_array[] = $searchfields[$val2]['label'] . ' ' . ($uiinfo['text'][$key2] / 1024);
-                        break;
-
-                    default:
-                        $text_array[] = sprintf("%s for '%s'", $searchfields[$val2]['label'], ((!empty($uiinfo['text_not'][$key2])) ? _("not") . ' ' : '') . $uiinfo['text'][$key2]);
-                        break;
-                    }
+        if (empty($uiinfo['field'])) {
+            return '';
+        }
+
+        $text = _("Search") . ' ';
+        $text_array = array();
+        foreach ($uiinfo['field'] as $key2 => $val2) {
+            if (isset($flagfields[$val2])) {
+                $text_array[] = $flagfields[$val2]['label'];
+            } else {
+                switch ($searchfields[$val2]['type']) {
+                case IMP_UI_Search::DATE:
+                    $text_array[] = sprintf("%s '%s'", $searchfields[$val2]['label'], strftime("%x", mktime(0, 0, 0, $uiinfo['date'][$key2]['month'], $uiinfo['date'][$key2]['day'], $uiinfo['date'][$key2]['year'])));
+                    break;
+
+                case IMP_UI_Search::SIZE:
+                    $text_array[] = $searchfields[$val2]['label'] . ' ' . ($uiinfo['text'][$key2] / 1024);
+                    break;
+
+                default:
+                    $text_array[] = sprintf("%s for '%s'", $searchfields[$val2]['label'], ((!empty($uiinfo['text_not'][$key2])) ? _("not") . ' ' : '') . $uiinfo['text'][$key2]);
+                    break;
                 }
             }
-            $text .= implode(' ' . (($uiinfo['match'] == 'and') ? _("and") : _("or")) . ' ', $text_array);
         }
 
-        return $text . ' ' . _("in") . ' ' . implode(', ', $uiinfo['folders']);
+        $text .= implode(' ' . (($uiinfo['match'] == 'and') ? _("and") : _("or")) . ' ', $text_array) . ' ' . _("in") . ' ' . implode(', ', $uiinfo['folders']);
     }
 
     /**
@@ -668,195 +655,4 @@ class IMP_Search
         return self::MBOX_PREFIX . $this->_strip($id);
     }
 
-    /**
-     * Return the base search fields.
-     *
-     * @return array  The base search fields.
-     */
-    public function searchFields()
-    {
-        return array(
-            'from' => array(
-                'label' => _("From"),
-                'type' => self::HEADER,
-                'not' => true
-            ),
-            'to' => array(
-                'label' => _("To"),
-                'type' => self::HEADER,
-                'not' => true
-            ),
-            'cc' => array(
-                'label' => _("Cc"),
-                'type' => self::HEADER,
-                'not' => true
-            ),
-            'bcc' => array(
-                'label' => _("Bcc"),
-                'type' => self::HEADER,
-                'not' => true
-            ),
-            'subject' => array(
-                'label' => _("Subject"),
-                'type' => self::HEADER,
-                'not' => true
-            ),
-            'body' => array(
-               'label' => _("Body"),
-               'type' => self::BODY,
-                'not' => true
-            ),
-            'text' => array(
-               'label' => _("Entire Message"),
-               'type' => self::TEXT,
-                'not' => true
-            ),
-            'date_on' => array(
-                'label' => _("Date ="),
-                'type' => self::DATE,
-                'not' => true
-            ),
-            'date_until' => array(
-                'label' => _("Date <"),
-                'type' => self::DATE,
-                'not' => true
-            ),
-            'date_since' => array(
-                'label' => _("Date >="),
-                'type' => self::DATE,
-                'not' => true
-            ),
-            // Displayed in KB, but stored internally in bytes
-            'size_smaller' => array(
-                'label' => _("Size (KB) <"),
-                'type' => self::SIZE,
-                'not' => false
-            ),
-            // Displayed in KB, but stored internally in bytes
-            'size_larger' => array(
-                'label' => _("Size (KB) >"),
-                'type' => self::SIZE,
-                'not' => false
-            ),
-        );
-    }
-
-    /**
-     * Return the base flag fields.
-     *
-     * @return array  The base flag fields.
-     */
-    public function flagFields()
-    {
-        return array(
-            'seen' => array(
-                'flag' => '\\seen',
-                'label' => _("Seen messages"),
-                'type' => self::FLAG_HAS
-            ),
-            'unseen' => array(
-                'flag' => '\\seen',
-                'label' => _("Unseen messages"),
-                'type' => self::FLAG_NOT
-            ),
-            'answered' => array(
-                'flag' => '\\answered',
-                'label' => _("Answered messages"),
-                'type' => self::FLAG_HAS
-            ),
-            'unanswered' => array(
-                'flag' => '\\answered',
-                'label' => _("Unanswered messages"),
-                'type' => self::FLAG_NOT
-            ),
-            'flagged' => array(
-                'flag' => '\\flagged',
-                'label' => _("Flagged messages"),
-                'type' => self::FLAG_HAS
-            ),
-            'unflagged' => array(
-                'flag' => '\\flagged',
-                'label' => _("Unflagged messages"),
-                'type' => self::FLAG_NOT
-            ),
-            'deleted' => array(
-                'flag' => '\\deleted',
-                'label' => _("Deleted messages"),
-                'type' => self::FLAG_HAS
-            ),
-            'undeleted' => array(
-                'flag' => '\\deleted',
-                'label' => _("Undeleted messages"),
-                'type' => self::FLAG_NOT
-            ),
-        );
-    }
-
-    /**
-     * Creates a search query.
-     *
-     * @param array $uiinfo  A UI info array (see imp/search.php).
-     *
-     * @return object  A search object (Horde_Imap_Client_Search_Query).
-     */
-    public function createQuery($search)
-    {
-        $query = new Horde_Imap_Client_Search_Query();
-
-        $search_array = array();
-        $search_fields = $this->searchFields();
-        $flag_fields = $this->flagFields();
-
-        foreach ($search['field'] as $key => $val) {
-            $ob = new Horde_Imap_Client_Search_Query();
-
-            if (isset($flag_fields[$val])) {
-                $ob->flag($flag_fields[$val]['flag'], (bool)$flag_fields[$val]['type']);
-                $search_array[] = $ob;
-            } else {
-                switch ($search_fields[$val]['type']) {
-                case self::HEADER:
-                    if (!empty($search['text'][$key])) {
-                        $ob->headerText($val, $search['text'][$key], $search['text_not'][$key]);
-                        $search_array[] = $ob;
-                    }
-                    break;
-
-                case self::BODY:
-                case self::TEXT:
-                    if (!empty($search['text'][$key])) {
-                        $ob->text($search['text'][$key], $search_fields[$val]['type'] == self::BODY, $search['text_not'][$key]);
-                        $search_array[] = $ob;
-                    }
-                    break;
-
-                case self::DATE:
-                    if (!empty($search['date'][$key]['day']) &&
-                        !empty($search['date'][$key]['month']) &&
-                        !empty($search['date'][$key]['year'])) {
-                        $date = new Horde_Date($search['date']);
-                        $ob->dateSearch($date, ($val == 'date_on') ? Horde_Imap_Client_Search_Query::DATE_ON : (($val == 'date_until') ? Horde_Imap_Client_Search_Query::DATE_BEFORE : Horde_Imap_Client_Search_Query::DATE_SINCE));
-                        $search_array[] = $ob;
-                    }
-                    break;
-
-                case self::SIZE:
-                    if (!empty($search['text'][$key])) {
-                        $ob->size(intval($search['text'][$key]), $val == 'size_larger');
-                        $search_array[] = $ob;
-                    }
-                    break;
-                }
-            }
-        }
-
-        /* Search match. */
-        if ($search['match'] == 'and') {
-            $query->andSearch($search_array);
-        } elseif ($search['match'] == 'or') {
-            $query->orSearch($search_array);
-        }
-
-        return $query;
-    }
 }
diff --git a/imp/lib/UI/Search.php b/imp/lib/UI/Search.php
new file mode 100644 (file)
index 0000000..89dc917
--- /dev/null
@@ -0,0 +1,247 @@
+<?php
+/**
+ * The IMP_UI_Search:: class is designed to provide a place to store common
+ * code shared among IMP's various UI views for the search page.
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author  Michael Slusarz <slusarz@horde.org>
+ * @package IMP
+ */
+class IMP_UI_Search
+{
+    /* Defines used to determine what kind of field query we are dealing
+     * with. */
+    const HEADER = 1;
+    const BODY = 2;
+    const DATE = 3;
+    const TEXT = 4;
+    const SIZE = 5;
+
+    /* Defines used to identify the flag input. */
+    const FLAG_NOT = 0;
+    const FLAG_HAS = 1;
+
+    /**
+     * Return the base search fields.
+     *
+     * @return array  The base search fields.
+     */
+    public function searchFields()
+    {
+        return array(
+            'from' => array(
+                'label' => _("From"),
+                'type' => self::HEADER,
+                'not' => true
+            ),
+            'to' => array(
+                'label' => _("To"),
+                'type' => self::HEADER,
+                'not' => true
+            ),
+            'cc' => array(
+                'label' => _("Cc"),
+                'type' => self::HEADER,
+                'not' => true
+            ),
+            'bcc' => array(
+                'label' => _("Bcc"),
+                'type' => self::HEADER,
+                'not' => true
+            ),
+            'subject' => array(
+                'label' => _("Subject"),
+                'type' => self::HEADER,
+                'not' => true
+            ),
+            'body' => array(
+               'label' => _("Body"),
+               'type' => self::BODY,
+                'not' => true
+            ),
+            'text' => array(
+               'label' => _("Entire Message"),
+               'type' => self::TEXT,
+                'not' => true
+            ),
+            'date_on' => array(
+                'label' => _("Date ="),
+                'type' => self::DATE,
+                'not' => true
+            ),
+            'date_until' => array(
+                'label' => _("Date <"),
+                'type' => self::DATE,
+                'not' => true
+            ),
+            'date_since' => array(
+                'label' => _("Date >="),
+                'type' => self::DATE,
+                'not' => true
+            ),
+            // Displayed in KB, but stored internally in bytes
+            'size_smaller' => array(
+                'label' => _("Size (KB) <"),
+                'type' => self::SIZE,
+                'not' => false
+            ),
+            // Displayed in KB, but stored internally in bytes
+            'size_larger' => array(
+                'label' => _("Size (KB) >"),
+                'type' => self::SIZE,
+                'not' => false
+            ),
+        );
+    }
+
+    /**
+     * Return the base flag fields.
+     *
+     * @return array  The base flag fields.
+     */
+    public function flagFields()
+    {
+        return array(
+            'seen' => array(
+                'flag' => '\\seen',
+                'label' => _("Seen messages"),
+                'type' => self::FLAG_HAS
+            ),
+            'unseen' => array(
+                'flag' => '\\seen',
+                'label' => _("Unseen messages"),
+                'type' => self::FLAG_NOT
+            ),
+            'answered' => array(
+                'flag' => '\\answered',
+                'label' => _("Answered messages"),
+                'type' => self::FLAG_HAS
+            ),
+            'unanswered' => array(
+                'flag' => '\\answered',
+                'label' => _("Unanswered messages"),
+                'type' => self::FLAG_NOT
+            ),
+            'flagged' => array(
+                'flag' => '\\flagged',
+                'label' => _("Flagged messages"),
+                'type' => self::FLAG_HAS
+            ),
+            'unflagged' => array(
+                'flag' => '\\flagged',
+                'label' => _("Unflagged messages"),
+                'type' => self::FLAG_NOT
+            ),
+            'deleted' => array(
+                'flag' => '\\deleted',
+                'label' => _("Deleted messages"),
+                'type' => self::FLAG_HAS
+            ),
+            'undeleted' => array(
+                'flag' => '\\deleted',
+                'label' => _("Undeleted messages"),
+                'type' => self::FLAG_NOT
+            ),
+        );
+    }
+
+    /**
+     * Creates a search query.
+     *
+     * @param array $uiinfo  A UI info array (see imp/search.php).
+     *
+     * @return object  A search object (Horde_Imap_Client_Search_Query).
+     */
+    public function createQuery($search)
+    {
+        $query = new Horde_Imap_Client_Search_Query();
+
+        $search_array = array();
+        $search_fields = $this->searchFields();
+        $flag_fields = $this->flagFields();
+
+        foreach ($search['field'] as $key => $val) {
+            $ob = new Horde_Imap_Client_Search_Query();
+
+            if (isset($flag_fields[$val])) {
+                $ob->flag($flag_fields[$val]['flag'], (bool)$flag_fields[$val]['type']);
+                $search_array[] = $ob;
+            } else {
+                switch ($search_fields[$val]['type']) {
+                case self::HEADER:
+                    if (!empty($search['text'][$key])) {
+                        $ob->headerText($val, $search['text'][$key], $search['text_not'][$key]);
+                        $search_array[] = $ob;
+                    }
+                    break;
+
+                case self::BODY:
+                case self::TEXT:
+                    if (!empty($search['text'][$key])) {
+                        $ob->text($search['text'][$key], $search_fields[$val]['type'] == self::BODY, $search['text_not'][$key]);
+                        $search_array[] = $ob;
+                    }
+                    break;
+
+                case self::DATE:
+                    if (!empty($search['date'][$key]['day']) &&
+                        !empty($search['date'][$key]['month']) &&
+                        !empty($search['date'][$key]['year'])) {
+                        $date = new Horde_Date($search['date']);
+                        $ob->dateSearch($date, ($val == 'date_on') ? Horde_Imap_Client_Search_Query::DATE_ON : (($val == 'date_until') ? Horde_Imap_Client_Search_Query::DATE_BEFORE : Horde_Imap_Client_Search_Query::DATE_SINCE));
+                        $search_array[] = $ob;
+                    }
+                    break;
+
+                case self::SIZE:
+                    if (!empty($search['text'][$key])) {
+                        $ob->size(intval($search['text'][$key]), $val == 'size_larger');
+                        $search_array[] = $ob;
+                    }
+                    break;
+                }
+            }
+        }
+
+        /* Search match. */
+        if ($search['match'] == 'and') {
+            $query->andSearch($search_array);
+        } elseif ($search['match'] == 'or') {
+            $query->orSearch($search_array);
+        }
+
+        return $query;
+    }
+
+    /**
+     *
+     */
+    public function processBasicSearch($mbox, $criteria, $text, $not, $flag)
+    {
+        $search_query = array(
+            'field' => array(),
+            'match' => 'and',
+            'text' => array(),
+            'text_not' => array()
+        );
+
+        if ($criteria) {
+            $search_query['field'][] = $criteria;
+            $search_query['text'][] = $text;
+            $search_query['text_not'][] = $not;
+        }
+
+        if ($flag) {
+            $search_query['field'][] = $flag;
+            $search_query['text'][] = $search_query['text_not'][] = null;
+        }
+
+        /* Set the search in the IMP session. */
+        return $GLOBALS['imp_search']->createSearchQuery($this->createQuery($search_query), array($mbox), array(), _("Search Results"));
+    }
+
+}
index f818337..4b0dcc2 100644 (file)
@@ -370,12 +370,17 @@ if ($unread) {
 }
 
 if ($vfolder || $search_mbox) {
-    $query_text = htmlspecialchars(wordwrap($imp_search->searchQueryText($imp_search->searchMboxID())));
-    if ($vfolder) {
-        $pagetitle .= ' [' . Horde::linkTooltip('#', $query_text, '', '', '', $query_text) . _("Virtual Folder") . '</a>]';
-        $title .= ' [' . _("Virtual Folder") . ']';
+    $query_text = $imp_search->searchQueryText($imp_search->searchMboxID());
+    if ($query_text) {
+        $query_text = htmlspecialchars(wordwrap($query_text));
+        if ($vfolder) {
+            $pagetitle .= ' [' . Horde::linkTooltip('#', $query_text, '', '', '', $query_text) . _("Virtual Folder") . '</a>]';
+            $title .= ' [' . _("Virtual Folder") . ']';
+        } else {
+            $pagetitle = Horde::linkTooltip('#', $query_text, '', '', '', $query_text) . $pagetitle . '</a>';
+        }
     } else {
-        $pagetitle = Horde::linkTooltip('#', $query_text, '', '', '', $query_text) . $pagetitle . '</a>';
+        $pagetitle = htmlspecialchars($title);
     }
 } else {
     $pagetitle = $title = htmlspecialchars($title);
@@ -430,7 +435,7 @@ if (isset($filter_url)) {
 $hdr_template->set('search', false);
 if ($_SESSION['imp']['protocol'] != 'pop') {
     if (!$search_mbox) {
-        $hdr_template->set('search', Horde::link(Horde_Util::addParameter(Horde::applicationUrl('search.php'), 'search_mailbox', $imp_mbox['mailbox']), sprintf(_("Search %s"), $rawtitle)) . Horde::img('search.png', _("Search")) . '</a>');
+        $hdr_template->set('search', Horde::link(Horde_Util::addParameter(Horde::applicationUrl('search-basic.php'), 'search_mailbox', $imp_mbox['mailbox']), sprintf(_("Search %s"), $rawtitle)) . Horde::img('search.png', _("Search")) . '</a>');
         if (!$readonly) {
             $hdr_template->set('empty', Horde::link(Horde_Util::addParameter($mailbox_imp_url, array('actionID' => 'empty_mailbox', 'mailbox' => $imp_mbox['mailbox'], 'mailbox_token' => $mailbox_token)), _("Empty folder"), '', '', "ImpMailbox.confirmDialog(this.href, '" . addslashes(_("Are you sure you wish to delete all mail in this folder?")) . "'); return false;") . Horde::img('empty_spam.png', _("Empty folder")) . '</a>');
         }
@@ -438,11 +443,14 @@ if ($_SESSION['imp']['protocol'] != 'pop') {
         if ($imp_search->isEditableVFolder()) {
             $edit_search = sprintf(_("Edit Virtual Folder Definition for %s"), htmlspecialchars($rawtitle));
             $hdr_template->set('delete_vfolder', Horde::link($imp_search->deleteURL(), sprintf(_("Delete Virtual Folder Definition for %s"), htmlspecialchars($rawtitle)), null, null, "if (confirm('" . addslashes(_("Are you sure you want to delete this Virtual Folder Definition?")) . "')) { return true; } else { return false; }") . Horde::img('delete.png', sprintf(_("Delete Virtual Folder Definition for %s"), $rawtitle), '', $graphicsdir) . '</a>');
-        } else {
-            if (!$vfolder) {
-                $edit_search = _("Edit Search Query");
-            }
+        } elseif (!$query_text) {
+            /* Mini search results. */
+            reset($mbox_info['uids']);
+            $hdr_template->set('search', Horde::link(Horde_Util::addParameter(Horde::applicationUrl('search-basic.php'), 'search_mailbox', key($mbox_info['uids'])), sprintf(_("Search %s"), IMP::getLabel(key($mbox_info['uids'])))) . Horde::img('search.png', _("Search")) . '</a>');
+        } elseif (!$vfolder) {
+            $edit_search = _("Edit Search Query");
         }
+
         if (isset($edit_search)) {
             $hdr_template->set('search', Horde::link($imp_search->editURL(), $edit_search) . Horde::img('edit.png', $edit_search, '', $graphicsdir) . '</a>');
         }
diff --git a/imp/search-basic.php b/imp/search-basic.php
new file mode 100644 (file)
index 0000000..ad7a853
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+/**
+ * IMP basic search script.
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author  Michael Slusarz <slusarz@horde.org>
+ * @package IMP
+ */
+
+require_once dirname(__FILE__) . '/lib/Application.php';
+new IMP_Application(array('init' => true));
+
+if ($_SESSION['imp']['protocol'] == 'pop') {
+    if ($_SESSION['imp']['view'] == 'imp') {
+        $notification->push(_("Searching is not available with a POP3 server."), 'horde.error');
+        $from_message_page = true;
+        $actionID = $start = null;
+        require_once IMP_BASE . '/mailbox.php';
+    }
+    exit;
+}
+
+$imp_ui_search = new IMP_UI_Search();
+
+/* If search_basic_mbox is set, we are processing the search query. */
+$search_mailbox = Horde_Util::getFormData('search_basic_mbox');
+if ($search_mailbox) {
+    $id = $imp_ui_search->processBasicSearch($search_mailbox, Horde_Util::getFormData('search_criteria'), Horde_Util::getFormData('search_criteria_text'), Horde_Util::getFormData('search_criteria_not'), Horde_Util::getFormData('search_flags'));
+
+    /* Redirect to the mailbox screen. */
+    header('Location: ' . Horde_Util::addParameter(Horde::applicationUrl('mailbox.php', true), 'mailbox', $GLOBALS['imp_search']->createSearchID($id), false));
+    exit;
+}
+
+$f_fields = $s_fields = array();
+$search_mailbox = Horde_Util::getFormData('search_mailbox');
+
+foreach ($imp_ui_search->searchFields() as $key => $val) {
+    if ($val['type'] != IMP_UI_Search::DATE) {
+        $s_fields[$key] = array(
+            'val' => $key,
+            'label' => $val['label']
+        );
+    }
+}
+
+foreach ($imp_ui_search->flagFields() as $key => $val) {
+    $f_fields[$key] = array(
+        'val' => $key,
+        'label' => $val['label']
+    );
+}
+
+/* Prepare the search template. */
+$t = new Horde_Template();
+$t->setOption('gettext', true);
+$t->set('dimpview', $_SESSION['imp']['view'] == 'dimp');
+
+$t->set('action', Horde::applicationUrl('search-basic.php'));
+$t->set('mbox', htmlspecialchars($search_mailbox));
+$t->set('search_title', sprintf(_("Search %s"), htmlspecialchars(IMP::displayFolder($search_mailbox))));
+$t->set('s_fields', $s_fields);
+$t->set('f_fields', $f_fields);
+
+if ($browser->hasFeature('javascript')) {
+    $t->set('advsearch', Horde::link(Horde_Util::addParameter(Horde::applicationUrl('search.php'), array('search_mailbox' => $search_mailbox))));
+}
+
+$title = _("Search");
+if ($_SESSION['imp']['view'] == 'imp') {
+    IMP::prepareMenu();
+    require IMP_TEMPLATES . '/common-header.inc';
+    IMP::menu();
+    IMP::status();
+}
+
+echo $t->fetch(IMP_TEMPLATES . '/search/search-basic.html');
+
+if ($_SESSION['imp']['view'] == 'imp') {
+    require $registry->get('templates', 'horde') . '/common-footer.inc';
+}
index e615941..65a7390 100644 (file)
@@ -30,12 +30,20 @@ if ($_SESSION['imp']['protocol'] == 'pop') {
     exit;
 }
 
+/* Load basic search if javascript is not enabled. */
+if (!$browser->hasFeature('javascript')) {
+    require_once IMP_BASE . '/search-basic.php';
+    exit;
+}
+
+$imp_ui_search = new IMP_UI_Search();
+
 $actionID = Horde_Util::getFormData('actionID');
 $edit_query = Horde_Util::getFormData('edit_query');
 $edit_query_vfolder = Horde_Util::getFormData('edit_query_vfolder');
 $search_mailbox = Horde_Util::getFormData('search_mailbox');
 
-$imp_search_fields = $imp_search->searchFields();
+$imp_search_fields = $imp_ui_search->searchFields();
 
 $charset = Horde_Nls::getCharset();
 
@@ -81,13 +89,13 @@ case 'do_search':
     for ($i = 0; $i <= $search['field_end']; $i++) {
         if (isset($search['field'][$i]) &&
             isset($imp_search_fields[$search['field'][$i]]) &&
-            ($imp_search_fields[$search['field'][$i]]['type'] == IMP_Search::SIZE)) {
+            ($imp_search_fields[$search['field'][$i]]['type'] == IMP_UI_Search::SIZE)) {
             $search['text'][$i] *= 1024;
         }
     }
 
     /* Create the search query. */
-    $query = $imp_search->createQuery($search);
+    $query = $imp_ui_search->createQuery($search);
 
     /* Save the search as a virtual folder if requested. */
     if (!empty($search['save_vfolder'])) {
@@ -193,7 +201,7 @@ foreach ($imp_search_fields as $key => $val) {
         'sel' => null
     );
 }
-foreach ($imp_search->flagFields() as $key => $val) {
+foreach ($imp_ui_search->flagFields() as $key => $val) {
     $f_fields[$key] = array(
         'val' => $key,
         'label' => $val['label'],
@@ -220,18 +228,18 @@ for ($i = 0; $i <= $search['field_end']; $i++) {
             $fields[$i]['f_fields'][$curr]['sel'] = true;
         } else {
             $fields[$i]['s_fields'][$curr]['sel'] = true;
-            if (in_array($imp_search_fields[$curr]['type'], array(IMP_Search::HEADER, IMP_Search::BODY, IMP_Search::TEXT, IMP_Search::SIZE))) {
+            if (in_array($imp_search_fields[$curr]['type'], array(IMP_UI_Search::HEADER, IMP_UI_Search::BODY, IMP_UI_Search::TEXT, IMP_UI_Search::SIZE))) {
                 $fields[$i]['search_text'] = true;
                 $fields[$i]['search_text_val'] = (!empty($search['text'][$i])) ? @htmlspecialchars($search['text'][$i], ENT_COMPAT, $charset) : null;
                 if ($retrieve_search &&
-                    ($imp_search_fields[$curr]['type'] == IMP_Search::SIZE)) {
+                    ($imp_search_fields[$curr]['type'] == IMP_UI_Search::SIZE)) {
                     $fields[$i]['search_text_val'] /= 1024;
                 }
                 if ($imp_search_fields[$curr]['not']) {
                     $fields[$i]['show_not'] = true;
                     $fields[$i]['search_text_not'] = (!empty($search['text_not'][$i]));
                 }
-            } elseif ($imp_search_fields[$curr]['type'] == IMP_Search::DATE) {
+            } elseif ($imp_search_fields[$curr]['type'] == IMP_UI_Search::DATE) {
                 if (!isset($curr_date)) {
                     $curr_date = getdate();
                 }
@@ -293,7 +301,7 @@ $t->set('delete_img', $registry->getImageDir('horde') . '/delete.png');
 $t->set('remove', _("Remove Field From Search"));
 
 if ($subscribe) {
-    $t->set('inverse_subscribe', ($shown == IMP_Search::SHOW_UNSUBSCRIBED) ? IMP_Search::SHOW_SUBSCRIBED_ONLY : IMP_Search::SHOW_UNSUBSCRIBED);
+    $t->set('inverse_subscribe', !$shown);
 }
 
 $t->set('mbox', htmlspecialchars($search['mbox']));
index 29dbf31..2de28ce 100644 (file)
@@ -49,6 +49,7 @@ $code['conf'] = array_filter(array(
     'URI_MESSAGE' => Horde::applicationUrl('message-dimp.php'),
     'URI_PREFS' => Horde::getServiceLink('prefsapi', 'imp'),
     'URI_PREFS_IMP' => str_replace('&amp;', '&', Horde::getServiceLink('options', 'imp')),
+    'URI_SEARCH_BASIC' => Horde::applicationUrl('search-basic.php'),
     'URI_VIEW' => Horde::applicationUrl('view.php'),
 
     'SESSION_ID' => defined('SID') ? SID : '',
@@ -73,6 +74,7 @@ $code['conf'] = array_filter(array(
     'qsearchid' => IMP_Search::MBOX_PREFIX . 'dimpqsearch',
     'qsearchfield' => $GLOBALS['prefs']->getValue('dimp_qsearch_field'),
     'refresh_time' => intval($GLOBALS['prefs']->getValue('refresh_time')),
+    'searchprefix' => IMP_Search::MBOX_PREFIX,
     'sortdate' => Horde_Imap_Client::SORT_DATE,
     'sortthread' => Horde_Imap_Client::SORT_THREAD,
     'spam_mbox' => IMP::folderPref($GLOBALS['prefs']->getValue('spam_folder'), true),
diff --git a/imp/templates/search/search-basic.html b/imp/templates/search/search-basic.html
new file mode 100644 (file)
index 0000000..2ef6cbc
--- /dev/null
@@ -0,0 +1,56 @@
+<form method="post" action="<tag:action />">
+<input type="hidden" name="search_basic_mbox" value="<tag:mbox />" />
+
+<h1 class="header">
+ <strong><tag:search_title /></strong>
+</h1>
+
+<table class="item">
+ <tr>
+  <td class="searchUILabel"><gettext>Search Criteria:</gettext></td>
+  <td>
+   <select name="search_criteria">
+    <option value=""><gettext>None</gettext></option>
+    <option value="" disabled="disabled">- - - - - - - - - -</option>
+<loop:s_fields>
+    <option value="<tag:s_fields.val />"><tag:s_fields.label /></option>
+</loop:s_fields>
+   </select>
+  </td>
+  <td>
+   <input type="text" name="search_criteria_text" size="40" />
+  </td>
+  <td>
+   <input type="checkbox" class="checkbox" name="search_criteria_not" />
+   <label for="search_criteria_not"><gettext>Do NOT Match</gettext></label>
+  </td>
+ </tr>
+ <tr>
+  <td class="searchUILabel"><gettext>Search Flags:</gettext></td>
+  <td>
+   <select name="search_flags">
+    <option value=""><gettext>None</gettext></option>
+    <option value="" disabled="disabled">- - - - - - - - - -</option>
+<loop:f_fields>
+    <option value="<tag:f_fields.val />"><tag:f_fields.label /></option>
+</loop:f_fields>
+   </select>
+  </td>
+  <td></td>
+  <td></td>
+ </tr>
+<if:advsearch>
+<tr>
+  <td colspan="5"><tag:advsearch /><gettext>Go to Advanced Search Page...</gettext></td>
+ </tr>
+</if:advsearch>
+</table>
+
+<div>
+ <input type="submit" class="button basicSearchSubmit" value="<gettext>Submit</gettext>" />
+ <input type="reset" class="button basicSearchReset" value="<gettext>Reset</gettext>" />
+<if:dimpview>
+ <input type="button" class="button basicSearchCancel" value="<gettext>Close</gettext>" />
+</if:dimpview>
+</div>
+</form>