From 9fd857307079b57f515fa394cd8f0aefc64336e0 Mon Sep 17 00:00:00 2001
From: Guy Pyrzak <guy.pyrzak@gmail.com>
Date: Sun, 6 Jun 2010 01:40:18 -0700
Subject: [PATCH] Bug 450301: What Simplify searching UI, initial improvements
 to the advanced search ui. r=mkanat, a=mkanat

---
 Bugzilla/Config/Query.pm                      |   2 +-
 Bugzilla/Search.pm                            |   2 +-
 js/TUI.js                                     |  11 +-
 skins/standard/IE-fixes.css                   |   6 +
 skins/standard/search_form.css                | 133 ++++
 template/en/default/bug/field-label.html.tmpl |   9 +-
 template/en/default/filterexceptions.pl       |   5 -
 .../default/search/boolean-charts.html.tmpl   |   7 +-
 template/en/default/search/field.html.tmpl    | 117 +++
 template/en/default/search/form.html.tmpl     | 673 ++++++------------
 .../default/search/search-advanced.html.tmpl  |   6 +-
 .../search/search-create-series.html.tmpl     |   3 +-
 .../search/search-report-graph.html.tmpl      |   3 +-
 .../search/search-report-table.html.tmpl      |   3 +-
 14 files changed, 512 insertions(+), 468 deletions(-)
 create mode 100644 skins/standard/search_form.css
 create mode 100644 template/en/default/search/field.html.tmpl

diff --git a/Bugzilla/Config/Query.pm b/Bugzilla/Config/Query.pm
index 808a9a102..6d570e01a 100644
--- a/Bugzilla/Config/Query.pm
+++ b/Bugzilla/Config/Query.pm
@@ -64,7 +64,7 @@ sub get_param_list {
   {
    name => 'defaultquery',
    type => 't',
-   default => 'bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&emailassigned_to1=1&emailassigned_to2=1&emailreporter2=1&emailcc2=1&emailqa_contact2=1&order=Importance&long_desc_type=substring'
+   default => 'bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&emailassigned_to1=1&emailassigned_to2=1&emailreporter2=1&emailcc2=1&emailqa_contact2=1&emaillongdesc3=1&order=Importance&long_desc_type=substring'
   },
 
   {
diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm
index 271e23298..f036584ce 100644
--- a/Bugzilla/Search.pm
+++ b/Bugzilla/Search.pm
@@ -372,7 +372,7 @@ sub init {
         }
     }
 
-    foreach my $id ("1", "2") {
+    foreach my $id (1, 2, 3) {
         if (!defined ($params->param("email$id"))) {
             next;
         }
diff --git a/js/TUI.js b/js/TUI.js
index aa7f2fff4..34a79dc16 100644
--- a/js/TUI.js
+++ b/js/TUI.js
@@ -68,6 +68,7 @@ function TUI_hide_default(className) {
 
 function _TUI_toggle_control_link(className) {
     var link = document.getElementById(className + "_controller");
+    if (!link) return;
     var original_text = link.innerHTML;
     link.innerHTML = TUI_alternates[className];
     TUI_alternates[className] = original_text;
@@ -93,14 +94,14 @@ function _TUI_store(aClass, state) {
 }
 
 function _TUI_restore() {
-    var classes = YAHOO.util.Cookie.getSubs(TUI_COOKIE_NAME);
-    for (item in classes) {
-        if (classes[item] == 0) {
-            var elements = YAHOO.util.Dom.getElementsByClassName(item);
+    var yui_classes = YAHOO.util.Cookie.getSubs(TUI_COOKIE_NAME);
+    for (yui_item in yui_classes) {
+        if (yui_classes[yui_item] == 0) {
+            var elements = YAHOO.util.Dom.getElementsByClassName(yui_item);
             for (var i = 0; i < elements.length; i++) {
                 YAHOO.util.Dom.addClass(elements[i], 'bz_tui_hidden');
             }
-            _TUI_toggle_control_link(item);
+            _TUI_toggle_control_link(yui_item);
         }
     }
 }
diff --git a/skins/standard/IE-fixes.css b/skins/standard/IE-fixes.css
index 4c85340e7..1b6b9929f 100644
--- a/skins/standard/IE-fixes.css
+++ b/skins/standard/IE-fixes.css
@@ -44,3 +44,9 @@ form#Create #comp_desc {
 #footer .links {
     display: inline;
 }
+
+#bug_id_container, .search_field_grid, 
+.search_email_fields, ul.bug_changes li { 
+  zoom: 1;
+  display: inline;
+}
\ No newline at end of file
diff --git a/skins/standard/search_form.css b/skins/standard/search_form.css
new file mode 100644
index 000000000..9e123ab54
--- /dev/null
+++ b/skins/standard/search_form.css
@@ -0,0 +1,133 @@
+/* The contents of this file are subject to the Mozilla Public
+  * License Version 1.1 (the "License"); you may not use this file
+  * except in compliance with the License. You may obtain a copy of
+  * the License at http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an "AS
+  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  * implied. See the License for the specific language governing
+  * rights and limitations under the License.
+  *
+  * The Original Code is the Bugzilla Bug Tracking System.
+  *
+  * The Initial Developer of the Original Code is Guy Pyrzak
+  * Portions created by the Initial Developer are Copyright (C) 2010 the
+  * Initial Developer. All Rights Reserved.
+  *
+  * Contributor(s): 
+  *           Guy Pyrzak <guy.pyrzak@gmail.com>
+  */
+
+#bug_id_container { 
+  display: inline-block;
+  vertical-align: middle;
+}
+
+.search_field_grid {
+  margin-top: 1em;
+  display: inline-block;
+}
+
+.search_field_grid .field_help_link, 
+.history_query .field_help_link 
+{
+  display: block;
+  text-align: left;
+}
+
+#chart .section_help {
+  font-size: 0.8em; 
+  font-weight: normal
+}
+
+#bug_id_container .field_help {
+  font-size: 0.75em
+}
+
+.search_field_row {
+  display: block;
+  padding: 0.5ex 0;
+  vertical-align: top;
+}
+
+.search_field_grid label {
+  display: block;
+}
+
+.search_field_grid select {
+  width: 17em;
+  height: 15ex;
+}
+
+.search_field_grid, .search_field_row {
+  padding-left: 1.5em;
+}
+
+.search_email_fields {
+  display: inline-block;
+  width: 14.5em;
+  padding-left: 1.5em;
+}
+
+ul.bug_changes {
+  margin: 0;
+  padding: 0;
+}
+
+ul.bug_changes li {
+  display: inline-block;
+  width: 14.5em;
+  vertical-align: top;
+  padding-left: 1.5em;
+}
+
+ul.bug_changes select {
+  width: 15em;
+}
+
+ul.bug_changes li label {
+   display: block;
+}
+
+div.bz_section_title {
+  display: block;
+  margin-top: 2em;
+  font-size: 1.2em;
+}
+
+div.bz_section_title a {
+  font-weight: bold;    
+}
+
+div.bz_section_title span {
+  font-size: 0.75em;
+  margin-left: 1em;    
+}  
+
+#summary_field {
+  margin: 0;
+  padding: 0;
+}
+
+#summary_field label {
+  margin-right: 2em;
+  font-weight: bold;
+  display: inline;
+}
+
+.hide_people_filter #people_filter_section, 
+.hide_history_filter #history_filter_section, 
+.hide_detailed_information #detailed_information_section 
+{
+  display: none;
+}
+
+.arrow {
+  display: inline;
+  width: 16px;
+  height: 16px;
+}
+
+.bz_search_section, ul.bz_search_section {
+  margin-top: 1em;
+}
\ No newline at end of file
diff --git a/template/en/default/bug/field-label.html.tmpl b/template/en/default/bug/field-label.html.tmpl
index 7b63f7b8c..3f9187c89 100644
--- a/template/en/default/bug/field-label.html.tmpl
+++ b/template/en/default/bug/field-label.html.tmpl
@@ -23,14 +23,15 @@
   #   desc_url: An alternate link to help for the field.
   #   hidden: True if the field label should start hidden.
   #   rowspan: a "rowspan" value for the label's <th>.
+  #   tag_name: the tag to use to surround the label
   #%]
 
 [% PROCESS "bug/field-help.none.tmpl" %]
-
-<th class="field_label [% ' bz_hidden_field' IF hidden %]
+[% DEFAULT tag_name = "th" %]
+<[% tag_name %] class="field_label [% ' bz_hidden_field' IF hidden %]
            [%- ' required' IF field.is_mandatory %]"
     id="field_label_[% field.name FILTER html %]"
-    [% IF rowspan %] rowspan="[% rowspan FILTER html %]"[% END %]>
+    [% IF rowspan > 0 %] rowspan="[% rowspan FILTER html %]"[% END %]>
 
   [% IF editable %]
     <label for="[% field.name FILTER html %]">
@@ -49,4 +50,4 @@
   >[%- field_descs.${field.name} FILTER html %]:</a>
 
   [% '</label>' IF editable %]
-</th>
+</[% tag_name %]>
diff --git a/template/en/default/filterexceptions.pl b/template/en/default/filterexceptions.pl
index 46132c892..799371f63 100644
--- a/template/en/default/filterexceptions.pl
+++ b/template/en/default/filterexceptions.pl
@@ -59,7 +59,6 @@
 
 'search/boolean-charts.html.tmpl' => [
   '"field${chartnum}-${rownum}-${colnum}"', 
-  '"value${chartnum}-${rownum}-${colnum}"', 
   'field.name', 
   '"${chartnum}-${rownum}-${newor}"', 
   '"${chartnum}-${newand}-0"', 
@@ -70,10 +69,6 @@
 'search/form.html.tmpl' => [
   'qv.name',
   'qv.description',
-  'field.name',
-  'field.description',
-  'field.accesskey',
-  'sel.name',
 ],
 
 'search/search-specific.html.tmpl' => [
diff --git a/template/en/default/search/boolean-charts.html.tmpl b/template/en/default/search/boolean-charts.html.tmpl
index a8d018556..404e77f07 100644
--- a/template/en/default/search/boolean-charts.html.tmpl
+++ b/template/en/default/search/boolean-charts.html.tmpl
@@ -50,7 +50,9 @@
 ] %]
 
   <h3 id="chart">
-    Advanced Searching Using Boolean Charts
+    Custom Search <span class="section_help">Didn't find what 
+      you're looking for above? This area allows for ANDs, ORs 
+      and other more complex searches.</span>
   </h3>
 
 [%# Whoever wrote the original version of boolean charts had a seriously twisted mind %]
@@ -87,9 +89,8 @@
         [% INCLUDE "search/type-select.html.tmpl"
            name = "type${chartnum}-${rownum}-${colnum}",
            types = types, selected = col.type %]
-
         <input name="[% "value${chartnum}-${rownum}-${colnum}" %]" 
-               value="[% col.value FILTER html %]"> 
+               value="[% col.value FILTER html %]">
       </td>
       
       [% UNLESS loop.last %]
diff --git a/template/en/default/search/field.html.tmpl b/template/en/default/search/field.html.tmpl
new file mode 100644
index 000000000..63ef4530f
--- /dev/null
+++ b/template/en/default/search/field.html.tmpl
@@ -0,0 +1,117 @@
+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the "License"); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an "AS
+  # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Guy Pyrzak
+  # Portions created by the Initial Developer are Copyright (C) 2010 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): Guy Pyrzak <guy.pyrzak@gmail.com>
+  #
+  #%]
+[%# INTERFACE:
+  #   field: a Bugzilla::Field object
+  #   value: the value or values that should be used to prepopulate the field
+  #   accesskey: the access key used to access the field more quickly
+  #   onchange: js to run when the change event fires on the field
+  #   type_selected: used by the free text to indicate which type of text
+  #                  search was selected for a particular field
+  #%]
+  
+[% SWITCH field.type %]
+  [% CASE [ constants.FIELD_TYPE_FREETEXT,
+            constants.FIELD_TYPE_TEXTAREA, 
+            constants.FIELD_TYPE_UNKNOWN ] %]
+    [% INCLUDE "bug/field-label.html.tmpl"
+      field = field
+      tag_name = "span"
+      editable = 1
+    %]
+
+    [% INCLUDE "search/type-select.html.tmpl"
+       name = field.name _ "_type",
+       types = types, 
+       selected = type_selected  %]
+       
+    <input name="[% field.name FILTER html %]" 
+           id="[% field.name FILTER html %]" size="40"
+           [% IF onchange %] onchange="[% onchange FILTER html %]"[% END %]
+           value="[% value FILTER html %]">              
+  [% CASE constants.FIELD_TYPE_DATETIME %]
+    [% INCLUDE "bug/field-label.html.tmpl"
+      field = field
+      tag_name = "span"
+      editable = 1
+    %]
+    from <input name="[% field.name %]from" 
+                id="[% field.name %]" 
+                size="10" maxlength="10"
+                value="[% value.0 FILTER html %]" 
+                onchange="updateCalendarFromField(this);[% onchange FILTER html %]">
+         <button type="button" class="calendar_button"
+                        id="button_calendar_[% field.name FILTER html %]"
+                        onclick="showCalendar('[% field.name FILTER js %]')">
+           <span>Calendar</span>
+         </button>
+         <div id="con_calendar_[% field.name FILTER html %]"></div>               
+    to <input name="[% field.name %]to" 
+              id="[% field.name %]to" size="10" maxlength="10"
+              value="[% value.1 FILTER html %]" 
+              onchange="updateCalendarFromField(this);[% onchange FILTER html %]">
+       <button type="button" class="calendar_button"
+                      id="button_calendar_[% field.name FILTER html %]to"
+                      onclick="showCalendar('[% field.name FILTER js %]to')">
+         <span>Calendar</span>
+       </button>
+    <small>(YYYY-MM-DD or relative dates)</small>
+    
+    <div id="con_calendar_[% field.name FILTER html %]to"></div>
+    <script type="text/javascript">
+      createCalendar('[% field.name FILTER js %]');
+      createCalendar('[% field.name FILTER js %]to');
+    </script>
+  [% CASE [ constants.FIELD_TYPE_SINGLE_SELECT, 
+            constants.FIELD_TYPE_MULTI_SELECT ] %]
+    <div id="container_[% field.name FILTER html %]" class="search_field_grid">      
+      [% INCLUDE "bug/field-label.html.tmpl"
+        field = field
+        editable = 1
+        tag_name = "span"
+      %]
+      <select name="[% field.name FILTER html%]" 
+              id="[% field.name FILTER html %]" 
+        [% IF onchange %] onchange="[% onchange FILTER html %]"[% END %]
+        multiple="multiple" size="7">
+        [% legal_values = ${field.name} %]
+        [% IF field.name == "component" %]
+          [% legal_values = ${"component_"} %]
+        [% END %]
+        [% FOREACH current_value = legal_values %]
+          [% IF current_value.id %]
+            [%# current_value is a hash instead of a value which 
+                only applies for Resolution really, everywhere else current_value
+                is just the value %]
+            [% v = current_value.name OR '---' -%]
+            <option value="[% v FILTER html %]"
+              [% ' selected="selected"' IF value.contains( v ) %]>
+              [% display_value(field.name, current_value.name) FILTER html %]
+            </option>
+          [% ELSE %]
+            <option value="[% current_value OR '---' FILTER html %]"
+              [% ' selected="selected"' IF value.contains( current_value ) %]>
+              [% display_value(field.name, current_value) FILTER html %]
+            </option>
+          [% END %]
+        [% END %]
+      </select>
+    </div>
+  [% END %]  
+  
\ No newline at end of file
diff --git a/template/en/default/search/form.html.tmpl b/template/en/default/search/form.html.tmpl
index 63ca03565..c7e6f96a8 100644
--- a/template/en/default/search/form.html.tmpl
+++ b/template/en/default/search/form.html.tmpl
@@ -18,6 +18,7 @@
   # Contributor(s): Chris Lahey <clahey@ximian.com> [javascript fixes]
   #                 Christian Reis <kiko@async.com.br> [javascript rewrite]
   #                 Gervase Markham <gerv@gerv.net>
+  #                 Guy Pyrzak <guy.pyrzak@gmail.com>
   #%]
 
 [% PROCESS "global/field-descs.none.tmpl" %]
@@ -103,6 +104,17 @@ function doOnSelectProduct(selectmode) {
     }
 }
 
+// Hide the Advanced Fields by default, unless the user has a cookie
+// that specifies otherwise.
+// &#9656; and &#9662; are both utf8 escaped characters for right 
+//    and down facing arrows respectivly.
+TUI_alternates['history_query'] = '&#9658;';
+TUI_alternates['people_query'] = '&#9658;';
+TUI_alternates['information_query'] = '&#9658;';
+
+TUI_hide_default('history_query');
+TUI_hide_default('people_query');
+TUI_hide_default('information_query');
 </script>
 
 [% query_types = [
@@ -122,383 +134,202 @@ function doOnSelectProduct(selectmode) {
 
 [%# *** Summary *** %]
 
-<table>
-  <tr>
-    <th align="right">
-      <label for="short_desc" accesskey="s"><u>S</u>ummary</label>:
-    </th>
-    <td>
-      [% INCLUDE "search/type-select.html.tmpl"
-         name = "short_desc_type",
-         types = query_types, selected = default.short_desc_type.0 %]
-    </td>
-    <td>
-      <input name="short_desc" id="short_desc" size="40"
-             value="[% default.short_desc.0 FILTER html %]">
+  <div class="search_field_row" id="summary_field">
+      [% INCLUDE "search/field.html.tmpl"
+         field = bug_fields.short_desc
+         types = query_types
+         value = default.short_desc.0
+         type_selected = default.short_desc_type.0 
+         accesskey = "s"
+         %]
       <script type="text/javascript"> <!--
           document.forms[queryform].short_desc.focus(); 
       // -->
       </script>
-    </td>
-    <td>
+
       [% IF button_name %]
         <input type="submit" id="[% button_name FILTER css_class_quote %]_top"
                value="[% button_name FILTER html %]">
       [% END %]
-    </td>
-  </tr>
+  </div>
 
-[%# *** Classification Product Component Version Target *** %]
-  <tr>
-    <td colspan="4">
-      <table>
-        <tr>
-        [% Hook.process('before_selects_top') %]
-        [% IF Param('useclassification') %]
-          <td valign="top">
-            <table>
-              <tr valign="bottom">
-                <th align="left">
-                  <label for="classification">Classification</label>:
-                </th>
-              </tr>
-              <tr valign="top">
-                <td align="left">
-                  <select name="classification" multiple="multiple" size="5" id="classification"
-                          onchange="doOnSelectProduct(1);">
-                    [% FOREACH cat = classification %]
-                      <option value="[% cat.name FILTER html %]"
-                        [% " selected" IF lsearch(default.classification, cat.name) != -1 %]>
-                        [% cat.name FILTER html %]
-                      </option>
-                    [% END %]
-                  </select>
-                </td>
-              </tr>
-            </table>
-          </td>
-        [% END %]
-          <td valign="top">
-            <table>
-              <tr valign="bottom">
-                <th align="left">
-                  <label for="product" accesskey="p"><u>P</u>roduct</label>:
-                </th>
-              </tr>
-              <tr valign="top">
-                [%# Can't use the select block here because of the onChange %]
-                <td align="left">
-                  <select name="product" multiple="multiple" size="5" id="product"
-                          onchange="doOnSelectProduct(2);">
-                    [% FOREACH p = product %]
-                      [% IF p.components.size %]
-                      <option value="[% p.name FILTER html %]"
-                        [% " selected" IF lsearch(default.product, p.name) != -1 %]>
-                        [% p.name FILTER html %]</option>
-                      [% END %]
-                    [% END %]
-                  </select>
-                </td>
-              </tr>
-            </table>
-          </td>
-          <td valign="top">
-            <table>
-              <tr valign="bottom">
-                <th align="left">
-                  <label for="component" accesskey="m"><a href="describecomponents.cgi">Co<u>m</u>ponent</a></label>:
-                </th>
-              </tr>
-              <tr valign="top">
-                [%# Can't use the select block here because 'component' is a toolkit
-                    reserved word - we use 'component_' instead. %]
-                <td align="left">
-                  <select name="component" id="component"
-                          multiple="multiple" size="5">
-                    [% FOREACH c = component_ %]
-                      <option value="[% c FILTER html %]"
-                        [% " selected" IF lsearch(default.component, c) != -1 %]>
-                        [% c FILTER html %]</option>
-                    [% END %]
-                  </select>
-                </td>
-              </tr>
-            </table>
-          </td>
-          <td valign="top">
-            <table>
-              <tr valign="bottom">
-                <th align="left">
-                  <label for="version">Version</label>:
-                </th>
-              </tr>
-              <tr valign="top">
-                [% PROCESS select sel = { name => 'version',
-                                          size => 5 } %]
-              </tr>
-            </table>
-          </td>
-        [% IF Param('usetargetmilestone') %]
-          <td valign="top">
-            <table>
-              <tr valign="bottom">
-                <th align="left">
-                  <label for="target_milestone">Target</label>:
-                </th>
-              </tr>
-              <tr valign="top">
-                [% PROCESS select sel = { name => 'target_milestone',
-                                          size => 5 } %]
-              </tr>
-            </table>
-          </td>
-        [% END %]
-        [% Hook.process('after_selects_top') %]
-        </tr>
-      </table>
-    </td>
-  </tr>
+[%# *** Classification Product Component *** %]
+  
+[% Hook.process('before_selects_top') %]
+[% IF Param('useclassification') %]
+      [% fake_classfication = { name => bug_fields.classification.name,
+                                type => constants.FIELD_TYPE_SINGLE_SELECT } %]
+      [% INCLUDE "search/field.html.tmpl" 
+            field => fake_classfication
+            accesskey => "c"
+            onchange => "doOnSelectProduct(1);" 
+            value => default.classification
+      %]          
+[% END %]
 
+[% INCLUDE "search/field.html.tmpl" 
+      field => bug_fields.product
+      accesskey => "p"
+      onchange => "doOnSelectProduct(2);" 
+      value => default.product
+%]
+[% INCLUDE "search/field.html.tmpl" 
+      field => bug_fields.component
+      accesskey => "m"
+      onchange => "doOnSelectProduct(2);" 
+      value => default.component
+%]
+[% INCLUDE "search/field.html.tmpl" 
+      field => bug_fields.bug_status
+      accesskey => "a"
+      value => default.bug_status
+%]
+[% INCLUDE "search/field.html.tmpl" 
+      field => bug_fields.resolution
+      accesskey => "r" 
+      value => default.resolution
+%]
+
+[% Hook.process('after_selects_top') %]
+
+<div id="detailed_information" class="bz_section_title">
+  <div id="information_query_controller" class="arrow">&#9660;</div>
+  <a href="javascript:TUI_toggle_class('information_query')">
+    Detailed [% terms.Bug %] Information
+  </a>
+  <span class="section_help">Narrow results by the following fields: 
+    [%+ field_descs.longdesc %]s, [%+ field_descs.bug_file_loc %], 
+    [% IF Param('usestatuswhiteboard') %] [%+ field_descs.status_whiteboard %], [%+ END %]
+    [% IF use_keywords %] [%+ field_descs.keywords %], [%+ END %]
+    [% IF user.is_timetracker %] [%+ field_descs.deadline %], [%+ END %]
+    [% terms.Bug %] Numbers, [%+ field_descs.version %], 
+    [% IF Param('usetargetmilestone') %] [%+ field_descs.target_milestone %], [%+ END %]
+    [% field_descs.bug_severity %], [%+ field_descs.priority%], [%+ field_descs.rep_platform %], 
+    [%+ field_descs.op_sys %]
+  </span>
+</div>
 [%# *** Comment URL Whiteboard Keywords *** %]
-
+<div id="detailed_information_section" class="bz_search_section information_query">
   [% SET freetext_fields = [
-    { name => "longdesc", description => "A&nbsp;<u>C</u>omment",
-      accesskey => 'c' },
-    { name => "bug_file_loc", description => "The&nbsp;<u>U</u>RL",
-      accesskey => 'u' },
-    { name => "status_whiteboard", description => "<u>W</u>hiteboard",
-      accesskey => 'w' } 
+    { field => bug_fields.longdesc, accesskey => 'c' },
+    { field => bug_fields.bug_file_loc, accesskey => 'u' },
+    { field => bug_fields.status_whiteboard, accesskey => 'w' },
+    { field => bug_fields.keywords, accesskey => 'k', 
+      qtypes => ['allwords', 'anywords', 'nowords', 'regexp', 'notregexp'] }   
   ] %]
-
   [% Hook.process('before_freetext_fields') %]
-  [% FOREACH field = freetext_fields %]
-    [% NEXT IF field.name == 'status_whiteboard' 
+  
+  [%# loop through a bunch of free text fields and print out their text stuff %]
+  [% FOREACH field_container = freetext_fields %]
+    [% NEXT IF field_container.field.name == 'status_whiteboard' 
                AND NOT Param('usestatuswhiteboard') 
     %]
-    <tr>
-      <th align="right">
-        <label for="[% field.name %]" 
-               accesskey="[% field.accesskey %]">[% field.description %]</label>:
-      </th>
-      <td>
-        [% type = field.name _ "_type" %]
-        [% INCLUDE "search/type-select.html.tmpl"
-           name = type,
-           types = query_types, selected = default.$type.0 %]
-      </td>
-      <td><input name="[% field.name %]" id="[% field.name %]" size="40"
-                 value="[% default.${field.name}.0 FILTER html %]">
-      </td>
-      <td></td>
-    </tr>
-  [% END %]
-
-  [% IF use_keywords %]
-    <tr>
-      <th align="right">
-        <label for="keywords" accesskey="k"><a href="describekeywords.cgi"><u>K</u>eywords</a></label>:
-      </th>
-      <td>
-        [% INCLUDE "search/type-select.html.tmpl"
-           name = "keywords_type",
-           types = ['allwords', 'anywords', 'nowords', 'regexp', 'notregexp'],
-           selected = default.keywords_type.0 %]
-      </td>
-      <td>
-        <input name="keywords" id="keywords" size="40"
-               value="[% default.keywords.0 FILTER html %]">
-      </td>
-    </tr>
+    [% NEXT IF field_container.field.name == 'keywords' 
+               AND NOT use_keywords
+    %]
+    <div class="search_field_row">
+      [% type = field_container.field.name _ "_type" %]
+      [% INCLUDE "search/field.html.tmpl" 
+          field => field_container.field
+          types => field_container.qtypes || query_types
+          accesskey => field_container.accesskey
+          value => default.${field_container.field.name}.0
+          type_selected => default.$type.0
+      %]
+    </div>
   [% END %]
 
   [%# Deadline %]
   [% IF user.is_timetracker %]
-    <tr>
-      <th align="right">
-        <label for="deadlinefrom" accesskey="l">Dead<u>l</u>ine</label>:
-      </th>
-      <td>
-        from <input name="deadlinefrom" id="deadlinefrom" size="10" maxlength="10"
-                    value="[% default.deadlinefrom.0 FILTER html %]">
-        to <input name="deadlineto" size="10" maxlength="10"
-                  value="[% default.deadlineto.0 FILTER html %]">
-      </td>
-      <td>
-        <small>(YYYY-MM-DD or relative dates)</small>
-      </td>
-    </tr>
+    <div class="search_field_row">
+        [% INCLUDE "search/field.html.tmpl" 
+                    field = bug_fields.deadline 
+                    accesskey = "l"
+                    value = [ default.deadlinefrom.0, default.deadlineto.0  ]
+        %]
+    </div>
   [% END %]
 
+  <div class="search_field_row">
+    <label for="bug_id">[% terms.Bugs %] numbered</label>
+    <div id="bug_id_container" >
+      <input type="text" name="bug_id" id="bug_id"
+           value="[% default.bug_id.0 FILTER html %]" size="20">
+           <div class="field_help">(comma-separated list)</div>
+    </div>
+    should be 
+    <select name="bug_id_type">
+      <option value="anyexact"[% " selected" IF default.bug_id_type.0 == "anyexact" %]>only included in</option>
+      <option value="nowords"[% " selected" IF default.bug_id_type.0 == "nowords" %]>excluded from</option>
+    </select> the results
+  </div>
+
   [% Hook.process('after_freetext_fields') %]
   
-</table>
-
-<hr>
-
-[%# *** Status Resolution Severity Priority Hardware OS *** %]
-
-<table>
-  <tr>
+  [%# *** Status Resolution Severity Priority Hardware OS *** %]
+  <div>
     [% Hook.process('before_selects_bottom') %]
-    <td>
-      <table>
-        <tr>
-          <th align="left">
-            <label for="bug_status" accesskey="a">St<u>a</u>tus</label>:
-          </th>
-        </tr>
-        <tr valign="top">
-          [% PROCESS select sel = { name => 'bug_status',
-                                    size => 7 } %]
-        </tr>
-      </table>
-    </td>
-    <td>
-      <table>
-        <tr>
-          <th align="left">
-            <label for="resolution" accesskey="r"><u>R</u>esolution</label>:
-          </th>
-        </tr>
-        <tr valign="top">
-          [% PROCESS select sel = { name => 'resolution',
-                                    size => 7 } %]
-        </tr>
-      </table>
-    </td>
-    <td>
-      <table>
-        <tr>
-          <th align="left">
-            <label for="bug_severity">Severity</label>:
-          </th>
-        </tr>
-        <tr valign="top">
-          [% PROCESS select sel = { name => 'bug_severity',
-                                    size => 7 }%]
-        </tr>
-      </table>
-    </td>
-    <td>
-      <table>
-        <tr>
-          <th align="left">
-            <label for="priority" accesskey="i">Pr<u>i</u>ority</label>:
-          </th>
-        </tr>
-        <tr valign="top">
-          [% PROCESS select sel = { name => 'priority',
-                                    size => 7 } %]
-        </tr>
-      </table>
-    </td>
-    <td>
-      <table>
-        <tr>
-          <th align="left">
-            <label for="rep_platform" accesskey="h"><u>H</u>ardware</label>:
-          </th>
-        </tr>
-        <tr valign="top">
-          [% PROCESS select sel = { name => 'rep_platform',
-                                    size => 7 } %]
-        </tr>
-      </table>
-    </td>
-    <td>
-      <table>
-        <tr>
-          <th align="left">
-            <label for="op_sys" accesskey="o"><u>O</u>S</label>:
-          </th>
-        </tr>
-        <tr valign="top">
-          [% PROCESS select sel = { name => 'op_sys',
-                                    size => 7 } %]
-        </tr>
-      </table>
-    </td>
+    [% fake_version_field = { name => bug_fields.version.name,
+                              type => constants.FIELD_TYPE_SINGLE_SELECT }%]
+    [% INCLUDE "search/field.html.tmpl" 
+          field => fake_version_field
+          value => default.version
+    %]                              
+    [% IF Param('usetargetmilestone') %]
+        [% fake_target_milestone_field = { name => bug_fields.target_milestone.name , 
+                                           type => constants.FIELD_TYPE_SINGLE_SELECT } %]
+        [% INCLUDE "search/field.html.tmpl" 
+              field => fake_target_milestone_field
+              value => default.target_milestone
+        %]
+    [% END %]
+    [% INCLUDE "search/field.html.tmpl" 
+          field => bug_fields.bug_severity
+          accesskey=> "v" 
+          value => default.bug_severity
+    %]
+    [% INCLUDE "search/field.html.tmpl" 
+         field => bug_fields.priority
+         accesskey => "i"
+         value => default.priority
+    %]    
+    [% INCLUDE "search/field.html.tmpl" 
+        field => bug_fields.rep_platform 
+        accesskey =>"h"
+        value => default.rep_platform
+    %]               
+    [% INCLUDE "search/field.html.tmpl" 
+        field => bug_fields.op_sys 
+        accesskey =>"o"
+        value => default.op_sys
+    %]               
     [% Hook.process('after_selects_bottom') %]
-  </tr>
-</table>
-
+  </div>
+</div>
 [%# *** Email Numbering *** %]
-
-<table>
-  <tr>
-    <td>
-      <fieldset>
-        <legend>
-          <strong>Email Addresses and [% terms.Bug %] Numbers</strong>
-        </legend>
-
-
-<table>
-  <tr>
-  [% FOREACH n = [1, 2] %]
-    <td>
-
-
-<table cellspacing="0" cellpadding="0">
-  <tr>
-    <td>
+  <div class="bz_section_title" id="people_filter">
+    <div id="people_query_controller" class="arrow">&#9660;</div>
+    <a href="javascript:TUI_toggle_class('people_query')">Search By People</a>
+    <span>Narrow results to a role (ie. [% field_descs.assigned_to%], [% field_descs.reporter %], 
+      [% field_descs.commenter %], etc.) a person has on a [% terms.bug %]
+    </span>
+  </div>
+  <div id="people_filter_section" class="bz_search_section people_query">
+  [% FOREACH n = [1, 2, 3] %]
+    <div class="search_email_fields">
       Any of:
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <input type="checkbox" name="emailassigned_to[% n %]"
-             id="emailassigned_to[% n %]" value="1"
-             [% " checked" IF default.emailassigned_to.$n %]>
-      <label for="emailassigned_to[% n %]">
-        the [% terms.bug %] assignee
-      </label>
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <input type="checkbox" name="emailreporter[% n %]"
-             id="emailreporter[% n %]" value="1"
-             [% " checked" IF default.emailreporter.$n %]>
-      <label for="emailreporter[% n %]">
-        the reporter
-      </label>
-    </td>
-  </tr>
-  [% IF Param('useqacontact') %]
-  <tr>
-    <td>
-      <input type="checkbox" name="emailqa_contact[% n %]"
-             id="emailqa_contact[% n %]" value="1"
-             [% " checked" IF default.emailqa_contact.$n %]>
-      <label for="emailqa_contact[% n %]">
-        the QA contact
-      </label>
-    </td>
-  </tr>
-  [% END %]
-  <tr>
-    <td>
-      <input type="checkbox" name="emailcc[% n %]"
-             id="emailcc[% n %]" value="1"
-             [% " checked" IF default.emailcc.$n %]>
-      <label for="emailcc[% n %]">
-        a CC list member
-      </label>
-    </td>
-  </tr>
-  <tr>
-    <td>
-        <input type="checkbox" name="emaillongdesc[% n %]"
-               id="emaillongdesc[% n %]" value="1"
-               [% " checked" IF default.emaillongdesc.$n %]>
-      <label for="emaillongdesc[% n %]">
-        a commenter
-      </label>
-    </td>
-  </tr>
-  <tr>
-    <td>
+      [% PROCESS role_types field = { count => n, name => "emailassigned_to",
+                  label=> "the ${terms.Bug} ${field_descs.assigned_to}" } %]
+      [% PROCESS role_types field = { count => n, name => "emailreporter",
+                  label=> "the ${field_descs.reporter}" } %]    
+      [% IF Param('useqacontact') %]
+          [% PROCESS role_types field = { count => n, name => "emailqa_contact", 
+                  label=> "the ${field_descs.qa_contact}" } %]
+      [% END %]
+      [% PROCESS role_types field = { count => n, name => "emailcc", 
+                  label=> "a ${field_descs.cc} list member" } %]
+      [% PROCESS role_types field = { count => n, name => "emaillongdesc", 
+                  label=> " a ${field_descs.commenter}" } %]
       <select name="emailtype[% n %]">
       [% FOREACH qv = [
         { name => "substring", description => "contains" },
@@ -506,121 +337,75 @@ function doOnSelectProduct(selectmode) {
         { name => "notequals", description => "is not" },
         { name => "regexp", description => "matches regexp" },
         { name => "notregexp", description => "doesn't match regexp" } ] %]
-
         <option value="[% qv.name %]"
           [% " selected" IF default.emailtype.$n == qv.name %]>[% qv.description %]</option>
       [% END %]
       </select>
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <input name="email[% n %]" size="25" value="[% default.email.$n FILTER html %]">
-    </td>
-  </tr>
-</table>
-
-
-    </td>
+      <input name="email[% n %]" class="email" id="email[% n %]" value="[% default.email.$n FILTER html %]">
+    </div>
   [% END %]
-  </tr>
-</table>
-<hr>
-<table>
-  <tr>
-    <td>
-      <select name="bug_id_type">
-        <option value="anyexact"[% " selected" IF default.bug_id_type.0 == "anyexact" %]>Only include</option>
-        <option value="nowords"[% " selected" IF default.bug_id_type.0 == "nowords" %]>Exclude</option>
-      </select>
-      <label for="bug_id">[% terms.bugs %] numbered</label>:
-    </td>
-    <td>
-      <input type="text" name="bug_id" id="bug_id"
-             value="[% default.bug_id.0 FILTER html %]" size="20">
-    </td>
-  </tr>
-  <tr>
-    <td></td>
-    <td>(comma-separated list)</td>
-  </tr>
-  [% Hook.process('email_numbering_end') %]
-</table>
-
-
-      </fieldset>
-    </td>
-   
+   [% Hook.process('email_numbering_end') %]
+   </div>
 [%# *** Bug Changes *** %]
-
-    <td valign="top">
-      <fieldset>
-        <legend><strong>[% terms.Bug %] Changes</strong></legend>
-
-
-<dl class="bug_changes">
-  <dt>
-    <label for="chfieldfrom">Only [% terms.bugs %] changed between</label>:
-  </dt>
-  <dd>
-    <input name="chfieldfrom" id="chfieldfrom"
-           size="10" value="[% default.chfieldfrom.0 FILTER html %]">
-    and <input name="chfieldto" size="10" value="[% default.chfieldto.0 FILTER html %]">
-    <br>(YYYY-MM-DD or relative dates)
-  </dd>
-  <dt>
-    <label for="chfield">where one or more of the following changed</label>:
-  </dt>
-  <dd>
+<div class="bz_section_title" id="history_filter">
+  <div id="history_query_controller" class="arrow">&#9660;</div>
+  <a href="javascript:TUI_toggle_class('history_query')" >Search By Change History</a>
+  <span>Narrow results to how fields have changed during a specific time period</span>
+</div>
+<ul class="bug_changes bz_search_section history_query" id="history_filter_section" >
+  <li>
+    <label for="chfield">where ANY of the fields:</label>
     [%# Create array, so we can sort it by description #%]
     [% chfields = [] %]
     [% FOREACH field = chfield %]
       [% chfields.push({value => field, desc => (field_descs.$field || field) }) %]
     [% END %]
-
     <select name="chfield" id="chfield" multiple="multiple" size="4">
     [% FOREACH field = chfields.sort('desc') %]
       <option value="[% field.value FILTER html %]"
-        [% " selected" IF lsearch(default.chfield, field.value) != -1 %]>
+        [% " selected" IF default.chfield.contains(field.value) %]>
         [% field.desc FILTER html %]</option>
     [% END %]
     </select>
-  </dd>
-  <dt>and <label for="chfieldvalue">the new value was</label>:</dt>
-  <dd>
+  </li>
+  <li>
+    <label for="chfieldvalue">[% search_descs.changedto %]:</label>
     <input name="chfieldvalue" id="chfieldvalue"
            size="20" value="[% default.chfieldvalue.0 FILTER html %]">
-  </dd>
-</dl>
-
-       </fieldset>
-     </td>
-  </tr>
-</table>
+  </li>
+  <li>
+    <label for="chfieldfrom">Between:</label>
+    <input name="chfieldfrom" id="chfieldfrom" size="10" 
+           value="[% default.chfieldfrom.0 FILTER html %]" onchange="updateCalendarFromField(this)"> 
+           <button type="button" class="calendar_button"
+                          id="button_calendar_chfieldfrom"
+                          onclick="showCalendar('chfieldfrom')"><span>Calendar</span></button>
+           and 
+           <div id="con_calendar_chfieldfrom"></div>
+          <input name="chfieldto" size="10" id="chfieldto" 
+          value="[% default.chfieldto.0 FILTER html %]" onchange="updateCalendarFromField(this)">
+          <button type="button" class="calendar_button"
+                         id="button_calendar_chfieldto"
+                         onclick="showCalendar('chfieldto')"><span>Calendar</span></button>
+          <div id="con_calendar_chfieldto"></div>
+    (YYYY-MM-DD or relative dates)
+    <script type="text/javascript">
+      createCalendar('chfieldfrom');
+      createCalendar('chfieldto');
+    </script>
+  </li>    
+</ul>
 
 [%############################################################################%]
-[%# Block for SELECT fields                                                  #%]
+[%# Block for email role type use to select which email to search through    #%]
 [%############################################################################%]
-
-[% BLOCK select %]
-  <td align="left">
-    <select name="[% sel.name %]" id="[% sel.name %]"
-            multiple="multiple" size="[% sel.size %]">
-      [% FOREACH value = ${sel.name} %]
-        [% IF value.id %]
-          [%# This only applies for Resolution really %]
-          [% v = value.name OR '---' -%]
-          <option value="[% v FILTER html %]"
-            [% " selected" IF lsearch(default.${sel.name}, v) != -1 %]>
-            [% display_value(sel.name, value.name) FILTER html %]
-          </option>
-        [% ELSE %]
-          <option value="[% value OR '---' FILTER html %]"
-            [% " selected" IF lsearch(default.${sel.name}, value) != -1 %]>
-            [% display_value(sel.name, value) FILTER html %]
-          </option>
-        [% END %]
-      [% END %]
-    </select>
-  </td>
+[% BLOCK role_types %]
+  <div class="role_type">
+    <input type="checkbox" name="[% field.name _ field.count FILTER html %]"
+           id="[% field.name _ field.count FILTER html %]" value="1"
+           [% " checked" IF default.${field.name}.${field.count} %]>
+    <label for="[% field.name _ field.count FILTER html%]">
+      [% field.label FILTER html%]
+    </label>
+  </div>
 [% END %]
diff --git a/template/en/default/search/search-advanced.html.tmpl b/template/en/default/search/search-advanced.html.tmpl
index 3a4252c2d..4203d90a6 100644
--- a/template/en/default/search/search-advanced.html.tmpl
+++ b/template/en/default/search/search-advanced.html.tmpl
@@ -38,8 +38,10 @@ var queryform = "queryform"
   title = "Search for $terms.bugs"
   onload = "doOnSelectProduct(0); enableHelp();"
   javascript = js_data
-  javascript_urls = [ "js/productform.js" "js/util.js" "js/help.js" ]
-  style_urls = [ "skins/standard/help.css" ]
+  javascript_urls = [ "js/yui/calendar.js", "js/productform.js", "js/util.js",
+                      "js/help.js" , "js/TUI.js", "js/field.js"]
+  style_urls = [ "skins/standard/help.css" , "skins/standard/search_form.css", 
+                 "skins/standard/yui/calendar.css" ]
   doc_section = "query.html"
   style = "dl.bug_changes dt {
              margin-top: 15px;
diff --git a/template/en/default/search/search-create-series.html.tmpl b/template/en/default/search/search-create-series.html.tmpl
index da1011e10..82e656149 100644
--- a/template/en/default/search/search-create-series.html.tmpl
+++ b/template/en/default/search/search-create-series.html.tmpl
@@ -34,7 +34,8 @@
   title = "Create New Data Set"
   onload = "doOnSelectProduct(0);"
   javascript = js_data 
-  javascript_urls = [ "js/productform.js" ]
+  javascript_urls = [ "js/yui/calendar.js", "js/productform.js", "js/TUI.js", "js/field.js" ]
+  style_urls = [ "skins/standard/yui/calendar.css", "skins/standard/search_form.css" ]
   doc_section = "reporting.html#charts-new-series"
 %]
 
diff --git a/template/en/default/search/search-report-graph.html.tmpl b/template/en/default/search/search-report-graph.html.tmpl
index 61dd3b5df..48d9561d6 100644
--- a/template/en/default/search/search-report-graph.html.tmpl
+++ b/template/en/default/search/search-report-graph.html.tmpl
@@ -33,7 +33,8 @@ var queryform = "reportform"
   title = "Generate Graphical Report"
   onload = "doOnSelectProduct(0); chartTypeChanged()"
   javascript = js_data
-  javascript_urls = [ "js/productform.js" ]
+  javascript_urls = [ "js/yui/calendar.js", "js/productform.js", "js/TUI.js", "js/field.js" ]
+  style_urls = [ "skins/standard/yui/calendar.css", "skins/standard/search_form.css" ]
   doc_section = "reporting.html#reports"
 %]
 
diff --git a/template/en/default/search/search-report-table.html.tmpl b/template/en/default/search/search-report-table.html.tmpl
index 55d62a140..374630712 100644
--- a/template/en/default/search/search-report-table.html.tmpl
+++ b/template/en/default/search/search-report-table.html.tmpl
@@ -33,7 +33,8 @@ var queryform = "reportform"
   title = "Generate Tabular Report"
   onload = "doOnSelectProduct(0)"
   javascript = js_data
-  javascript_urls = [ "js/productform.js" ]
+  javascript_urls = [ "js/yui/calendar.js", "js/productform.js", "js/TUI.js", "js/field.js" ]
+  style_urls = [ "skins/standard/yui/calendar.css", "skins/standard/search_form.css" ]
   doc_section = "reporting.html#reports"
 %]
 
-- 
2.24.1