]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
fix for 69793: check in new files for QuickSearch
authorcyeh%bluemartini.com <>
Thu, 1 Mar 2001 07:07:24 +0000 (07:07 +0000)
committercyeh%bluemartini.com <>
Thu, 1 Mar 2001 07:07:24 +0000 (07:07 +0000)
patch contributed by franke@ags.uni-sb.de (Andreas Franke)
Now add quicksearch functionality to the main index page.

index.html
localconfig.js [new file with mode: 0644]
quicksearch.html [new file with mode: 0644]
quicksearch.js [new file with mode: 0644]
quicksearchhack.html [new file with mode: 0644]

index 566a1053b6e560567359c1465cefe3689f2855ca..3a1a76ff6c4eb62cbc59366ac680319daaee0e1f 100644 (file)
@@ -76,11 +76,23 @@ But it all boils down to a choice of:
 <a href="createaccount.cgi">Open a new Bugzilla account</a><br>
 <a href="relogin.cgi">Forget the currently stored login</a><br>
 <a href="userprefs.cgi">Change password or user preferences</a><br>
-<FORM METHOD=GET ACTION="show_bug.cgi">
-<INPUT TYPE=SUBMIT VALUE="Find"> bug # <INPUT NAME=id SIZE=6></FORM>
-<SCRIPT LANGUAGE="JavaScript">
-document.forms[0].id.focus()
-</SCRIPT>
+<p>
+<script language="JavaScript" src="localconfig.js"></script>
+<script language="JavaScript" src="quicksearch.js"></script>
+
+<form name="f" action="show_bug.cgi" method="get"
+      onsubmit="QuickSearch(); return false;"> 
+  Enter a bug # or some search terms:<br>
+  <input type="text" name="id">
+  <input type="submit" value="Show">
+  <a href="quicksearch.html">[Help]</a>
+</form>
+
+<script>
+<!--
+document.forms['f'].id.focus();
+//-->
+</script>
 
 </BODY>
 </HTML>
diff --git a/localconfig.js b/localconfig.js
new file mode 100644 (file)
index 0000000..7cb01eb
--- /dev/null
@@ -0,0 +1,75 @@
+//
+// This file contains the installation specific values for QuickSearch.
+// See quicksearch.js for more details.
+//
+
+// the global bugzilla url
+
+var bugzilla = "";
+//var bugzilla = "http://bugzilla.mozilla.org/";
+
+// Status and Resolution
+// =====================
+
+var statuses_open     = new Array("UNCONFIRMED","NEW","ASSIGNED","REOPENED");
+var statuses_resolved = new Array("RESOLVED","VERIFIED","CLOSED");
+var resolutions       = new Array("FIXED","INVALID","WONTFIX","LATER",
+                                  "REMIND","DUPLICATE","WORKSFORME","MOVED");
+
+// Keywords
+// ========
+//
+// Enumerate all your keywords here. This is necessary to avoid 
+// "foo is not a legal keyword" errors. This makes it possible
+// to include the keywords field in the search by default.
+
+var keywords = new Array(
+// "foo", "bar", "baz"
+);
+
+// Platforms
+// =========
+//
+// A list of words <w> (substrings of platform values) 
+// that will automatically be translated to "platform:<w>" 
+// E.g. if "mac" is defined as a platform, then searching 
+// for it will find all bugs with platform="Macintosh", 
+// but no other bugs with e.g. "mac" in the summary.
+
+var platforms = new Array(
+"pc","sun","macintosh","mac" //shortcut added
+//,"dec","hp","sgi" 
+//,"all"   //this is a legal value for OpSys, too :(
+//,"other" 
+);
+
+// Severities
+// ==========
+//
+// A list of words <w> (substrings of severity values)
+// that will automatically be translated to "severity:<w>"
+// E.g with this default set of severities, searching for
+// "blo,cri,maj" will find all severe bugs.
+
+var severities = new Array("blo","cri","maj","nor","min","tri","enh");
+
+// Products and Components
+// =======================
+//
+// It is not necessary to list all products and components here.
+// Instead, you can define a "blacklist" for some commonly used 
+// words or word fragments that occur in a product or component name
+// but should _not_ trigger product/component search.
+
+var product_exceptions = new Array(
+"row"   // [Browser]
+        //   ^^^
+,"new"  // [MailNews]
+        //      ^^^
+);
+
+var component_exceptions = new Array(
+"hang"  // [mozilla.org] Bugzilla: Component/Keyword Changes
+        //                                            ^^^^
+);
+
diff --git a/quicksearch.html b/quicksearch.html
new file mode 100644 (file)
index 0000000..9001800
--- /dev/null
@@ -0,0 +1,146 @@
+<html>
+<head>
+  <title>Bugzilla QuickSearch</title>
+</head>
+
+<body bgcolor="#ffffff">
+
+<small>If you are already familiar with the original 
+<a href="query.cgi">Bugzilla Query Form</a>, 
+you may prefer <a href="quicksearchhack.html">this form</a>.
+</small>
+
+<p>
+<script src="localconfig.js"></script>
+<script src="quicksearch.js"></script>
+
+<h1>Bugzilla QuickSearch</h1>
+
+Type in one or more words (or word fragments) to search for:
+
+<!-- The name of the form must be "f" (used in "quicksearch.js"). -->
+
+<form name="f" action="show_bug.cgi" method="get"
+      onsubmit="QuickSearch(); return false;">
+  <table>
+    <tr>
+      <td><input type="text" size="40" name="id"/></td>
+      <td align=left><input type="submit" value="Search"/></td>
+      <!-- <td><a href="javascript:QuickSearch_Help();">[Help]</a></td> -->
+    </tr>
+  </table>
+</form>
+
+<script>
+<!--
+document.forms['f'].id.focus();
+//-->
+</script>
+
+<p>
+<h2>Getting Started</h2>
+
+<ul>
+<li> This is <b>case-insensitive</b> search.
+     <ul>
+     <li> &nbsp;<tt>table</tt>&nbsp;, &nbsp;<tt>Table</tt>&nbsp; 
+     and &nbsp;<tt>TABLE</tt>&nbsp; are all the same.
+     </ul>
+<li> This is <b>all words as substrings</b> search.<br>
+     Therefore you should <b>use stems</b> to get better results: 
+     <ul> 
+     <li> Use <tt>localiz</tt> instead of <tt>localize</tt> or 
+     <tt>localization</tt>.
+     <li> Use <tt>bookmark</tt> instead of <tt>bookmarks</tt> or 
+     <tt>bookmarking</tt>.
+     </ul>
+</ul>
+
+<a name="features"/>
+<h2>Features</h2>
+
+<ul>
+<li> Boolean operations: ``<tt>-foo</tt>''(NOT), ``<tt>foo bar</tt>''(AND), 
+     ``<tt>foo|bar</tt>''(OR).
+     <ul>
+     <li> <b>NOT</b>: Use &nbsp;<tt><b>-</b><i>foo</i></tt>&nbsp; to exclude bugs 
+          with &nbsp;<tt><i>foo</i></tt>&nbsp; in the summary.
+     <li> <b>AND</b>: Space-separated words are treated as a conjunction.
+     <li> <b>OR</b>: Within a word, "|"-separated parts denote alternatives. 
+     <li> Besides "|", a comma can be used to separate alternatives.
+     <li> OR has higher precedence than AND; AND is the top level operation
+     </ul>
+     <i>Example:</i> &nbsp;<tt>url,location bar,field -focus</tt>&nbsp; 
+     means
+     <nobr>(<tt>url</tt> OR <tt>location</tt>) AND (<tt>bar</tt> OR <tt>field</tt>) AND (NOT <tt>focus</tt>)</nobr>
+     <p>
+<li> Use &nbsp;<tt>+foo</tt>&nbsp; to search for bugs where the <b>summary</b> contains &nbsp;<tt>foo</tt>&nbsp; as a <b>substring</b>.<br>
+     Use &nbsp;<tt>#foo</tt>&nbsp; to search for bugs where the <b>summary</b> contains the <b>word</b> &nbsp;<tt>foo</tt>&nbsp; 
+     <ul>
+     <li> &nbsp;<tt>+brow</tt>&nbsp; does not find all bugs in the &nbsp;<tt>Browser</tt>&nbsp; product
+     <li> &nbsp;<tt>#title</tt>&nbsp; does not find bugs bugs with &nbsp;<tt>titlebar</tt>&nbsp; or &nbsp;<tt>titled</tt>&nbsp; 
+     </ul>
+     Phrases with special chars (space, comma, +, -, #, ...) can be <b>quoted</b>:
+     <ul>
+     <li> &nbsp;<tt>"lock icon"</tt>&nbsp;
+     </ul>
+<p>
+<li> <b>Open vs. Resolved Bugs</b>:<br>
+     By default, only open (i.e. unresolved) bugs are shown.
+     Use &nbsp;<tt>+DUP</tt>&nbsp; as first word in your query 
+     to include duplicate bugs in your search, 
+     &nbsp;<tt>FIXED</tt>&nbsp; to search for fixed bugs only,
+     or &nbsp;<tt>ALL</tt>&nbsp; to search all bugs, 
+     regardless of status or resolution. Searching for duplicates is
+     recommended if you can't find an open bug directly.
+     <ul>
+     <li> &nbsp;<tt>+DUP,FIXED table border</tt>&nbsp;
+     <li> &nbsp;<tt>ALL mouse wheel</tt>&nbsp;
+     </ul>
+<p>
+<li> <b>Focus the Search with Products &amp; Components</b>:<br>
+     To search for bugs in product "Foo Bar" only, add 
+     &nbsp;<tt>:foo</tt>&nbsp; or &nbsp;<tt>:bar</tt>&nbsp; or both
+     to your query.
+     You can do this with any substring of a 
+     <a href="describecomponents.cgi">product or component</a> 
+     to focus the search.
+</ul>
+
+<h2>More Tips</h2>
+
+<ul>
+<li> You can also use this tool to <b>lookup</b> a bug by its number.
+     <ul>
+     <li> &nbsp;<tt>12345</tt>&nbsp;
+     </ul>
+<li> A comma-separated list of bug numbers gives you a list of these bugs.
+     <ul>
+     <li> &nbsp;<tt>12345,23456,34567</tt>&nbsp;
+     </ul>
+</ul>
+
+<p>
+By default, the following fields are searched: Summary, Keywords, Product, 
+Component, Status Whiteboard. If a word looks like a part of a URL, that field
+is included in the search, too.
+<p>
+<!--
+<small>For further details, see 
+<a href="http://bugzilla.mozilla.org/show_bug.cgi?id=61561">Bug 61561</a> and 
+<a href="http://bugzilla.mozilla.org/show_bug.cgi?id=69793">Bug 69793</a>.
+</small>
+  -->
+<hr>
+
+Use the powerful 
+<a href="query.cgi">Bugzilla Query Form</a>
+for advanced queries.
+
+</body>
+</html>
+
+
+
+
+
diff --git a/quicksearch.js b/quicksearch.js
new file mode 100644 (file)
index 0000000..e14710c
--- /dev/null
@@ -0,0 +1,670 @@
+//
+// This is the main JS file for QuickSearch.
+//
+// Derived from:
+//
+//   * C. Begle's SimpleSearch tool:
+//     http://www.mozilla.org/quality/help/simplesearch.html
+//     http://www.mozilla.org/quality/help/bugreport.js 
+//
+//   * Jesse Ruderman's bugzilla search page:
+//     http://www.cs.hmc.edu/~jruderma/s/bugz.html
+//
+// Created by
+//     Andreas Franke <afranke@mathweb.org>
+
+function go_to (url) {
+  document.location.href = url;
+  //window.open(url, "other" );
+}
+
+function map(l, f) {
+    l1 = new Array();
+    for (var i=0; i<l.length; i++) {
+        l1[i] = f(l[i]);
+    }
+    return l1;
+}
+
+function isPrefix(s1, s2) {
+    return (s1.length <= s2.length) &&
+           (s1 == s2.substring(0,s1.length))
+}
+
+function member(s, l) {
+    return (l.length > 0)
+    && ((s == l[0]) || member(s, l.slice(1)));
+}
+
+function add(s, l) {
+    if (! member(s, l)) {
+        l.unshift(s);
+    }
+}
+
+function addAll(l1, l2) {
+    for (var i=0; i<l1.length; i++) {
+        add(l1[i],l2);
+    }        
+}
+
+function isSubset (l1, l2) {
+    return (l1.length == 0)
+    || (member(l1[0],l2) && subset(l1.slice(1),l2));
+}
+
+// fields
+
+var f1 = new Array();
+var f2 = new Array();
+
+function add_mapping(from,to) {
+    f1[f1.length] = from;
+    f2[f2.length] = to;
+}
+
+// Status, Resolution, Platform, OS, Priority, Severity
+add_mapping("status",             "bug_status");
+add_mapping("resolution",         "resolution");  // no change
+add_mapping("platform",           "rep_platform");
+add_mapping("os",                 "op_sys");
+add_mapping("opsys",              "op_sys");
+add_mapping("priority",           "priority");    // no change
+add_mapping("pri",                "priority");
+add_mapping("severity",           "bug_severity");
+add_mapping("sev",                "bug_severity");
+// People: AssignedTo, Reporter, QA Contact, CC, Added comment (?)
+add_mapping("owner",              "assigned_to");
+add_mapping("assignee",           "assigned_to");
+add_mapping("assignedto",         "assigned_to");
+add_mapping("reporter",           "reporter");    // no change
+add_mapping("rep",                "reporter");
+add_mapping("qa",                 "qa_contact"); 
+add_mapping("qacontact",          "qa_contact");
+add_mapping("cc",                 "cc");          // no change
+// Product, Version, Component, Target Milestone
+add_mapping("product",            "product");     // no change
+add_mapping("prod",               "product");
+add_mapping("version",            "version");     // no change
+add_mapping("ver",                "version");
+add_mapping("component",          "component");   // no change
+add_mapping("comp",               "component");
+add_mapping("milestone",          "target_milestone");
+add_mapping("target",             "target_milestone");
+add_mapping("targetmilestone",    "target_milestone");
+// Summary, Description, URL, Status whiteboard, Keywords
+add_mapping("summary",            "short_desc");
+add_mapping("shortdesc",          "short_desc");
+add_mapping("desc",               "longdesc");
+add_mapping("description",        "longdesc");
+//add_mapping("comment",          "longdesc");    // ???
+          // reserve "comment" for "added comment" email search?
+add_mapping("longdesc",           "longdesc");
+add_mapping("url",                "bug_file_loc");
+add_mapping("whiteboard",         "status_whiteboard");
+add_mapping("statuswhiteboard",   "status_whiteboard");
+add_mapping("sw",                 "status_whiteboard");
+add_mapping("keywords",           "keywords");    // no change
+add_mapping("kw",                 "keywords");
+// Attachments
+add_mapping("attachment",         "attachments.description");
+add_mapping("attachmentdesc",     "attachments.description");
+add_mapping("attachdesc",         "attachments.description");
+add_mapping("attachmentdata",     "attachments.thedata");
+add_mapping("attachdata",         "attachments.thedata");
+add_mapping("attachmentmimetype", "attachments.mimetype");
+add_mapping("attachmimetype",     "attachments.mimetype");
+
+// disabled because of bug 30823:
+// "BugsThisDependsOn"       --> "dependson"
+// "OtherBugsDependingOnThis"--> "blocked"
+//add_mapping("dependson",        "dependson"); 
+//add_mapping("blocked",          "blocked");
+
+// Substring search doesn't make much sense for the following fields: 
+// "Attachment is patch"    --> "attachments.ispatch"
+// "Last changed date"      --> "delta_ts"
+// "Days since bug changed" --> "(to_days(now()) - to_days(bugs.delta_ts))"
+//"groupset"
+//"everconfirmed"
+//"bug","bugid","bugno"     --> "bug_id"
+// "votes"                  --> "votes"
+//     "votes>5", "votes>=5", "votes=>5" works now, see below
+//     "votes:5" is interpreted as "votes>=5"
+
+function findIndex(array,value) {
+    for (var i=0; i<array.length; i++)
+        if (array[i] == value) return i;
+    return -1;
+}
+
+function mapField(fieldname) {
+    var i = findIndex(f1,fieldname);
+    if (i >= 0) return f2[i];
+    return undefined;
+} 
+
+// `keywords' is defined externally
+function is_keyword(s) {
+    return member(s, keywords);
+}
+
+// `platforms' is defined externally
+
+function is_platform(str) {
+    return member (str.toLowerCase(),platforms);
+}
+
+// `severities' is defined externally
+
+function is_severity(str) {
+    return member(str.toLowerCase(),severities);
+}
+
+// `product_exceptions' is defined externally
+
+function match_product(str) {
+    s = str.toLowerCase();
+    return (s.length > 2) && (! member(s,product_exceptions));
+}
+
+// `component_exceptions are defined externally
+
+function match_component(str) {
+    s = str.toLowerCase();
+    return (s.length > 2) && (! member(s,component_exceptions));
+}
+
+var status_and_resolution = ""; // for pretty debug output only; these vars
+var charts = "";                // always hold the data from the last query
+
+// derived from http://www.mozilla.org/quality/help/bugreport.js
+
+function make_chart(expr, field, type, value) {
+    charts += "<tr>" +
+              "<td><tt>" + expr + "</tt></td>" + 
+              "<td><tt>" + field + "</tt></td>" + 
+              "<td><tt>" + type + "</tt></td>" + 
+              "<td><tt>" + value + "</tt></td>" +
+              "</tr>";
+    return "&field" + expr + "=" + field +
+           "&type"  + expr + "=" + type  +
+           "&value" + expr + "=" + escape(value).replace(/[+]/g,"%2B");
+}
+
+// returns true if at least one of comparelist had the prefix, false otherwise
+function addPrefixMatches(prefix, comparelist, resultlist) {
+    var foundMatch = false;
+    for (var i=0; i<comparelist.length; i++) {
+        if (isPrefix(prefix,comparelist[i])) {
+            foundMatch = true;
+            add(comparelist[i],resultlist);
+        }
+    }
+    return foundMatch;
+}
+
+function prefixesNotFoundError(prefixes,statusValues,resolutionValues) {
+    var txt;
+    if (prefixes.length == 1) {
+        txt = "is not a prefix ";
+    } else {
+        txt = "are not prefixes ";
+    }
+    alert(prefixes + "\n" + txt + 
+          "of one of these status or resolution values:\n" +
+          statusValues + "\n" + resolutionValues + "\n");
+}
+
+function make_query_URL(url, input, searchLong) {
+
+    status_and_resolution = "";
+    charts = "";
+
+    var searchURL = url; //bugzilla + "buglist.cgi";
+    var abort = false;
+    
+    // escape everything between quotes: "foo bar" --> "foo%20bar"
+    var parts = input.split('"');
+    if ((parts.length % 2) != 1) {
+        alert('Unterminated quote');
+        abort = true;
+        return undefined;      
+    }
+    for (var i=1; i<parts.length; i+=2) {
+        parts[i] = escape(parts[i]);
+    }
+    var input2 = parts.join('"');
+
+    // abort if there are still brackets
+    if (input2.match(/[(]|[\)]/)) {
+        alert('Brackets (...) are not supported.\n' + 
+              'Use quotes "..." for values that contain special characters.');
+        abort = true;
+        return undefined;
+    }
+
+    // translate " AND "," OR "," NOT " to space,comma,dash
+    input2 = input2.replace(/[\s]+AND[\s]+/g," ");
+    input2 = input2.replace(/[\s]+OR[\s]+/g,"|");
+    input2 = input2.replace(/[\s]+NOT[\s]+/g," -");
+
+    // now split into words at space positions
+    var word = input2.split(/[\s]+/);
+
+    // determine bug_status and resolution 
+    // the first word may contain relevant info
+
+    // `statuses_open' and `statuses_resolved' are defined externally
+    var statusOpen     = statuses_open;
+    var statusResolved = statuses_resolved;
+    var statusAll      = statusOpen.concat(statusResolved);
+
+    // `resolutions' is defined externally
+    var bug_status = statusOpen.slice().reverse(); //reverse is just cosmetic
+    var resolution = new Array();
+
+    // This function matches the given prefixes against the given statuses and
+    // resolutions. Matched statuses are added to bug_status, matched 
+    // resolutions are added to resolution. Returns true iff some matches 
+    // were found for at least one of the given prefixes.
+    function matchPrefixes(prefixes,statuses,resolutions) {
+        var failedPrefixes = new Array();
+        var foundMatch = false;
+        for (var j=0; j<prefixes.length; j++) {
+            var ok1 = addPrefixMatches(prefixes[j],statuses,bug_status);
+            var ok2 = addPrefixMatches(prefixes[j],resolutions,resolution);
+            if ((! ok1) && (! ok2)) {
+                add(prefixes[j],failedPrefixes);
+            } else {
+                foundMatch = true;
+            }
+        }
+        //report an error if some (but not all) prefixes didn't match anything
+        if (foundMatch && (failedPrefixes.length > 0)) {
+            prefixesNotFoundError(failedPrefixes,statuses,resolutions);
+            abort = true;
+        }
+        return foundMatch;
+    }
+    
+    if (word[0] == "ALL") {
+        // special case: search for bugs regardless of status
+        addAll(statusResolved,bug_status);
+        word.shift();
+    } else if (word[0] == "OPEN") {
+        // special case: search for open bugs only
+        word.shift();
+    } else if (word[0].match("^[+][A-Z]+(,[A-Z]+)*$")) {
+        // e.g. +DUP,FIX 
+        w0 = word.shift();
+        prefixes = w0.substring(1).split(",");
+        if (! matchPrefixes(prefixes,statusResolved,resolutions)) {
+            word.unshift(w0);
+        }
+    } else if (word[0].match("^[A-Z]+(,[A-Z]+)*$")) {
+        // e.g. NEW,ASSI,REOP,FIX
+        bug_status = new Array(); // reset
+        w0 = word.shift();        
+        prefixes = w0.split(",");
+        if (! matchPrefixes(prefixes,statusAll,resolutions)) {
+            word.unshift(w0);
+            bug_status = statusOpen.reverse(); //reset to default bug_status
+        }
+    } else {
+        // default case: 
+        // search for unresolved bugs only
+        // uncomment this to include duplicate bugs in the search
+        // add("DUPLICATE",resolution);
+    }
+    if (resolution.length > 0) {
+        resolution = resolution.reverse();
+        resolution.unshift("---");
+        addAll(statusResolved,bug_status);
+    }
+    bug_status = bug_status.reverse();
+    bug_status = map(bug_status,escape);
+    searchURL += "?bug_status=" +  bug_status.join("&bug_status=");
+    status_and_resolution += 'Status: <tt>'+bug_status+'</tt>';
+
+    if (resolution.length > 0) {
+        resolution = map(resolution,escape);
+        searchURL += "&resolution=" + resolution.join("&resolution=");
+        status_and_resolution += '<br>'+'Resolution: <tt>'+resolution+'</tt>';
+    }
+                              
+    // end of bug_status & resolution stuff
+
+    var chart = 0;
+    var and   = 0;
+    var or    = 0;
+
+    var negation = false;
+
+    function negate_comparison_type(type) {
+        switch(type) {
+            case "substring": return "notsubstring";
+            case "anywords":  return "nowords";
+            case "regexp":    return "notregexp";
+            default:
+                // e.g. "greaterthan" 
+                alert("Can't negate comparison type: `" + type + "'");
+                abort = true;
+        }
+    }
+
+    function add_chart(field,type,value) {
+        // undo escaping for value: '"foo%20bar"' --> 'foo bar'
+        var parts = value.split('"');
+        if ((parts.length % 2) != 1) {
+            alert('Internal error: unescaping failure');
+            abort = true;
+        }
+        for (var i=1; i<parts.length; i+=2) {
+            parts[i] = unescape(parts[i]);
+        }
+        var value2 = parts.join('');
+
+        // negate type if negation is set
+        var type2 = type;
+        if (negation) {
+            type2 = negate_comparison_type(type2);
+        }
+        searchURL += make_chart(chart+"-"+and+"-"+or,field,type2,value2);
+        or++;
+        if (negation) {
+            and++;
+            or=0;
+        }
+    }
+
+    for (var i=0; i<word.length; i++, chart++) {
+
+        w = word[i];
+        
+        negation = false;
+        if (w[0] == "-") {
+            negation = true;
+            w = w.substring(1);
+        }
+
+        switch (w[0]) {
+            case "+":
+                alternative = w.substring(1).split(/[|,]/);
+                for (var j=0; j<alternative.length; j++)
+                    add_chart("short_desc","substring",alternative[j]);
+                break;
+            case "#":
+                alternative = w.substring(1).replace(/[|,]/g," ");
+                add_chart("short_desc","anywords",alternative);
+                if (searchLong)
+                    add_chart("longdesc","anywords",alternative);
+                break;
+            case ":":
+                alternative = w.substring(1).split(",");
+                for ( var j=0; j<alternative.length; j++) {
+                    add_chart("product","substring",alternative[j]);
+                    add_chart("component","substring",alternative[j]);
+                }
+                break;
+            case "@":
+                alternative = w.substring(1).split(",");
+                for ( var j=0; j<alternative.length; j++)
+                    add_chart("assigned_to","substring",alternative[j]);
+                break;
+            case "[":
+                add_chart("short_desc","substring",w);
+                add_chart("status_whiteboard","substring",w);
+                break;
+            case "!":
+                add_chart("keywords","anywords",w.substring(1));
+                break;
+            default:
+                alternative=w.split("|");
+                for (var j=0; j<alternative.length; j++) {
+
+                    w=alternative[j];
+
+                    // votes:xx ("at least xx votes")
+                    if (w.match("^votes[:][0-9]+$")) {
+                        n = w.split(/[:]/)[1];
+                        add_chart("votes","greaterthan",String(n-1));
+                        continue;
+                    }
+                    // generic field1,field2,field3:value1,value2 notation
+                    if (w.match("^[^:]+[:][^:\/][^:]*$")) {
+                        parts = w.split(":");
+                        fields = parts[0].split(/[,]+/);
+                        values = parts[1].split(/[,]+/);
+                        for (var k=0; k<fields.length; k++) {
+                            field = mapField(fields[k]);
+                            if (field == undefined) {
+                                alert("`"+fields[k]+"'"+
+                                      " is not a valid field name.");
+                                abort = true;
+                                return undefined;
+                            } else {
+                                 for (var l=0; l<values.length; l++) {
+                                     add_chart(field,"substring",values[l]);
+                                 }
+                            }  
+                        }
+                        continue;
+                    }
+                    comma_separated_words=w.split(/[,]+/);
+                    for (var k=0; k<comma_separated_words.length; k++) {
+                        w=comma_separated_words[k];
+
+                        // platform
+                        if (is_platform(w)) {
+                            add_chart("rep_platform","substring",w);
+                            continue;
+                        }
+                        // priority
+                        if (w.match("^[pP][1-5](,[pP]?[1-5])*$")) {
+                            expr = "["+w.replace(/[p,]/g,"")+"]";
+                            add_chart("priority","regexp",expr);
+                            continue;
+                        }
+                        if (w.match("^[pP][1-5]-[1-5]$")) {
+                            expr = "["+w.substring(1)+"]";
+                            add_chart("priority","regexp",expr);
+                            continue;
+                        }
+                        // severity
+                        if (is_severity(w)) {
+                            add_chart("bug_severity","substring",w);
+                            continue;
+                        }
+                        // votes>xx
+                        if (w.match("^votes>[0-9]+$")) {
+                            n = w.split(">")[1];
+                            add_chart("votes","greaterthan",n);
+                            continue;
+                        }
+                        // votes>=xx, votes=>xx
+                        if (w.match("^votes(>=|=>)[0-9]+$")) {
+                            separator = w.match("^votes(>=|=>)[0-9]+$")[1];
+                            n = w.split(separator)[1];
+                            add_chart("votes","greaterthan",String(n-1));
+                            continue;
+                        }
+                        // really default case
+                        if (match_product(w)) {
+                            add_chart("product","substring",w);
+                        }
+                        if (match_component(w)) {
+                            add_chart("component","substring",w);
+                        }
+                        if (is_keyword(w)) {
+                            add_chart("keywords","substring",w);
+                            if (w.length > 2) {
+                                add_chart("short_desc","substring",w);
+                                add_chart("status_whiteboard","substring",w);
+                            }
+                        } else {
+                            add_chart("short_desc","substring",w);
+                            add_chart("status_whiteboard","substring",w);
+                        }
+                        if (searchLong)
+                            add_chart("longdesc","substring",w);
+                 
+                        // URL field (for IP addrs, host.names, scheme://urls)
+                        if (w.match(/[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+/)
+                           || w.match(/^[A-Za-z]+([.][A-Za-z]+)+/)
+                           || w.match(/[:][\/][\/]/)
+                           || w.match(/localhost/)
+                           || w.match(/mailto[:]?/)
+                           // || w.match(/[A-Za-z]+[:][0-9]+/) //host:port
+                           )
+                            add_chart("bug_file_loc","substring",w);
+                    }
+                }
+        }
+
+        or = 0;
+    }
+
+    //searchURL += "&cmdtype=doit";
+
+    if (abort == false) {
+        return searchURL;
+    } else {
+        return undefined;
+    }
+}
+
+function unique_id () {
+    return (new Date()).getTime();
+}
+
+function ShowURL(mode) {
+    var input = document.f.id.value;
+    var searchURL = make_query_URL(bugzilla+"buglist.cgi", input, false);
+    if (searchURL != undefined) {
+        var pieces = searchURL.replace(/[\?]/g,"\n?").replace(/[\&]/g,"\n&");
+        if (mode == "alert") {
+            alert(pieces);
+        } else {
+            var table = "<table border=1>" + 
+                          "<thead>" + 
+                            "<tr>" + 
+                              "<th>Chart-And-Or</th>" + 
+                              "<th>Field</th>" + 
+                              "<th>Type</th>" + 
+                              "<th>Value</th>" + 
+                            "</tr>" + 
+                          "</thead>" + 
+                          "<tbody>" + charts + "</tbody>" +
+                        "</table>";
+            var html = '<html>' + 
+                         '<head>' + 
+                           '<title>' + input + '</title>' +
+                         '</head>' +
+                         '<body>' + 
+                           '<a href="' + searchURL + '">' +
+                             'Submit Query' +
+                           '</a>' +
+                           '<p>' + status_and_resolution + 
+                           '<p>' + table + 
+                           '<pre>' +
+                             pieces.replace(/[\n]/g,"<br>") +
+                           '</pre>' +  
+                         '</body>' +
+                       '</html>';
+            var w = window.open("","preview_"+unique_id());
+            w.document.write(html);
+            w.document.close();
+        }
+    }
+}
+
+//
+// new interface: 
+// searchLong is a boolean now (not a checkbox/radiobutton)
+//
+function Search(url, input, searchLong) {
+    var inputstring = new String(input);
+    var word = inputstring.split(/[\s]+/);
+  
+    // Check for empty input
+    if ( word.length == 1 && word[0] == "" )
+        return;
+    
+    // Check for potential Bugzilla-busting intensive queries
+    if ((searchLong!=false) && word.length > 4) {  
+        var message = "Searching Descriptions for more than four words " +
+                      "will take a very long time indeed. Please choose " +
+                      "no more than four keywords for your query.";
+        alert(message);
+        return;
+    }
+    var searchURL = make_query_URL(url, inputstring, searchLong);
+    if (searchURL != undefined) {
+        go_to(searchURL);
+         //window.open(searchURL, "other" );
+    } else {
+        return;
+    }
+}
+
+//
+// original interface, untested
+//
+//function SearchForBugs (input, searchRadio) {
+//    if (searchRadio[0].checked) {
+//        return Search(bugzilla + "buglist.cgi", input, false);
+//    } else {
+//        return Search(bugzilla + "buglist.cgi", input, true);
+//    }
+//}
+
+// derived from http://www.cs.hmc.edu/~jruderma/s/bugz.html
+
+// QuickSearch combines lookup-by-bug-number and search
+// in a single textbox. It's name must be document.f.id .
+//
+// type nothing:
+//    --> go to bugzilla front page
+// type a number:
+//    --> go to that bug number
+// type several numbers, separated by commas:
+//    --> go to a buglist of just those bug numbers
+// type anything else:
+//    --> search summary, product, component, keywords, status whiteboard
+//        (and URL if it's an IP address, a host.name, or an absolute://URL)
+
+function QuickSearch ()
+{
+    var input = document.f.id.value;
+
+    if (input == "") 
+    {
+        //once this _is_ on http://bugzilla.mozilla.org, it should just return;
+        go_to(bugzilla);
+    } 
+    else if (input.match(/^[0-9, ]*$/)) 
+    {
+        if (input.indexOf(",") == -1) {
+            // only _one_ bug number --> show_bug
+            go_to(bugzilla+"show_bug.cgi?id="+escape(input));
+        } else {
+            // comma-separated bug numbers --> buglist
+            go_to(bugzilla+"buglist.cgi?bug_id="+escape(input)
+                  + "&bugidtype=include&order=bugs.bug_id");
+        }
+    }
+    else
+    {
+        Search(bugzilla+"buglist.cgi",input,false);
+    }
+    return;
+}
+
+function LoadQuery() {
+    var input = document.f.id.value;
+    Search(bugzilla+"query.cgi",input,false);
+    return;
+}
+
diff --git a/quicksearchhack.html b/quicksearchhack.html
new file mode 100644 (file)
index 0000000..f8c15bc
--- /dev/null
@@ -0,0 +1,350 @@
+<html>
+<head>
+  <title>Bugzilla QuickSearch (for Hackers)</title>
+</head>
+
+<body bgcolor="#ffffff">
+
+<script src="localconfig.js"></script>
+<script src="quicksearch.js"></script>
+
+<h1>Bugzilla QuickSearch (for Hackers)</h1>
+
+Type in one or more words (or word fragments) to search for:
+
+<!-- The name of the form must be "f" (used in "quicksearch.js"). -->
+
+<form name="f" action="show_bug.cgi" method="get"
+      onsubmit="QuickSearch(); return false;">
+  <table>
+    <tr>
+      <td><input type="text" size="40" name="id"/></td>
+      <td align=left><input type="submit" name="run"  value="Search"/></td>
+      <td align=left><input type="button" name="load" value="Load Query"
+                      onclick="LoadQuery();" />
+      </td>
+    </tr>
+  </table>
+</form>
+
+<script>
+<!--
+document.forms['f'].id.focus();
+//-->
+</script>
+
+<p>
+This is a case-insensitive ``all words as substrings'' search;
+words are separated by spaces. 
+By default, the following fields are relevant: Summary, Keywords, 
+Product, Component, Status Whiteboard. If you enter only a single 
+word, the URL field is included in the search, too.
+<p>
+The generic format for a ``word'' is
+&nbsp;<tt>field1,...,fieldN:value1,...,valueM</tt>&nbsp;.
+A bug qualifies if at least one of the values occurs as a substring in 
+at least one of the fields. 
+For example, &nbsp;<tt>owner,reporter,qa:ibm,sun</tt>&nbsp;
+will give you bugs where the owner, reporter, or qa contact 
+has an email address that contains 
+&nbsp;<tt>ibm</tt>&nbsp; or &nbsp;<tt>sun</tt>&nbsp;.
+If only &nbsp;<tt>value1,...,valueM</tt>&nbsp; is given,
+the prefix (roughly) defaults to &nbsp;<tt>summary,keywords,product,component,statuswhiteboard:</tt>&nbsp; as noted above.
+<p>
+Here is a complete listing of available fields (the Shortcut column is just 
+for access speed):
+<p>
+
+<table border=1>
+<thead>
+<tr>
+  <td><b>Searched by default</b></td>
+  <td><b>Shortcut</b></td>
+  <td><b>Field Name</b></td>
+  <td><b>Aliases</b></td>
+  <td><b>Description</b></td>
+</tr>
+</thead>
+
+<!-- Status, Resolution, Platform, OS, Priority, Severity -->
+
+<tr>
+  <td>&nbsp;</td>
+  <td rowspan=2><tt><nobr>UNCO,NEW,...,CLOS,</nobr><br><nobr>FIX,DUP,...</nobr> <i><nobr>(as first word)</nobr></i></tt></td>
+  <td><tt>status</tt></td>
+  <td>&nbsp;</td>
+  <td><a href="bug_status.html">Status</a> 
+      <i>("bug_status")</i>
+  </td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td><tt>resolution</tt></td>
+  <td>&nbsp;</td>
+  <td><a href="bug_status.html">Resolution</a></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td><i>as-is</i></td>
+  <td><tt>platform</tt></td>
+  <td>&nbsp;</td>
+  <td><a href="bug_status.html#rep_platform">Platform</a> <i>("rep_platform")</i></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><tt>os</tt></td>
+  <td><tt>opsys</tt></td>
+  <td><a href="bug_status.html#op_sys">OS</a> <i>("op_sys")</i></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td><tt>p1,p2</tt> <i>or</i> <tt>p1-2</tt></td>
+  <td><tt>priority</tt></td>
+  <td><tt>pri</tt></td>
+  <td><a href="bug_status.html#priority">Priority</a></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td><tt>blo,cri,...,enh</tt></td>
+  <td><tt>severity</tt></td>
+  <td><tt>sev</tt></td>
+  <td><a href="bug_status.html#severity">Severity</a> <i>("bug_severity")</i></td>
+</tr>
+
+<!-- People: AssignedTo, Reporter, QA Contact, CC, Added comment -->
+<!-- Added comment is missing!!!! -->
+
+<tr>
+  <td>&nbsp;</td>
+  <td><b>@</b><i>owner</i></td>
+  <td><tt>assignedto</tt></td>
+  <td><tt>assignee, owner</tt></td>
+  <td><a href="bug_status.html#assigned_to">Assignee</a> <i>("assigned_to")</i></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><tt>reporter</tt></td>
+  <td><tt>rep</tt></td>
+  <td>Reporter (email)</td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><tt>qa</tt></td>
+  <td><tt>qacontact</tt></td>
+  <td>QA Contact (email) <i>("qa_contact")</i></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><tt>cc</tt></td>
+  <td>&nbsp;</td>
+  <td>CC (email)</td>
+</tr>
+
+<!-- Product, Version, Component, Target Milestone -->
+
+<tr>
+  <td><i>yes</i></td>
+  <td rowspan=2><b>:</b><i>area</i></td>
+  <td><tt>product</tt></td>
+  <td><tt>prod</tt></td>
+  <td>Product (enum)</td>
+</tr>
+<tr>
+  <td><i>yes</i></td>
+  <td><tt>component</tt></td>
+  <td><tt>comp</tt></td>
+  <td><a href="describecomponents.cgi">Component</a></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><tt>version</tt></td>
+  <td><tt>ver</tt></td>
+  <td>Version (enum)</td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><tt>milestone</tt></td>
+  <td><tt>target, targetmilestone</tt></td>
+  <td>Target Milestone <i>("target_milestone")</i></td>
+</tr>
+
+<!-- Summary, Description, URL, Status whiteboard, Keywords -->
+
+<tr>
+  <td><i>yes</i></td>
+  <td>&nbsp;</td>
+  <td><tt>summary</tt></td>
+  <td><tt>shortdesc</tt></td>
+  <td>Bug Summary (short text)<i>("short_desc")</i></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><tt>description</tt></td>
+  <td><tt>desc, longdesc<!--, comment--></tt></td>
+  <!-- reserve "comment" for "added comment" email search?! -->
+  <td>Bug Description / Comments (long text)</td>
+</tr>
+<tr>
+  <td><i>one-word queries only</i></td>
+  <td>&nbsp;</td>
+  <td><tt>url</tt></td>
+  <td>&nbsp;</td>
+  <td>URL <i>("bug_file_loc")</i></td>
+</tr>
+<tr>
+  <td><i>yes</i></td>
+  <td>&nbsp;</td>
+  <td><tt>statuswhiteboard</tt></td>
+  <td><tt>sw, whiteboard</tt></td>
+  <td>Status Whiteboard <i>("status_whiteboard")</i></td>
+</tr>
+<tr>
+  <td><i>yes</i></td>
+  <td><b>!</b><i>keyword</i></td>
+  <td><tt>keywords</tt></td>
+  <td><tt>kw</tt></td>
+  <td><a href="describekeywords.cgi">Keywords</a></td>
+</tr>
+
+<!-- Attachments -->
+
+<tr>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><tt>attachmentdesc</tt></td>
+  <td><tt>attachdesc</tt></td>
+  <td>Attachment Description <i>("attachments.description")</i></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><tt>attachmentdata</tt></td>
+  <td><tt>attachdata</tt></td>
+  <td>Attachment Data <i>("attachments.thedata")</i></td>
+</tr>
+<tr>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td><tt>attachmentmimetype</tt></td>
+  <td><tt>attachmimetype</tt></td>
+  <td>Attachment mime-type <i>("attachments.mimetype")</i></td>
+</tr>
+
+</table>
+
+<p>
+Examples for some useful abbreviations:
+<p>
+<table border=1>
+<thead>
+<tr>
+  <td><b>Syntax</b></td>
+  <td><b>Semantics and Examples</b></td>
+</tr>
+</thead>
+
+<!--
+<tr>
+  <td><i>STAT</i> <i>(as first word)</i></td>
+  <td><b>status,resolution:</b><i>STAT</i></td>
+</tr>
+<tr>
+  <td></td>
+  <td></td>
+</tr>
+<tr>
+  <td><tt>ALL</tt> <i>(as first word)</i></td>
+  <td><i>include all resolved bugs in your query</i></td>
+</tr>
+<tr>
+  <td><tt>+DUP,FIXED</tt> <i>(as first word)</i></td>
+  <td><i>include DUPLICATE and FIXED bugs in your search</i></td>
+</tr>
+-->
+
+<tr>
+  <td><b>:</b><i>area</i></td>
+  <td><b>product,component:</b><i>area</i></td>
+</tr>
+<!--
+<tr>
+  <td><tt>:browser</tt></td>
+  <td><i>bugs in the Browser product</i></td>
+</tr>
+ <td><tt>:mail</tt></td>
+  <td><i>bugs in the MailNews product</td>
+</tr>
+<tr>
+  <td><tt>:xbl</tt></td>
+  <td><i>bugs in the XBL component</i></td>
+</tr>
+  -->
+<tr>
+  <td><i>sev</i></td>
+  <td><b>severity:</b><i>sev</i></td>
+</tr>
+<tr>
+  <td><tt>blo,cri,maj</tt></td>
+  <td><i>severe bugs</td>
+</tr>
+<tr>
+  <td><tt>enh</tt></td>
+  <td><i>enhancement requests</i></td>
+</tr>
+<tr>
+  <td><b>p</b><i>level</i></td>
+  <td><b>priority:</b><i>level</i></td>
+</tr>
+<tr>
+  <td><tt>p1<tt></td>
+  <td><i>very high-priority bugs</i></td>
+</tr>
+<tr>
+  <td><tt>p1-2</tt></td>
+  <td><i>high-priority bugs</td>
+</tr>
+<tr>
+  <td><b>@</b><i>owner</i></td>
+  <td><b>assignedto:</b><i>owner</i></td>
+</tr>
+<!--
+<tr>
+  <td><tt>@nobody</tt></td>
+  <td><i>ownerless bugs</i></td>
+</tr>
+<tr>
+  <td><tt>@mozilla.org</tt></td>
+  <td><i>bugs assigned to mozilla.org members</i></td>
+</tr>
+  -->
+<tr>
+  <td><b>!</b><i>keyword</i></td>
+  <td><b>keywords:</b><i>keyword</i></td>
+</tr>
+<!--
+<tr>
+  <td><tt>!crash</tt></td>
+  <td><i>crasher bugs</i></td>
+</tr>
+<tr>
+  <td><tt>!helpwanted</tt></td>
+  <td><i>bugs waiting for your help</i></td>
+</tr>
+  -->
+</table>
+
+<p>
+More information can be found in the
+<a href="quicksearch.html#features">&quot;Features&quot;</a> section 
+on the <a href="quicksearch.html">introductory page</a>.
+
+</body>
+</html>
+