Request #3438, Request #6875: Relative date searches
authorMichael M Slusarz <slusarz@curecanti.org>
Wed, 16 Sep 2009 18:25:12 +0000 (12:25 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Wed, 16 Sep 2009 18:25:12 +0000 (12:25 -0600)
imp/docs/CHANGES
imp/js/search.js
imp/lib/Search.php
imp/lib/UI/Search.php
imp/search-basic.php
imp/templates/search/search.html

index 327f3ed..0e0098b 100644 (file)
@@ -2,6 +2,7 @@
 v5.0-git
 --------
 
+[mms] Add ability to search by relative date intervals (Request #3438).
 [mms] Add advanced search query interface to DIMP (Request #6875).
 [mms] Add ability to search by a custom defined header (Request #6875).
 [mms] Improved advanced search query interface (Request #6875).
index 9090e45..f6ad78d 100644 (file)
@@ -79,6 +79,10 @@ var ImpSearch = {
                 this.insertDate(c.t, c.v);
                 break;
 
+            case 'within':
+                this.insertWithin(c.t, c.v);
+                break;
+
             case 'flag':
                 this.insertFlag(c.v);
                 break;
@@ -133,6 +137,10 @@ var ImpSearch = {
                 this.insertDate(val);
                 break;
 
+            case 'within':
+                this.insertWithin(val);
+                break;
+
             case 'flag':
                 this.insertFlag(val);
                 break;
@@ -212,6 +220,18 @@ var ImpSearch = {
         this.criteria[id] = { t: type, v: data };
     },
 
+    insertWithin: function(id, data)
+    {
+        data = data || { l: '', v: '' };
+
+        var tmp = [
+            new Element('EM').insert(this.getLabel(id)),
+            new Element('INPUT', { type: 'text', size: 8 }).setValue(data.v),
+            $($('within_criteria').cloneNode(true)).writeAttribute({ id: null }).show().setValue(data.l)
+        ];
+        this.criteria[this.insertCriteria(tmp)] = { t: id };
+    },
+
     insertFlag: function(id)
     {
         var tmp = [
@@ -262,6 +282,11 @@ var ImpSearch = {
                         data.push(this.criteria[c]);
                         break;
 
+                    case 'within':
+                        this.criteria[c].v = { l: $F($(c).down('SELECT')), v: parseInt($F($(c).down('INPUT')), 10) };
+                        data.push(this.criteria[c]);
+                        break;
+
                     case 'flag':
                         data.push({ t: 'flag', v: this.criteria[c].t });
                         break;
index 07f9b76..ef6aac2 100644 (file)
@@ -24,7 +24,8 @@
  * array(
  *     stdClass object {
  *         't' => (string) 'Type' - The criteria type
- *                Values: header, customhdr, body, text, date, size, flag
+ *                Values: header, customhdr, body, text, date, within, 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:
  *                         'm' - (integer) The search month (is 1 less than
  *                               the actual month)
  *                         'd' - (integer) The search day
+ *                'within' - (stdClass object) Contains 2 elements:
+ *                           'l' - (string) The length of time. Either 'y'
+ *                                 (years), 'm' (months), or 'd' (days)
+ *                           'v' - (integer) The length of time
  *                'size' - (integer) The search size in bytes
  *                'flag' - (string) The flag to search for
  *         'n' => (boolean) 'Not' - Should we do a not search?
@@ -190,6 +195,16 @@ class IMP_Search
                 'type' => 'date',
                 'not' => true
             ),
+            'older' => array(
+                'label' => _("Older Than"),
+                'type' => 'within',
+                'not' => true
+            ),
+            'younger' => array(
+                'label' => _("Younger Than"),
+                'type' => 'within',
+                'not' => true
+            ),
             // Displayed in KB, but stored internally in bytes
             'size_smaller' => array(
                 'label' => _("Size (KB) <"),
@@ -670,16 +685,20 @@ class IMP_Search
                 }
                 break;
 
+            case 'customhdr':
+                $text_array[] = sprintf("%s for '%s'", $rule->v->h, ((!empty($rule->n)) ? _("not") . ' ' : '') . $rule->v->s);
+                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);
+            case 'within':
+                $text_array[] = sprintf("%s %u %s", $searchfields[$field]['label'], $rule->v->v, $rule->v->l == 'y' ? _("years") : ($rule->v->l == 'm' ? _("months") : _("days")));
                 break;
 
-            case 'customhdr':
-                $text_array[] = sprintf("%s for '%s'", $rule->v->h, ((!empty($rule->n)) ? _("not") . ' ' : '') . $rule->v->s);
+            case 'size':
+                $text_array[] = $searchfields[$field]['label'] . ' ' . ($rule->v / 1024);
                 break;
 
             default:
index 7989172..34adf34 100644 (file)
@@ -75,6 +75,27 @@ class IMP_UI_Search
                 }
                 break;
 
+            case 'within':
+                /* Limited to day granularity because that is the technical
+                 * limit for IMAP servers without 'WITHIN' extension. */
+                if (!empty($rule->v)) {
+                    $secs = $rule->v->v * 60 * 60 * 24;
+
+                    switch ($rule->v->l) {
+                    case 'y':
+                        $secs *= 365;
+                        break;
+
+                    case 'm':
+                        $secs *= 30;
+                        break;
+                    }
+
+                    $ob->intervalSearch($secs, $rule->t == 'older' ? Horde_Imap_Client_Search_Query::INTERVAL_OLDER : Horde_Imap_Client_Search_Query::INTERVAL_YOUNGER);
+                    $search_array[] = $ob;
+                }
+                break;
+
             case 'size':
                 if (!empty($rule->v)) {
                     $ob->size(intval($rule->v), $rule->t == 'size_larger');
index ac1fedd..6d91190 100644 (file)
@@ -39,7 +39,7 @@ $f_fields = $s_fields = array();
 $search_mailbox = Horde_Util::getFormData('search_mailbox');
 
 foreach ($imp_search->searchFields() as $key => $val) {
-    if (!in_array($val['type'], array('customhdr', 'date'))) {
+    if (!in_array($val['type'], array('customhdr', 'date', 'within'))) {
         $s_fields[] = array(
             'val' => $key,
             'label' => $val['label']
index b81ffe4..c1ae7c9 100644 (file)
@@ -87,3 +87,9 @@
 <div id="folder_row" style="display:none">
  <input type="checkbox" class="checkbox" name="search_folders_form[]" />
 </div>
+
+<select id="within_criteria" style="display:none">
+ <option value="d"><gettext>Days</gettext></option>
+ <option value="m"><gettext>Months</gettext></option>
+ <option value="y"><gettext>Years</gettext></option>
+</select>