зеркало из https://github.com/mozilla/gecko-dev.git
Bug 138995 - split up search.html.tmpl. Patch by gerv; 2xr=myk.
This commit is contained in:
Родитель
1fcb78d629
Коммит
0313e1e25c
|
@ -0,0 +1,118 @@
|
||||||
|
<!-- 1.0@bugzilla.org -->
|
||||||
|
[%# 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 Netscape Communications
|
||||||
|
# Corporation. Portions created by Netscape are
|
||||||
|
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||||
|
# Rights Reserved.
|
||||||
|
#
|
||||||
|
# Contributor(s): Gervase Markham <gerv@gerv.net>
|
||||||
|
#%]
|
||||||
|
|
||||||
|
[% types = [
|
||||||
|
{ name => "noop", description => "---" },
|
||||||
|
{ name => "equals", description => "is equal to" },
|
||||||
|
{ name => "notequals", description => "is not equal to" },
|
||||||
|
{ name => "substring", description => "contains the string" },
|
||||||
|
{ name => "casesubstring", description => "contains the string (exact case)" },
|
||||||
|
{ name => "notsubstring", description => "does not contain the string" },
|
||||||
|
{ name => "allwordssubstr", description => "contains all of the strings" },
|
||||||
|
{ name => "anywordssubstr", description => "contains any of the strings" },
|
||||||
|
{ name => "regexp", description => "contains regexp" },
|
||||||
|
{ name => "notregexp", description => "does not contain regexp" },
|
||||||
|
{ name => "lessthan", description => "is less than" },
|
||||||
|
{ name => "greaterthan", description => "is greater than" },
|
||||||
|
{ name => "anywords", description => "contains any of the words" },
|
||||||
|
{ name => "allwords", description => "contains all of the words" },
|
||||||
|
{ name => "nowords", description => "contains none of the words" },
|
||||||
|
{ name => "changedbefore", description => "changed before" },
|
||||||
|
{ name => "changedafter", description => "changed after" },
|
||||||
|
{ name => "changedfrom", description => "changed from" },
|
||||||
|
{ name => "changedto", description => "changed to" },
|
||||||
|
{ name => "changedby", description => "changed by" } ] %]
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>
|
||||||
|
<a name="chart" href="queryhelp.cgi#advancedquerying">
|
||||||
|
Advanced Querying Using Boolean Charts</a>:
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
[%# Whoever wrote the original version of boolean charts had a seriously twisted mind %]
|
||||||
|
|
||||||
|
[% jsmagic = "onclick=\"document.forms[0].action='query.cgi#chart'; document.forms[0].method='POST'; return 1;\"" %]
|
||||||
|
|
||||||
|
[% FOREACH chart = default.charts %]
|
||||||
|
[% chartnum = loop.count - 1 %]
|
||||||
|
<table>
|
||||||
|
[% FOREACH row = chart %]
|
||||||
|
[% rownum = loop.count - 1 %]
|
||||||
|
<tr>
|
||||||
|
[% FOREACH col = row %]
|
||||||
|
[% colnum = loop.count - 1 %]
|
||||||
|
<td>
|
||||||
|
<select name="[% "field${chartnum}-${rownum}-${colnum}" %]">
|
||||||
|
[% FOREACH field = fields %]
|
||||||
|
<option value="[% field.name %]"
|
||||||
|
[%- " selected" IF field.name == col.field %]>[% field.description %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select name="[% "type${chartnum}-${rownum}-${colnum}" %]">
|
||||||
|
[% FOREACH type = types %]
|
||||||
|
<option value="[% type.name %]"
|
||||||
|
[%- " selected" IF type.name == col.type %]>[% type.description %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<input name="[% "value${chartnum}-${rownum}-${colnum}" %]"
|
||||||
|
value="[% col.value FILTER html %]">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
[% IF NOT col == row.last %]
|
||||||
|
<td align="center">
|
||||||
|
Or
|
||||||
|
</td>
|
||||||
|
[% ELSE %]
|
||||||
|
<td>
|
||||||
|
[% newor = colnum + 1 %]
|
||||||
|
<input type="submit" value="Or"
|
||||||
|
name="cmd-add[% "${chartnum}-${rownum}-${newor}" %]" [% $jsmagic %]>
|
||||||
|
</td>
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
[% END %]
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
[% IF NOT row == chart.last %]
|
||||||
|
<tr>
|
||||||
|
<td>And</td>
|
||||||
|
</tr>
|
||||||
|
[% ELSE %]
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
[% newand = rownum + 1; newchart = chartnum + 1 %]
|
||||||
|
<input type="submit" value="And"
|
||||||
|
name="cmd-add[% "${chartnum}-${newand}-0" %]"[% $jsmagic %]>
|
||||||
|
|
||||||
|
<input type="submit" value="Add another boolean chart"
|
||||||
|
name="cmd-add[% newchart %]-0-0" [% $jsmagic %]>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
[% END %]
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
[% END %]
|
|
@ -0,0 +1,670 @@
|
||||||
|
<!-- 1.0@bugzilla.org -->
|
||||||
|
[%# 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 Netscape Communications
|
||||||
|
# Corporation. Portions created by Netscape are
|
||||||
|
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||||
|
# Rights Reserved.
|
||||||
|
#
|
||||||
|
# Contributor(s): Chris Lahey <clahey@ximian.com> [javascript fixes]
|
||||||
|
# Christian Reis <kiko@async.com.br> [javascript rewrite]
|
||||||
|
# Gervase Markham <gerv@gerv.net>
|
||||||
|
#%]
|
||||||
|
|
||||||
|
[%# Note: use Template comments and not JS ones here, to avoid bloating
|
||||||
|
what we actually send to the browser %]
|
||||||
|
|
||||||
|
<script language="JavaScript" type="text/javascript"> <!--
|
||||||
|
|
||||||
|
var first_load = true; [%# is this the first time we load the page? %]
|
||||||
|
var last_sel = new Array(); [%# caches last selection %]
|
||||||
|
|
||||||
|
var cpts = new Array();
|
||||||
|
var vers = new Array();
|
||||||
|
[% IF Param('usetargetmilestone') %]
|
||||||
|
var tms = new Array();
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
[%# Create three arrays of components, versions and target milestones, indexed
|
||||||
|
# numerically according to the product they refer to. #%]
|
||||||
|
|
||||||
|
[% n = 0 %]
|
||||||
|
[% FOREACH p = product %]
|
||||||
|
cpts[[% n %]] = [
|
||||||
|
[%- FOREACH item = componentsbyproduct.$p %]'[% item FILTER js %]', [%- END -%]];
|
||||||
|
vers[[% n %]] = [
|
||||||
|
[%- FOREACH item = versionsbyproduct.$p -%]'[% item FILTER js %]', [%- END -%]];
|
||||||
|
[% IF Param('usetargetmilestone') %]
|
||||||
|
tms[[% n %]] = [
|
||||||
|
[%- FOREACH item = milestonesbyproduct.$p %]'[% item FILTER js %]', [%- END -%]];
|
||||||
|
[% END %]
|
||||||
|
[% n = n+1 %]
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
[%# updateSelect(array, sel, target, merging)
|
||||||
|
#
|
||||||
|
# Adds to the target select object all elements in array that
|
||||||
|
# correspond to the elements selected in source.
|
||||||
|
# - array should be a array of arrays, indexed by number. the
|
||||||
|
# array should contain the elements that correspond to that
|
||||||
|
# product.
|
||||||
|
# - sel is a list of selected items, either whole or a diff
|
||||||
|
# depending on merging.
|
||||||
|
# - target should be the target select object.
|
||||||
|
# - merging (boolean) determines if we are mergine in a diff or
|
||||||
|
# substituting the whole selection. a diff is used to optimize adding
|
||||||
|
# selections.
|
||||||
|
#
|
||||||
|
# Example (compsel is a select form control)
|
||||||
|
#
|
||||||
|
# var components = Array();
|
||||||
|
# components[1] = [ 'ComponentA', 'ComponentB' ];
|
||||||
|
# components[2] = [ 'ComponentC', 'ComponentD' ];
|
||||||
|
# source = [ 2 ];
|
||||||
|
# updateSelect(components, source, compsel, 0, 0);
|
||||||
|
#
|
||||||
|
# would clear compsel and add 'ComponentC' and 'ComponentD' to it.
|
||||||
|
#
|
||||||
|
%]
|
||||||
|
|
||||||
|
function updateSelect(array, sel, target, merging) {
|
||||||
|
|
||||||
|
var i, item;
|
||||||
|
|
||||||
|
[%# If we have no versions/components/milestones %]
|
||||||
|
if (array.length < 1) {
|
||||||
|
target.options.length = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (merging) {
|
||||||
|
[%# array merging/sorting in the case of multiple selections %]
|
||||||
|
[%# merge in the current options with the first selection %]
|
||||||
|
item = merge_arrays(array[sel[0]], target.options, 1);
|
||||||
|
|
||||||
|
[%# merge the rest of the selection with the results %]
|
||||||
|
for (i = 1 ; i < sel.length ; i++) {
|
||||||
|
item = merge_arrays(array[sel[i]], item, 0);
|
||||||
|
}
|
||||||
|
} else if ( sel.length > 1 ) {
|
||||||
|
[%# here we micro-optimize for two arrays to avoid merging with a
|
||||||
|
null array %]
|
||||||
|
item = merge_arrays(array[sel[0]],array[sel[1]], 0);
|
||||||
|
|
||||||
|
[%# merge the arrays. not very good for multiple selections. %]
|
||||||
|
for (i = 2; i < sel.length; i++) {
|
||||||
|
item = merge_arrays(item, array[sel[i]], 0);
|
||||||
|
}
|
||||||
|
} else { [%# single item in selection, just get me the list %]
|
||||||
|
item = array[sel[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[%# clear select %]
|
||||||
|
target.options.length = 0;
|
||||||
|
|
||||||
|
[%# load elements of list into select %]
|
||||||
|
for (i = 0; i < item.length; i++) {
|
||||||
|
target.options[i] = new Option(item[i], item[i]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[%# Returns elements in a that are not in b.
|
||||||
|
# NOT A REAL DIFF: does not check the reverse.
|
||||||
|
# - a,b: arrays of values to be compare. %]
|
||||||
|
function fake_diff_array(a, b) {
|
||||||
|
var newsel = new Array();
|
||||||
|
var found = false;
|
||||||
|
|
||||||
|
[%# do a boring array diff to see who's new %]
|
||||||
|
for (var ia in a) {
|
||||||
|
for (var ib in b) {
|
||||||
|
if (a[ia] == b[ib]) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
newsel[newsel.length] = a[ia];
|
||||||
|
}
|
||||||
|
found = false;
|
||||||
|
}
|
||||||
|
return newsel;
|
||||||
|
}
|
||||||
|
|
||||||
|
[%# takes two arrays and sorts them by string, returning a new, sorted
|
||||||
|
# array. the merge removes dupes, too.
|
||||||
|
# - a, b: arrays to be merge.
|
||||||
|
# - b_is_select: if true, then b is actually an optionitem and as
|
||||||
|
# such we need to use item.value on it. %]
|
||||||
|
function merge_arrays(a, b, b_is_select) {
|
||||||
|
var pos_a = 0;
|
||||||
|
var pos_b = 0;
|
||||||
|
var ret = new Array();
|
||||||
|
var bitem, aitem;
|
||||||
|
|
||||||
|
[%# iterate through both arrays and add the larger item to the return
|
||||||
|
list. remove dupes, too. Use toLowerCase to provide
|
||||||
|
case-insensitivity. %]
|
||||||
|
while ((pos_a < a.length) && (pos_b < b.length)) {
|
||||||
|
if (b_is_select) {
|
||||||
|
bitem = b[pos_b].value;
|
||||||
|
} else {
|
||||||
|
bitem = b[pos_b];
|
||||||
|
}
|
||||||
|
aitem = a[pos_a];
|
||||||
|
|
||||||
|
[%# smaller item in list a %]
|
||||||
|
if (aitem.toLowerCase() < bitem.toLowerCase()) {
|
||||||
|
ret[ret.length] = aitem;
|
||||||
|
pos_a++;
|
||||||
|
} else {
|
||||||
|
[%# smaller item in list b %]
|
||||||
|
if (aitem.toLowerCase() > bitem.toLowerCase()) {
|
||||||
|
ret[ret.length] = bitem;
|
||||||
|
pos_b++;
|
||||||
|
} else {
|
||||||
|
[%# list contents are equal, inc both counters. %]
|
||||||
|
ret[ret.length] = aitem;
|
||||||
|
pos_a++;
|
||||||
|
pos_b++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[%# catch leftovers here. these sections are ugly code-copying. %]
|
||||||
|
if (pos_a < a.length) {
|
||||||
|
for (; pos_a < a.length ; pos_a++) {
|
||||||
|
ret[ret.length] = a[pos_a];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos_b < b.length) {
|
||||||
|
for (; pos_b < b.length; pos_b++) {
|
||||||
|
if (b_is_select) {
|
||||||
|
bitem = b[pos_b].value;
|
||||||
|
} else {
|
||||||
|
bitem = b[pos_b];
|
||||||
|
}
|
||||||
|
ret[ret.length] = bitem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
[%# Returns an array of indexes or values from a select form control.
|
||||||
|
# - control: select control from which to find selections
|
||||||
|
# - findall: boolean, store all options when true or just the selected
|
||||||
|
# indexes
|
||||||
|
# - want_values: boolean; we store values when true and indexes when
|
||||||
|
# false %]
|
||||||
|
function getSelection(control, findall, want_values) {
|
||||||
|
var ret = new Array();
|
||||||
|
|
||||||
|
if ((!findall) && (control.selectedIndex == -1)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i=0; i<control.length; i++) {
|
||||||
|
if (findall || control.options[i].selected) {
|
||||||
|
ret[ret.length] = want_values ? control.options[i].value : i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
[%# Selects items in control that have index defined in sel
|
||||||
|
# - control: SELECT control to be restored
|
||||||
|
# - selnames: array of indexes in select form control %]
|
||||||
|
function restoreSelection(control, selnames) {
|
||||||
|
[%# right. this sucks. but I see no way to avoid going through the
|
||||||
|
# list and comparing to the contents of the control. %]
|
||||||
|
for (var j=0; j < selnames.length; j++) {
|
||||||
|
for (var i=0; i < control.options.length; i++) {
|
||||||
|
if (control.options[i].value == selnames[j]) {
|
||||||
|
control.options[i].selected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[%# selectProduct reads the selection from f.product and updates
|
||||||
|
# f.version, component and target_milestone accordingly.
|
||||||
|
# - f: a form containing product, component, varsion and
|
||||||
|
# target_milestone select boxes.
|
||||||
|
# globals (3vil!):
|
||||||
|
# - cpts, vers, tms: array of arrays, indexed by product name. the
|
||||||
|
# subarrays contain a list of names to be fed to the respective
|
||||||
|
# selectboxes. For bugzilla, these are generated with perl code
|
||||||
|
# at page start.
|
||||||
|
# - first_load: boolean, specifying if it is the first time we load
|
||||||
|
# the query page.
|
||||||
|
# - last_sel: saves our last selection list so we know what has
|
||||||
|
# changed, and optimize for additions. %]
|
||||||
|
function selectProduct(f) {
|
||||||
|
[%# this is to avoid handling events that occur before the form
|
||||||
|
itself is ready, which could happen in buggy browsers. %]
|
||||||
|
if ((!f) || (!f.product)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[%# if this is the first load and nothing is selected, no need to
|
||||||
|
merge and sort all components; perl gives it to us sorted. %]
|
||||||
|
if ((first_load) && (f.product.selectedIndex == -1)) {
|
||||||
|
first_load = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[%# turn first_load off. this is tricky, since it seems to be
|
||||||
|
redundant with the above clause. It's not: if when we first load
|
||||||
|
the page there is _one_ element selected, it won't fall into that
|
||||||
|
clause, and first_load will remain 1. Then, if we unselect that
|
||||||
|
item, selectProduct will be called but the clause will be valid
|
||||||
|
(since selectedIndex == -1), and we will return - incorrectly -
|
||||||
|
without merge/sorting. %]
|
||||||
|
first_load = false;
|
||||||
|
|
||||||
|
[%# - sel keeps the array of products we are selected.
|
||||||
|
- merging says if it is a full list or just a list of products that
|
||||||
|
were added to the current selection. %]
|
||||||
|
var merging = false;
|
||||||
|
var sel = Array();
|
||||||
|
|
||||||
|
[%# if nothing selected, pick all %]
|
||||||
|
var findall = f.product.selectedIndex == -1;
|
||||||
|
sel = getSelection(f.product, findall, false);
|
||||||
|
if (!findall) {
|
||||||
|
[%# save sel for the next invocation of selectProduct() %]
|
||||||
|
var tmp = sel;
|
||||||
|
|
||||||
|
[%# this is an optimization: if we have just added products to an
|
||||||
|
existing selection, no need to clear the form controls and add
|
||||||
|
everybody again; just merge the new ones with the existing
|
||||||
|
options. %]
|
||||||
|
if ((last_sel.length > 0) && (last_sel.length < sel.length)) {
|
||||||
|
sel = fake_diff_array(sel, last_sel);
|
||||||
|
merging = true;
|
||||||
|
}
|
||||||
|
last_sel = tmp;
|
||||||
|
}
|
||||||
|
[%# save original options selected %]
|
||||||
|
var saved_cpts = getSelection(f.component, false, true);
|
||||||
|
var saved_vers = getSelection(f.version, false, true);
|
||||||
|
[% IF Param('usetargetmilestone') %]
|
||||||
|
var saved_tms = getSelection(f.target_milestone, false, true);
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
[%# do the actual fill/update, reselect originally selected options %]
|
||||||
|
updateSelect(cpts, sel, f.component, merging);
|
||||||
|
restoreSelection(f.component, saved_cpts);
|
||||||
|
updateSelect(vers, sel, f.version, merging);
|
||||||
|
restoreSelection(f.version, saved_vers);
|
||||||
|
[% IF Param('usetargetmilestone') %]
|
||||||
|
updateSelect(tms, sel, f.target_milestone, merging);
|
||||||
|
restoreSelection(f.target_milestone, saved_tms);
|
||||||
|
[% END %]
|
||||||
|
}
|
||||||
|
|
||||||
|
// -->
|
||||||
|
</script>
|
||||||
|
|
||||||
|
[% query_variants = [
|
||||||
|
{ value => "allwordssubstr", description => "contains all of the words/strings" },
|
||||||
|
{ value => "anywordssubstr", description => "contains any of the words/strings" },
|
||||||
|
{ value => "substring", description => "contains the string" },
|
||||||
|
{ value => "casesubstring", description => "contains the string (exact case)" },
|
||||||
|
{ value => "allwords", description => "contains all of the words" },
|
||||||
|
{ value => "anywords", description => "contains any of the words" },
|
||||||
|
{ value => "regexp", description => "matches the regexp" },
|
||||||
|
{ value => "notregexp", description => "doesn’t match the regexp" } ] %]
|
||||||
|
|
||||||
|
[%# *** Summary *** %]
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th align="right">Summary:</th>
|
||||||
|
<td>
|
||||||
|
<select name="short_desc_type">
|
||||||
|
[% FOREACH qv = query_variants %]
|
||||||
|
<option value="[% qv.value %]"
|
||||||
|
[% " selected" IF default.short_desc_type.0 == qv.value %]>[% qv.description %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input name="short_desc" size="40" value="[% default.short_desc.0 FILTER html %]">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="submit" value="[% button_name %]">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
[%# *** Product Component Version Target *** %]
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td colspan="4">
|
||||||
|
<table>
|
||||||
|
<tr valign="bottom">
|
||||||
|
<th align="left">Product:</th>
|
||||||
|
<th align="left"><a href="describecomponents.cgi">Component</a>:</th>
|
||||||
|
<th align="left">Version:</th>
|
||||||
|
|
||||||
|
[% IF (Param("usetargetmilestone")) %]
|
||||||
|
<th align="left">Target:</th>
|
||||||
|
[% END %]
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr valign="top">
|
||||||
|
|
||||||
|
[%# Can't use the select block here because of onChange and the fact that
|
||||||
|
'component' is a toolkit reserved word - we use 'component_' instead. %]
|
||||||
|
<td align="left">
|
||||||
|
<select name="product" multiple size="5" onChange="selectProduct(this.form);">
|
||||||
|
[% FOREACH p = product %]
|
||||||
|
<option value="[% p FILTER html %]"
|
||||||
|
[% " selected" IF lsearch(default.product, p) != -1 %]>
|
||||||
|
[% p FILTER html %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td align="left">
|
||||||
|
<select name="component" 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>
|
||||||
|
|
||||||
|
[% PROCESS select sel = { name => 'version', size => 5 } %]
|
||||||
|
|
||||||
|
[% IF Param('usetargetmilestone') && target_milestone.size > 0 %]
|
||||||
|
[% PROCESS select sel = { name => 'target_milestone', size => 5 } %]
|
||||||
|
[% END %]
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
[%# *** Comment URL Whiteboard Keywords *** %]
|
||||||
|
|
||||||
|
[% FOREACH field = [
|
||||||
|
{ name => "long_desc", description => "A comment" },
|
||||||
|
{ name => "bug_file_loc", description => "The URL" },
|
||||||
|
{ name => "status_whiteboard", description => "Whiteboard" } ] %]
|
||||||
|
|
||||||
|
[% UNLESS field.name == 'status_whiteboard' AND NOT Param('usestatuswhiteboard') %]
|
||||||
|
<tr>
|
||||||
|
<th align="right">[% field.description %]:</th>
|
||||||
|
<td>
|
||||||
|
<select name="[% field.name %]_type">
|
||||||
|
[% FOREACH qv = query_variants %]
|
||||||
|
[% type = "${field.name}_type" %]
|
||||||
|
<option value="[% qv.value %]"
|
||||||
|
[% " selected" IF default.$type.0 == qv.value %]>[% qv.description %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td><input name="[% field.name %]" size="40" value="
|
||||||
|
[% default.${field.name}.0 FILTER html %]">
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
[% END %]
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
[% IF have_keywords %]
|
||||||
|
<tr>
|
||||||
|
<th align="right"><a href="describekeywords.cgi">Keywords</a>:</th>
|
||||||
|
<td>
|
||||||
|
<select name="keywords_type">
|
||||||
|
[% FOREACH qv = [
|
||||||
|
{ name => "anywords", description => "contains any of the keywords" },
|
||||||
|
{ name => "allwords", description => "contains all of the keywords" },
|
||||||
|
{ name => "nowords", description => "contains none of the keywords" } ] %]
|
||||||
|
|
||||||
|
<option value="[% qv.name %]"
|
||||||
|
[% " selected" IF default.keywords_type.0 == qv.name %]>
|
||||||
|
[% qv.description %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input name="keywords" size="40" value="[% default.keywords.0 FILTER html %]">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
[% END %]
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
[%# *** Status Resolution Severity Priority Hardware OS *** %]
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th align="left"><a href="queryhelp.cgi#status">Status</a>:</th>
|
||||||
|
<th align="left"><a href="queryhelp.cgi#resolution">Resolution</a>:</th>
|
||||||
|
<th align="left"><a href="queryhelp.cgi#severity">Severity</a>:</th>
|
||||||
|
<th align="left"><a href="queryhelp.cgi#priority">Priority</a>:</th>
|
||||||
|
<th align="left"><a href="queryhelp.cgi#platform">Hardware</a>:</th>
|
||||||
|
<th align="left"><a href="queryhelp.cgi#opsys">OS</a>:</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr valign="top">
|
||||||
|
[% PROCESS select sel = { name => 'bug_status', size => 7 } %]
|
||||||
|
[% PROCESS select sel = { name => 'resolution', size => 7 } %]
|
||||||
|
[% PROCESS select sel = { name => 'bug_severity', size => 7 } %]
|
||||||
|
[% PROCESS select sel = { name => 'priority', size => 7 } %]
|
||||||
|
[% PROCESS select sel = { name => 'rep_platform', size => 7 } %]
|
||||||
|
[% PROCESS select sel = { name => 'op_sys', size => 7 } %]
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
[%# *** Email Numbering Votes *** %]
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<fieldset>
|
||||||
|
<legend>
|
||||||
|
<strong>
|
||||||
|
<a href="queryhelp.cgi#peopleinvolved">Email</a> and Numbering
|
||||||
|
</strong>
|
||||||
|
</legend>
|
||||||
|
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
[% FOREACH n = [1, 2] %]
|
||||||
|
<td>
|
||||||
|
|
||||||
|
|
||||||
|
<table cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
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 %]">
|
||||||
|
bug owner
|
||||||
|
</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 %]">
|
||||||
|
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 %]">
|
||||||
|
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 %]">
|
||||||
|
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 %]">
|
||||||
|
commenter
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<select name="emailtype[% n %]">
|
||||||
|
[% FOREACH qv = [
|
||||||
|
{ name => "substring", description => "contains" },
|
||||||
|
{ name => "exact", description => "is" },
|
||||||
|
{ 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>
|
||||||
|
[% END %]
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<select name="bugidtype">
|
||||||
|
<option value="include"[% " selected" IF default.bugidtype.0 == "include" %]>Only include</option>
|
||||||
|
<option value="exclude"[% " selected" IF default.bugidtype.0 == "exclude" %]>Exclude</option>
|
||||||
|
</select>
|
||||||
|
bugs numbered:
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="bug_id" value="[% default.bug_id.0 FILTER html %]" size="20">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>(comma-separated list)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
Only bugs with at least:
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input name="votes" size="3" value="[% default.votes.0 FILTER html %]"> votes
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
[%# *** Bug Changes *** %]
|
||||||
|
|
||||||
|
<td valign="top">
|
||||||
|
<fieldset>
|
||||||
|
<legend><strong>Bug Changes</strong></legend>
|
||||||
|
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>Only bugs changed in the last </dt>
|
||||||
|
<dd><input name=changedin size=3 value="[% default.changedin.0 FILTER html %]"> days</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>Only bugs where any of the fields</dt>
|
||||||
|
<dd>
|
||||||
|
<select name="chfield" multiple size="4">
|
||||||
|
[% FOREACH field = chfield %]
|
||||||
|
<option value="[% field FILTER html %]"
|
||||||
|
[% " selected" IF lsearch(default.chfield, field) != -1 %]>
|
||||||
|
[% field FILTER html %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>were changed between</dt>
|
||||||
|
<dd>
|
||||||
|
<input name="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)
|
||||||
|
</dd>
|
||||||
|
<dt>to this value: (optional)</dt>
|
||||||
|
<dd>
|
||||||
|
<input name="chfieldvalue" size="20" value="[% default.chfieldvalue.0 FILTER html %]">
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
[%# Note: the <form> tag is unclosed at the end of this template %]
|
||||||
|
|
||||||
|
[%############################################################################%]
|
||||||
|
[%# Block for SELECT fields #%]
|
||||||
|
[%############################################################################%]
|
||||||
|
|
||||||
|
[% BLOCK select %]
|
||||||
|
<td align="left">
|
||||||
|
<select name="[% sel.name %]" multiple size="[% sel.size %]">
|
||||||
|
[% FOREACH name = ${sel.name} %]
|
||||||
|
<option value="[% name FILTER html %]"
|
||||||
|
[% " selected" IF lsearch(default.${sel.name}, name) != -1 %]>
|
||||||
|
[% name FILTER html %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
[% END %]
|
|
@ -0,0 +1,95 @@
|
||||||
|
<!-- 1.0@bugzilla.org -->
|
||||||
|
[%# 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 Netscape Communications
|
||||||
|
# Corporation. Portions created by Netscape are
|
||||||
|
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||||
|
# Rights Reserved.
|
||||||
|
#
|
||||||
|
# Contributor(s): Gervase Markham <gerv@gerv.net>
|
||||||
|
#%]
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
|
||||||
|
[% IF NOT userid %]
|
||||||
|
<input type="hidden" name="cmdtype" value="doit">
|
||||||
|
[% ELSE %]
|
||||||
|
<br>
|
||||||
|
<input type="radio" name="cmdtype" value="doit" checked> Run this query
|
||||||
|
<br>
|
||||||
|
|
||||||
|
[% IF namedqueries.size > 0 %]
|
||||||
|
<p>
|
||||||
|
<table cellspacing="0" cellpadding="0">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="cmdtype" value="editnamed">
|
||||||
|
Load my remembered query:
|
||||||
|
</td>
|
||||||
|
<td rowspan="3">
|
||||||
|
<select name="namedcmd">
|
||||||
|
[% FOREACH query = namedqueries %]
|
||||||
|
<option value="[% query FILTER html %]">[% query FILTER html %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="cmdtype" value="runnamed">
|
||||||
|
Run my remembered query:
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="radio" name="cmdtype" value="forgetnamed">
|
||||||
|
Forget my remembered query:
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
<input type="radio" name="cmdtype" value="asdefault">
|
||||||
|
Remember this as my default query
|
||||||
|
<br>
|
||||||
|
<input type="radio" name="cmdtype" value="asnamed">
|
||||||
|
Remember this query, and name it:
|
||||||
|
<input type="text" name="newqueryname">
|
||||||
|
<br> <input type="checkbox" name="tofooter" value="1">
|
||||||
|
and put it in my page footer
|
||||||
|
<br>
|
||||||
|
[% END %]
|
||||||
|
<br>
|
||||||
|
<div>
|
||||||
|
Sort results by:
|
||||||
|
<select name="order">
|
||||||
|
[% FOREACH order = orders %]
|
||||||
|
<option value="[% order FILTER html %]"
|
||||||
|
[% " selected" IF default.order.0 == order %]>[% order FILTER html %]</option>
|
||||||
|
[% END %]
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<input type="submit" value="[% button_name %]">
|
||||||
|
[% IF userdefaultquery %]
|
||||||
|
<p>
|
||||||
|
<a href="query.cgi?nukedefaultquery=1">
|
||||||
|
Set my default query back to the system default</a>
|
||||||
|
</p>
|
||||||
|
[% END %]
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
|
@ -16,9 +16,7 @@
|
||||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||||
# Rights Reserved.
|
# Rights Reserved.
|
||||||
#
|
#
|
||||||
# Contributor(s): Chris Lahey <clahey@ximian.com> [javascript fixes]
|
# Contributor(s): Gervase Markham <gerv@gerv.net>
|
||||||
# Christian Reis <kiko@async.com.br> [javascript rewrite]
|
|
||||||
# Gervase Markham <gerv@gerv.net>
|
|
||||||
#%]
|
#%]
|
||||||
|
|
||||||
[% PROCESS global/header.html.tmpl
|
[% PROCESS global/header.html.tmpl
|
||||||
|
@ -26,833 +24,20 @@
|
||||||
extra = " onLoad=\"selectProduct(document.forms['queryform']);\""
|
extra = " onLoad=\"selectProduct(document.forms['queryform']);\""
|
||||||
%]
|
%]
|
||||||
|
|
||||||
[%# Note: use Template comments and not JS ones here, to avoid bloating
|
[% button_name = "Search" %]
|
||||||
what we actually send to the browser %]
|
|
||||||
|
|
||||||
<script language="JavaScript" type="text/javascript"> <!--
|
[% PROCESS search/form.html.tmpl %]
|
||||||
|
|
||||||
var first_load = true; [%# is this the first time we load the page? %]
|
[% PROCESS search/knob.html.tmpl %]
|
||||||
var last_sel = new Array(); [%# caches last selection %]
|
|
||||||
|
|
||||||
var cpts = new Array();
|
|
||||||
var vers = new Array();
|
|
||||||
[% IF Param('usetargetmilestone') %]
|
|
||||||
var tms = new Array();
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[%# Create three arrays of components, versions and target milestones, indexed
|
|
||||||
# numerically according to the product they refer to. #%]
|
|
||||||
|
|
||||||
[% n = 0 %]
|
|
||||||
[% FOREACH p = product %]
|
|
||||||
cpts[[% n %]] = [
|
|
||||||
[%- FOREACH item = componentsbyproduct.$p %]'[% item FILTER js %]', [%- END -%]];
|
|
||||||
vers[[% n %]] = [
|
|
||||||
[%- FOREACH item = versionsbyproduct.$p -%]'[% item FILTER js %]', [%- END -%]];
|
|
||||||
[% IF Param('usetargetmilestone') %]
|
|
||||||
tms[[% n %]] = [
|
|
||||||
[%- FOREACH item = milestonesbyproduct.$p %]'[% item FILTER js %]', [%- END -%]];
|
|
||||||
[% END %]
|
|
||||||
[% n = n+1 %]
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[%# updateSelect(array, sel, target, merging)
|
|
||||||
#
|
|
||||||
# Adds to the target select object all elements in array that
|
|
||||||
# correspond to the elements selected in source.
|
|
||||||
# - array should be a array of arrays, indexed by number. the
|
|
||||||
# array should contain the elements that correspond to that
|
|
||||||
# product.
|
|
||||||
# - sel is a list of selected items, either whole or a diff
|
|
||||||
# depending on merging.
|
|
||||||
# - target should be the target select object.
|
|
||||||
# - merging (boolean) determines if we are mergine in a diff or
|
|
||||||
# substituting the whole selection. a diff is used to optimize adding
|
|
||||||
# selections.
|
|
||||||
#
|
|
||||||
# Example (compsel is a select form control)
|
|
||||||
#
|
|
||||||
# var components = Array();
|
|
||||||
# components[1] = [ 'ComponentA', 'ComponentB' ];
|
|
||||||
# components[2] = [ 'ComponentC', 'ComponentD' ];
|
|
||||||
# source = [ 2 ];
|
|
||||||
# updateSelect(components, source, compsel, 0, 0);
|
|
||||||
#
|
|
||||||
# would clear compsel and add 'ComponentC' and 'ComponentD' to it.
|
|
||||||
#
|
|
||||||
%]
|
|
||||||
|
|
||||||
function updateSelect(array, sel, target, merging) {
|
|
||||||
|
|
||||||
var i, item;
|
|
||||||
|
|
||||||
[%# If we have no versions/components/milestones %]
|
|
||||||
if (array.length < 1) {
|
|
||||||
target.options.length = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (merging) {
|
|
||||||
[%# array merging/sorting in the case of multiple selections %]
|
|
||||||
[%# merge in the current options with the first selection %]
|
|
||||||
item = merge_arrays(array[sel[0]], target.options, 1);
|
|
||||||
|
|
||||||
[%# merge the rest of the selection with the results %]
|
|
||||||
for (i = 1 ; i < sel.length ; i++) {
|
|
||||||
item = merge_arrays(array[sel[i]], item, 0);
|
|
||||||
}
|
|
||||||
} else if ( sel.length > 1 ) {
|
|
||||||
[%# here we micro-optimize for two arrays to avoid merging with a
|
|
||||||
null array %]
|
|
||||||
item = merge_arrays(array[sel[0]],array[sel[1]], 0);
|
|
||||||
|
|
||||||
[%# merge the arrays. not very good for multiple selections. %]
|
|
||||||
for (i = 2; i < sel.length; i++) {
|
|
||||||
item = merge_arrays(item, array[sel[i]], 0);
|
|
||||||
}
|
|
||||||
} else { [%# single item in selection, just get me the list %]
|
|
||||||
item = array[sel[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# clear select %]
|
|
||||||
target.options.length = 0;
|
|
||||||
|
|
||||||
[%# load elements of list into select %]
|
|
||||||
for (i = 0; i < item.length; i++) {
|
|
||||||
target.options[i] = new Option(item[i], item[i]);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# Returns elements in a that are not in b.
|
|
||||||
# NOT A REAL DIFF: does not check the reverse.
|
|
||||||
# - a,b: arrays of values to be compare. %]
|
|
||||||
function fake_diff_array(a, b) {
|
|
||||||
var newsel = new Array();
|
|
||||||
var found = false;
|
|
||||||
|
|
||||||
[%# do a boring array diff to see who's new %]
|
|
||||||
for (var ia in a) {
|
|
||||||
for (var ib in b) {
|
|
||||||
if (a[ia] == b[ib]) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
newsel[newsel.length] = a[ia];
|
|
||||||
}
|
|
||||||
found = false;
|
|
||||||
}
|
|
||||||
return newsel;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# takes two arrays and sorts them by string, returning a new, sorted
|
|
||||||
# array. the merge removes dupes, too.
|
|
||||||
# - a, b: arrays to be merge.
|
|
||||||
# - b_is_select: if true, then b is actually an optionitem and as
|
|
||||||
# such we need to use item.value on it. %]
|
|
||||||
function merge_arrays(a, b, b_is_select) {
|
|
||||||
var pos_a = 0;
|
|
||||||
var pos_b = 0;
|
|
||||||
var ret = new Array();
|
|
||||||
var bitem, aitem;
|
|
||||||
|
|
||||||
[%# iterate through both arrays and add the larger item to the return
|
|
||||||
list. remove dupes, too. Use toLowerCase to provide
|
|
||||||
case-insensitivity. %]
|
|
||||||
while ((pos_a < a.length) && (pos_b < b.length)) {
|
|
||||||
if (b_is_select) {
|
|
||||||
bitem = b[pos_b].value;
|
|
||||||
} else {
|
|
||||||
bitem = b[pos_b];
|
|
||||||
}
|
|
||||||
aitem = a[pos_a];
|
|
||||||
|
|
||||||
[%# smaller item in list a %]
|
|
||||||
if (aitem.toLowerCase() < bitem.toLowerCase()) {
|
|
||||||
ret[ret.length] = aitem;
|
|
||||||
pos_a++;
|
|
||||||
} else {
|
|
||||||
[%# smaller item in list b %]
|
|
||||||
if (aitem.toLowerCase() > bitem.toLowerCase()) {
|
|
||||||
ret[ret.length] = bitem;
|
|
||||||
pos_b++;
|
|
||||||
} else {
|
|
||||||
[%# list contents are equal, inc both counters. %]
|
|
||||||
ret[ret.length] = aitem;
|
|
||||||
pos_a++;
|
|
||||||
pos_b++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# catch leftovers here. these sections are ugly code-copying. %]
|
|
||||||
if (pos_a < a.length) {
|
|
||||||
for (; pos_a < a.length ; pos_a++) {
|
|
||||||
ret[ret.length] = a[pos_a];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos_b < b.length) {
|
|
||||||
for (; pos_b < b.length; pos_b++) {
|
|
||||||
if (b_is_select) {
|
|
||||||
bitem = b[pos_b].value;
|
|
||||||
} else {
|
|
||||||
bitem = b[pos_b];
|
|
||||||
}
|
|
||||||
ret[ret.length] = bitem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# Returns an array of indexes or values from a select form control.
|
|
||||||
# - control: select control from which to find selections
|
|
||||||
# - findall: boolean, store all options when true or just the selected
|
|
||||||
# indexes
|
|
||||||
# - want_values: boolean; we store values when true and indexes when
|
|
||||||
# false %]
|
|
||||||
function getSelection(control, findall, want_values) {
|
|
||||||
var ret = new Array();
|
|
||||||
|
|
||||||
if ((!findall) && (control.selectedIndex == -1)) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i=0; i<control.length; i++) {
|
|
||||||
if (findall || control.options[i].selected) {
|
|
||||||
ret[ret.length] = want_values ? control.options[i].value : i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# Selects items in control that have index defined in sel
|
|
||||||
# - control: SELECT control to be restored
|
|
||||||
# - selnames: array of indexes in select form control %]
|
|
||||||
function restoreSelection(control, selnames) {
|
|
||||||
[%# right. this sucks. but I see no way to avoid going through the
|
|
||||||
# list and comparing to the contents of the control. %]
|
|
||||||
for (var j=0; j < selnames.length; j++) {
|
|
||||||
for (var i=0; i < control.options.length; i++) {
|
|
||||||
if (control.options[i].value == selnames[j]) {
|
|
||||||
control.options[i].selected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# selectProduct reads the selection from f.product and updates
|
|
||||||
# f.version, component and target_milestone accordingly.
|
|
||||||
# - f: a form containing product, component, varsion and
|
|
||||||
# target_milestone select boxes.
|
|
||||||
# globals (3vil!):
|
|
||||||
# - cpts, vers, tms: array of arrays, indexed by product name. the
|
|
||||||
# subarrays contain a list of names to be fed to the respective
|
|
||||||
# selectboxes. For bugzilla, these are generated with perl code
|
|
||||||
# at page start.
|
|
||||||
# - first_load: boolean, specifying if it is the first time we load
|
|
||||||
# the query page.
|
|
||||||
# - last_sel: saves our last selection list so we know what has
|
|
||||||
# changed, and optimize for additions. %]
|
|
||||||
function selectProduct(f) {
|
|
||||||
[%# this is to avoid handling events that occur before the form
|
|
||||||
itself is ready, which could happen in buggy browsers. %]
|
|
||||||
if ((!f) || (!f.product)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# if this is the first load and nothing is selected, no need to
|
|
||||||
merge and sort all components; perl gives it to us sorted. %]
|
|
||||||
if ((first_load) && (f.product.selectedIndex == -1)) {
|
|
||||||
first_load = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# turn first_load off. this is tricky, since it seems to be
|
|
||||||
redundant with the above clause. It's not: if when we first load
|
|
||||||
the page there is _one_ element selected, it won't fall into that
|
|
||||||
clause, and first_load will remain 1. Then, if we unselect that
|
|
||||||
item, selectProduct will be called but the clause will be valid
|
|
||||||
(since selectedIndex == -1), and we will return - incorrectly -
|
|
||||||
without merge/sorting. %]
|
|
||||||
first_load = false;
|
|
||||||
|
|
||||||
[%# - sel keeps the array of products we are selected.
|
|
||||||
- merging says if it is a full list or just a list of products that
|
|
||||||
were added to the current selection. %]
|
|
||||||
var merging = false;
|
|
||||||
var sel = Array();
|
|
||||||
|
|
||||||
[%# if nothing selected, pick all %]
|
|
||||||
var findall = f.product.selectedIndex == -1;
|
|
||||||
sel = getSelection(f.product, findall, false);
|
|
||||||
if (!findall) {
|
|
||||||
[%# save sel for the next invocation of selectProduct() %]
|
|
||||||
var tmp = sel;
|
|
||||||
|
|
||||||
[%# this is an optimization: if we have just added products to an
|
|
||||||
existing selection, no need to clear the form controls and add
|
|
||||||
everybody again; just merge the new ones with the existing
|
|
||||||
options. %]
|
|
||||||
if ((last_sel.length > 0) && (last_sel.length < sel.length)) {
|
|
||||||
sel = fake_diff_array(sel, last_sel);
|
|
||||||
merging = true;
|
|
||||||
}
|
|
||||||
last_sel = tmp;
|
|
||||||
}
|
|
||||||
[%# save original options selected %]
|
|
||||||
var saved_cpts = getSelection(f.component, false, true);
|
|
||||||
var saved_vers = getSelection(f.version, false, true);
|
|
||||||
[% IF Param('usetargetmilestone') %]
|
|
||||||
var saved_tms = getSelection(f.target_milestone, false, true);
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[%# do the actual fill/update, reselect originally selected options %]
|
|
||||||
updateSelect(cpts, sel, f.component, merging);
|
|
||||||
restoreSelection(f.component, saved_cpts);
|
|
||||||
updateSelect(vers, sel, f.version, merging);
|
|
||||||
restoreSelection(f.version, saved_vers);
|
|
||||||
[% IF Param('usetargetmilestone') %]
|
|
||||||
updateSelect(tms, sel, f.target_milestone, merging);
|
|
||||||
restoreSelection(f.target_milestone, saved_tms);
|
|
||||||
[% END %]
|
|
||||||
}
|
|
||||||
|
|
||||||
// -->
|
|
||||||
</script>
|
|
||||||
|
|
||||||
[% query_variants = [
|
|
||||||
{ value => "allwordssubstr", description => "contains all of the words/strings" },
|
|
||||||
{ value => "anywordssubstr", description => "contains any of the words/strings" },
|
|
||||||
{ value => "substring", description => "contains the string" },
|
|
||||||
{ value => "casesubstring", description => "contains the string (exact case)" },
|
|
||||||
{ value => "allwords", description => "contains all of the words" },
|
|
||||||
{ value => "anywords", description => "contains any of the words" },
|
|
||||||
{ value => "regexp", description => "matches the regexp" },
|
|
||||||
{ value => "notregexp", description => "doesn’t match the regexp" } ] %]
|
|
||||||
|
|
||||||
<form method="get" action="buglist.cgi" name="queryform">
|
|
||||||
|
|
||||||
[%# *** Summary *** %]
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th align="right">Summary:</th>
|
|
||||||
<td>
|
|
||||||
<select name="short_desc_type">
|
|
||||||
[% FOREACH qv = query_variants %]
|
|
||||||
<option value="[% qv.value %]"
|
|
||||||
[% " selected" IF default.short_desc_type.0 == qv.value %]>[% qv.description %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input name="short_desc" size="40" value="[% default.short_desc.0 FILTER html %]">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="submit" value="Search">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
[%# *** Product Component Version Target *** %]
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td colspan="4">
|
|
||||||
<table>
|
|
||||||
<tr valign="bottom">
|
|
||||||
<th align="left">Product:</th>
|
|
||||||
<th align="left"><a href="describecomponents.cgi">Component</a>:</th>
|
|
||||||
<th align="left">Version:</th>
|
|
||||||
|
|
||||||
[% IF (Param("usetargetmilestone")) %]
|
|
||||||
<th align="left">Target:</th>
|
|
||||||
[% END %]
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr valign="top">
|
|
||||||
|
|
||||||
[%# Can't use the select block here because of onChange and the fact that
|
|
||||||
'component' is a toolkit reserved word - we use 'component_' instead. %]
|
|
||||||
<td align="left">
|
|
||||||
<select name="product" multiple size="5" onChange="selectProduct(this.form);">
|
|
||||||
[% FOREACH p = product %]
|
|
||||||
<option value="[% p FILTER html %]"
|
|
||||||
[% " selected" IF lsearch(default.product, p) != -1 %]>
|
|
||||||
[% p FILTER html %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td align="left">
|
|
||||||
<select name="component" 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>
|
|
||||||
|
|
||||||
[% PROCESS select sel = { name => 'version', size => 5 } %]
|
|
||||||
|
|
||||||
[% IF Param('usetargetmilestone') && target_milestone.size > 0 %]
|
|
||||||
[% PROCESS select sel = { name => 'target_milestone', size => 5 } %]
|
|
||||||
[% END %]
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
[%# *** Comment URL Whiteboard Keywords *** %]
|
|
||||||
|
|
||||||
[% FOREACH field = [
|
|
||||||
{ name => "long_desc", description => "A comment" },
|
|
||||||
{ name => "bug_file_loc", description => "The URL" },
|
|
||||||
{ name => "status_whiteboard", description => "Whiteboard" } ] %]
|
|
||||||
|
|
||||||
[% UNLESS field.name == 'status_whiteboard' AND NOT Param('usestatuswhiteboard') %]
|
|
||||||
<tr>
|
|
||||||
<th align="right">[% field.description %]:</th>
|
|
||||||
<td>
|
|
||||||
<select name="[% field.name %]_type">
|
|
||||||
[% FOREACH qv = query_variants %]
|
|
||||||
[% type = "${field.name}_type" %]
|
|
||||||
<option value="[% qv.value %]"
|
|
||||||
[% " selected" IF default.$type.0 == qv.value %]>[% qv.description %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td><input name="[% field.name %]" size="40" value="
|
|
||||||
[% default.${field.name}.0 FILTER html %]">
|
|
||||||
</td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
[% END %]
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[% IF have_keywords %]
|
|
||||||
<tr>
|
|
||||||
<th align="right"><a href="describekeywords.cgi">Keywords</a>:</th>
|
|
||||||
<td>
|
|
||||||
<select name="keywords_type">
|
|
||||||
[% FOREACH qv = [
|
|
||||||
{ name => "anywords", description => "contains any of the keywords" },
|
|
||||||
{ name => "allwords", description => "contains all of the keywords" },
|
|
||||||
{ name => "nowords", description => "contains none of the keywords" } ] %]
|
|
||||||
|
|
||||||
<option value="[% qv.name %]"
|
|
||||||
[% " selected" IF default.keywords_type.0 == qv.name %]>
|
|
||||||
[% qv.description %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input name="keywords" size="40" value="[% default.keywords.0 FILTER html %]">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
[% END %]
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
[%# *** Status Resolution Severity Priority Hardware OS *** %]
|
[% PROCESS "search/boolean-charts.html.tmpl" %]
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#status">Status</a>:</th>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#resolution">Resolution</a>:</th>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#severity">Severity</a>:</th>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#priority">Priority</a>:</th>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#platform">Hardware</a>:</th>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#opsys">OS</a>:</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr valign="top">
|
|
||||||
[% PROCESS select sel = { name => 'bug_status', size => 7 } %]
|
|
||||||
[% PROCESS select sel = { name => 'resolution', size => 7 } %]
|
|
||||||
[% PROCESS select sel = { name => 'bug_severity', size => 7 } %]
|
|
||||||
[% PROCESS select sel = { name => 'priority', size => 7 } %]
|
|
||||||
[% PROCESS select sel = { name => 'rep_platform', size => 7 } %]
|
|
||||||
[% PROCESS select sel = { name => 'op_sys', size => 7 } %]
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
Give me a <a href="queryhelp.cgi">clue</a> about how to use this form.
|
||||||
|
</p>
|
||||||
|
|
||||||
[%# *** Email Numbering Votes *** %]
|
</form>
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<fieldset>
|
|
||||||
<legend>
|
|
||||||
<strong>
|
|
||||||
<a href="queryhelp.cgi#peopleinvolved">Email</a> and Numbering
|
|
||||||
</strong>
|
|
||||||
</legend>
|
|
||||||
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
[% FOREACH n = [1, 2] %]
|
|
||||||
<td>
|
|
||||||
|
|
||||||
|
|
||||||
<table cellspacing="0" cellpadding="0">
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
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 %]">
|
|
||||||
bug owner
|
|
||||||
</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 %]">
|
|
||||||
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 %]">
|
|
||||||
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 %]">
|
|
||||||
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 %]">
|
|
||||||
commenter
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<select name="emailtype[% n %]">
|
|
||||||
[% FOREACH qv = [
|
|
||||||
{ name => "substring", description => "contains" },
|
|
||||||
{ name => "exact", description => "is" },
|
|
||||||
{ 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="20" value="[% default.email.$n FILTER html %]">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
[% END %]
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<select name="bugidtype">
|
|
||||||
<option value="include"[% " selected" IF default.bugidtype.0 == "include" %]>Only include</option>
|
|
||||||
<option value="exclude"[% " selected" IF default.bugidtype.0 == "exclude" %]>Exclude</option>
|
|
||||||
</select>
|
|
||||||
bugs numbered:
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="bug_id" value="[% default.bug_id.0 FILTER html %]" size="20">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td></td>
|
|
||||||
<td>(comma-separated list)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="right">
|
|
||||||
Only bugs with at least:
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input name="votes" size="3" value="[% default.votes.0 FILTER html %]"> votes
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
</fieldset>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
[%# *** Bug Changes *** %]
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<fieldset>
|
|
||||||
<legend><strong>Bug Changes</strong></legend>
|
|
||||||
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>Only bugs changed in the last </dt>
|
|
||||||
<dd><input name=changedin size=3 value="[% default.changedin.0 FILTER html %]"> days</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>Only bugs where any of the fields</dt>
|
|
||||||
<dd>
|
|
||||||
<select name="chfield" multiple size="4">
|
|
||||||
[% FOREACH field = chfield %]
|
|
||||||
<option value="[% field FILTER html %]"
|
|
||||||
[% " selected" IF lsearch(default.chfield, field) != -1 %]>
|
|
||||||
[% field FILTER html %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>were changed between</dt>
|
|
||||||
<dd>
|
|
||||||
<input name="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)
|
|
||||||
</dd>
|
|
||||||
<dt>to this value: (optional)</dt>
|
|
||||||
<dd>
|
|
||||||
<input name="chfieldvalue" size="20" value="[% default.chfieldvalue.0 FILTER html %]">
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
</fieldset>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
[%# *** Action Selection *** %]
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td colspan="2">
|
|
||||||
|
|
||||||
[% IF NOT userid %]
|
|
||||||
<input type="hidden" name="cmdtype" value="doit">
|
|
||||||
[% ELSE %]
|
|
||||||
<br>
|
|
||||||
<input type="radio" name="cmdtype" value="doit" checked> Run this query
|
|
||||||
<br>
|
|
||||||
|
|
||||||
[% IF namedqueries.size > 0 %]
|
|
||||||
<p>
|
|
||||||
<table cellspacing="0" cellpadding="0">
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<input type="radio" name="cmdtype" value="editnamed">
|
|
||||||
Load my remembered query:
|
|
||||||
</td>
|
|
||||||
<td rowspan="3">
|
|
||||||
<select name="namedcmd">
|
|
||||||
[% FOREACH query = namedqueries %]
|
|
||||||
<option value="[% query FILTER html %]">[% query FILTER html %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<input type="radio" name="cmdtype" value="runnamed">
|
|
||||||
Run my remembered query:
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<input type="radio" name="cmdtype" value="forgetnamed">
|
|
||||||
Forget my remembered query:
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</p>
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
<input type="radio" name="cmdtype" value="asdefault">
|
|
||||||
Remember this as my default query
|
|
||||||
<br>
|
|
||||||
<input type="radio" name="cmdtype" value="asnamed">
|
|
||||||
Remember this query, and name it:
|
|
||||||
<input type="text" name="newqueryname">
|
|
||||||
<br> <input type="checkbox" name="tofooter" value="1">
|
|
||||||
and put it in my page footer
|
|
||||||
<br>
|
|
||||||
[% END %]
|
|
||||||
<br>
|
|
||||||
<div>
|
|
||||||
Sort results by:
|
|
||||||
<select name="order">
|
|
||||||
[% FOREACH order = orders %]
|
|
||||||
<option value="[% order FILTER html %]"
|
|
||||||
[% " selected" IF default.order.0 == order %]>[% order FILTER html %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<input type="submit" value="Search">
|
|
||||||
[% IF userdefaultquery %]
|
|
||||||
<p>
|
|
||||||
<a href="query.cgi?nukedefaultquery=1">
|
|
||||||
Set my default query back to the system default</a>
|
|
||||||
</p>
|
|
||||||
[% END %]
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
[%# *** Boolean Charts *** %]
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
[% types = [
|
|
||||||
{ name => "noop", description => "---" },
|
|
||||||
{ name => "equals", description => "is equal to" },
|
|
||||||
{ name => "notequals", description => "is not equal to" },
|
|
||||||
{ name => "substring", description => "contains the string" },
|
|
||||||
{ name => "casesubstring", description => "contains the string (exact case)" },
|
|
||||||
{ name => "notsubstring", description => "does not contain the string" },
|
|
||||||
{ name => "allwordssubstr", description => "contains all of the strings" },
|
|
||||||
{ name => "anywordssubstr", description => "contains any of the strings" },
|
|
||||||
{ name => "regexp", description => "contains regexp" },
|
|
||||||
{ name => "notregexp", description => "does not contain regexp" },
|
|
||||||
{ name => "lessthan", description => "is less than" },
|
|
||||||
{ name => "greaterthan", description => "is greater than" },
|
|
||||||
{ name => "anywords", description => "contains any of the words" },
|
|
||||||
{ name => "allwords", description => "contains all of the words" },
|
|
||||||
{ name => "nowords", description => "contains none of the words" },
|
|
||||||
{ name => "changedbefore", description => "changed before" },
|
|
||||||
{ name => "changedafter", description => "changed after" },
|
|
||||||
{ name => "changedfrom", description => "changed from" },
|
|
||||||
{ name => "changedto", description => "changed to" },
|
|
||||||
{ name => "changedby", description => "changed by" } ] %]
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<strong>
|
|
||||||
<a name="chart" href="queryhelp.cgi#advancedquerying">
|
|
||||||
Advanced Querying Using Boolean Charts</a>:
|
|
||||||
</strong>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
[%# Whoever wrote the original version of boolean charts had a seriously twisted mind %]
|
|
||||||
|
|
||||||
[% jsmagic = "onclick=\"document.forms[0].action='query.cgi#chart'; document.forms[0].method='POST'; return 1;\"" %]
|
|
||||||
|
|
||||||
[% FOREACH chart = default.charts %]
|
|
||||||
[% chartnum = loop.count - 1 %]
|
|
||||||
<table>
|
|
||||||
[% FOREACH row = chart %]
|
|
||||||
[% rownum = loop.count - 1 %]
|
|
||||||
<tr>
|
|
||||||
[% FOREACH col = row %]
|
|
||||||
[% colnum = loop.count - 1 %]
|
|
||||||
<td>
|
|
||||||
<select name="[% "field${chartnum}-${rownum}-${colnum}" %]">
|
|
||||||
[% FOREACH field = fields %]
|
|
||||||
<option value="[% field.name %]"
|
|
||||||
[%- " selected" IF field.name == col.field %]>[% field.description %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select name="[% "type${chartnum}-${rownum}-${colnum}" %]">
|
|
||||||
[% FOREACH type = types %]
|
|
||||||
<option value="[% type.name %]"
|
|
||||||
[%- " selected" IF type.name == col.type %]>[% type.description %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<input name="[% "value${chartnum}-${rownum}-${colnum}" %]"
|
|
||||||
value="[% col.value FILTER html %]">
|
|
||||||
</td>
|
|
||||||
|
|
||||||
[% IF NOT col == row.last %]
|
|
||||||
<td align="center">
|
|
||||||
Or
|
|
||||||
</td>
|
|
||||||
[% ELSE %]
|
|
||||||
<td>
|
|
||||||
[% newor = colnum + 1 %]
|
|
||||||
<input type="submit" value="Or"
|
|
||||||
name="cmd-add[% "${chartnum}-${rownum}-${newor}" %]" [% $jsmagic %]>
|
|
||||||
</td>
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[% END %]
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
[% IF NOT row == chart.last %]
|
|
||||||
<tr>
|
|
||||||
<td>And</td>
|
|
||||||
</tr>
|
|
||||||
[% ELSE %]
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
[% newand = rownum + 1; newchart = chartnum + 1 %]
|
|
||||||
<input type="submit" value="And"
|
|
||||||
name="cmd-add[% "${chartnum}-${newand}-0" %]"[% $jsmagic %]>
|
|
||||||
|
|
||||||
<input type="submit" value="Add another boolean chart"
|
|
||||||
name="cmd-add[% newchart %]-0-0" [% $jsmagic %]>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[% END %]
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
<p>Give me a <a href="queryhelp.cgi">clue</a> about how to use this form.</p>
|
|
||||||
|
|
||||||
</FORM>
|
|
||||||
|
|
||||||
[% PROCESS global/footer.html.tmpl %]
|
[% PROCESS global/footer.html.tmpl %]
|
||||||
|
|
||||||
[%############################################################################%]
|
|
||||||
[%# Block for SELECT fields #%]
|
|
||||||
[%############################################################################%]
|
|
||||||
|
|
||||||
[% BLOCK select %]
|
|
||||||
<td align="left">
|
|
||||||
<select name="[% sel.name %]" multiple size="[% sel.size %]">
|
|
||||||
[% FOREACH name = ${sel.name} %]
|
|
||||||
<option value="[% name FILTER html %]"
|
|
||||||
[% " selected" IF lsearch(default.${sel.name}, name) != -1 %]>
|
|
||||||
[% name FILTER html %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
[% END %]
|
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||||
# Rights Reserved.
|
# Rights Reserved.
|
||||||
#
|
#
|
||||||
# Contributor(s): Chris Lahey <clahey@ximian.com> [javascript fixes]
|
# Contributor(s): Gervase Markham <gerv@gerv.net>
|
||||||
# Christian Reis <kiko@async.com.br> [javascript rewrite]
|
|
||||||
# Gervase Markham <gerv@gerv.net>
|
|
||||||
#%]
|
#%]
|
||||||
|
|
||||||
[% PROCESS global/header.html.tmpl
|
[% PROCESS global/header.html.tmpl
|
||||||
|
@ -26,833 +24,20 @@
|
||||||
extra = " onLoad=\"selectProduct(document.forms['queryform']);\""
|
extra = " onLoad=\"selectProduct(document.forms['queryform']);\""
|
||||||
%]
|
%]
|
||||||
|
|
||||||
[%# Note: use Template comments and not JS ones here, to avoid bloating
|
[% button_name = "Search" %]
|
||||||
what we actually send to the browser %]
|
|
||||||
|
|
||||||
<script language="JavaScript" type="text/javascript"> <!--
|
[% PROCESS search/form.html.tmpl %]
|
||||||
|
|
||||||
var first_load = true; [%# is this the first time we load the page? %]
|
[% PROCESS search/knob.html.tmpl %]
|
||||||
var last_sel = new Array(); [%# caches last selection %]
|
|
||||||
|
|
||||||
var cpts = new Array();
|
|
||||||
var vers = new Array();
|
|
||||||
[% IF Param('usetargetmilestone') %]
|
|
||||||
var tms = new Array();
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[%# Create three arrays of components, versions and target milestones, indexed
|
|
||||||
# numerically according to the product they refer to. #%]
|
|
||||||
|
|
||||||
[% n = 0 %]
|
|
||||||
[% FOREACH p = product %]
|
|
||||||
cpts[[% n %]] = [
|
|
||||||
[%- FOREACH item = componentsbyproduct.$p %]'[% item FILTER js %]', [%- END -%]];
|
|
||||||
vers[[% n %]] = [
|
|
||||||
[%- FOREACH item = versionsbyproduct.$p -%]'[% item FILTER js %]', [%- END -%]];
|
|
||||||
[% IF Param('usetargetmilestone') %]
|
|
||||||
tms[[% n %]] = [
|
|
||||||
[%- FOREACH item = milestonesbyproduct.$p %]'[% item FILTER js %]', [%- END -%]];
|
|
||||||
[% END %]
|
|
||||||
[% n = n+1 %]
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[%# updateSelect(array, sel, target, merging)
|
|
||||||
#
|
|
||||||
# Adds to the target select object all elements in array that
|
|
||||||
# correspond to the elements selected in source.
|
|
||||||
# - array should be a array of arrays, indexed by number. the
|
|
||||||
# array should contain the elements that correspond to that
|
|
||||||
# product.
|
|
||||||
# - sel is a list of selected items, either whole or a diff
|
|
||||||
# depending on merging.
|
|
||||||
# - target should be the target select object.
|
|
||||||
# - merging (boolean) determines if we are mergine in a diff or
|
|
||||||
# substituting the whole selection. a diff is used to optimize adding
|
|
||||||
# selections.
|
|
||||||
#
|
|
||||||
# Example (compsel is a select form control)
|
|
||||||
#
|
|
||||||
# var components = Array();
|
|
||||||
# components[1] = [ 'ComponentA', 'ComponentB' ];
|
|
||||||
# components[2] = [ 'ComponentC', 'ComponentD' ];
|
|
||||||
# source = [ 2 ];
|
|
||||||
# updateSelect(components, source, compsel, 0, 0);
|
|
||||||
#
|
|
||||||
# would clear compsel and add 'ComponentC' and 'ComponentD' to it.
|
|
||||||
#
|
|
||||||
%]
|
|
||||||
|
|
||||||
function updateSelect(array, sel, target, merging) {
|
|
||||||
|
|
||||||
var i, item;
|
|
||||||
|
|
||||||
[%# If we have no versions/components/milestones %]
|
|
||||||
if (array.length < 1) {
|
|
||||||
target.options.length = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (merging) {
|
|
||||||
[%# array merging/sorting in the case of multiple selections %]
|
|
||||||
[%# merge in the current options with the first selection %]
|
|
||||||
item = merge_arrays(array[sel[0]], target.options, 1);
|
|
||||||
|
|
||||||
[%# merge the rest of the selection with the results %]
|
|
||||||
for (i = 1 ; i < sel.length ; i++) {
|
|
||||||
item = merge_arrays(array[sel[i]], item, 0);
|
|
||||||
}
|
|
||||||
} else if ( sel.length > 1 ) {
|
|
||||||
[%# here we micro-optimize for two arrays to avoid merging with a
|
|
||||||
null array %]
|
|
||||||
item = merge_arrays(array[sel[0]],array[sel[1]], 0);
|
|
||||||
|
|
||||||
[%# merge the arrays. not very good for multiple selections. %]
|
|
||||||
for (i = 2; i < sel.length; i++) {
|
|
||||||
item = merge_arrays(item, array[sel[i]], 0);
|
|
||||||
}
|
|
||||||
} else { [%# single item in selection, just get me the list %]
|
|
||||||
item = array[sel[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# clear select %]
|
|
||||||
target.options.length = 0;
|
|
||||||
|
|
||||||
[%# load elements of list into select %]
|
|
||||||
for (i = 0; i < item.length; i++) {
|
|
||||||
target.options[i] = new Option(item[i], item[i]);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# Returns elements in a that are not in b.
|
|
||||||
# NOT A REAL DIFF: does not check the reverse.
|
|
||||||
# - a,b: arrays of values to be compare. %]
|
|
||||||
function fake_diff_array(a, b) {
|
|
||||||
var newsel = new Array();
|
|
||||||
var found = false;
|
|
||||||
|
|
||||||
[%# do a boring array diff to see who's new %]
|
|
||||||
for (var ia in a) {
|
|
||||||
for (var ib in b) {
|
|
||||||
if (a[ia] == b[ib]) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
newsel[newsel.length] = a[ia];
|
|
||||||
}
|
|
||||||
found = false;
|
|
||||||
}
|
|
||||||
return newsel;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# takes two arrays and sorts them by string, returning a new, sorted
|
|
||||||
# array. the merge removes dupes, too.
|
|
||||||
# - a, b: arrays to be merge.
|
|
||||||
# - b_is_select: if true, then b is actually an optionitem and as
|
|
||||||
# such we need to use item.value on it. %]
|
|
||||||
function merge_arrays(a, b, b_is_select) {
|
|
||||||
var pos_a = 0;
|
|
||||||
var pos_b = 0;
|
|
||||||
var ret = new Array();
|
|
||||||
var bitem, aitem;
|
|
||||||
|
|
||||||
[%# iterate through both arrays and add the larger item to the return
|
|
||||||
list. remove dupes, too. Use toLowerCase to provide
|
|
||||||
case-insensitivity. %]
|
|
||||||
while ((pos_a < a.length) && (pos_b < b.length)) {
|
|
||||||
if (b_is_select) {
|
|
||||||
bitem = b[pos_b].value;
|
|
||||||
} else {
|
|
||||||
bitem = b[pos_b];
|
|
||||||
}
|
|
||||||
aitem = a[pos_a];
|
|
||||||
|
|
||||||
[%# smaller item in list a %]
|
|
||||||
if (aitem.toLowerCase() < bitem.toLowerCase()) {
|
|
||||||
ret[ret.length] = aitem;
|
|
||||||
pos_a++;
|
|
||||||
} else {
|
|
||||||
[%# smaller item in list b %]
|
|
||||||
if (aitem.toLowerCase() > bitem.toLowerCase()) {
|
|
||||||
ret[ret.length] = bitem;
|
|
||||||
pos_b++;
|
|
||||||
} else {
|
|
||||||
[%# list contents are equal, inc both counters. %]
|
|
||||||
ret[ret.length] = aitem;
|
|
||||||
pos_a++;
|
|
||||||
pos_b++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# catch leftovers here. these sections are ugly code-copying. %]
|
|
||||||
if (pos_a < a.length) {
|
|
||||||
for (; pos_a < a.length ; pos_a++) {
|
|
||||||
ret[ret.length] = a[pos_a];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos_b < b.length) {
|
|
||||||
for (; pos_b < b.length; pos_b++) {
|
|
||||||
if (b_is_select) {
|
|
||||||
bitem = b[pos_b].value;
|
|
||||||
} else {
|
|
||||||
bitem = b[pos_b];
|
|
||||||
}
|
|
||||||
ret[ret.length] = bitem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# Returns an array of indexes or values from a select form control.
|
|
||||||
# - control: select control from which to find selections
|
|
||||||
# - findall: boolean, store all options when true or just the selected
|
|
||||||
# indexes
|
|
||||||
# - want_values: boolean; we store values when true and indexes when
|
|
||||||
# false %]
|
|
||||||
function getSelection(control, findall, want_values) {
|
|
||||||
var ret = new Array();
|
|
||||||
|
|
||||||
if ((!findall) && (control.selectedIndex == -1)) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i=0; i<control.length; i++) {
|
|
||||||
if (findall || control.options[i].selected) {
|
|
||||||
ret[ret.length] = want_values ? control.options[i].value : i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# Selects items in control that have index defined in sel
|
|
||||||
# - control: SELECT control to be restored
|
|
||||||
# - selnames: array of indexes in select form control %]
|
|
||||||
function restoreSelection(control, selnames) {
|
|
||||||
[%# right. this sucks. but I see no way to avoid going through the
|
|
||||||
# list and comparing to the contents of the control. %]
|
|
||||||
for (var j=0; j < selnames.length; j++) {
|
|
||||||
for (var i=0; i < control.options.length; i++) {
|
|
||||||
if (control.options[i].value == selnames[j]) {
|
|
||||||
control.options[i].selected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# selectProduct reads the selection from f.product and updates
|
|
||||||
# f.version, component and target_milestone accordingly.
|
|
||||||
# - f: a form containing product, component, varsion and
|
|
||||||
# target_milestone select boxes.
|
|
||||||
# globals (3vil!):
|
|
||||||
# - cpts, vers, tms: array of arrays, indexed by product name. the
|
|
||||||
# subarrays contain a list of names to be fed to the respective
|
|
||||||
# selectboxes. For bugzilla, these are generated with perl code
|
|
||||||
# at page start.
|
|
||||||
# - first_load: boolean, specifying if it is the first time we load
|
|
||||||
# the query page.
|
|
||||||
# - last_sel: saves our last selection list so we know what has
|
|
||||||
# changed, and optimize for additions. %]
|
|
||||||
function selectProduct(f) {
|
|
||||||
[%# this is to avoid handling events that occur before the form
|
|
||||||
itself is ready, which could happen in buggy browsers. %]
|
|
||||||
if ((!f) || (!f.product)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# if this is the first load and nothing is selected, no need to
|
|
||||||
merge and sort all components; perl gives it to us sorted. %]
|
|
||||||
if ((first_load) && (f.product.selectedIndex == -1)) {
|
|
||||||
first_load = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[%# turn first_load off. this is tricky, since it seems to be
|
|
||||||
redundant with the above clause. It's not: if when we first load
|
|
||||||
the page there is _one_ element selected, it won't fall into that
|
|
||||||
clause, and first_load will remain 1. Then, if we unselect that
|
|
||||||
item, selectProduct will be called but the clause will be valid
|
|
||||||
(since selectedIndex == -1), and we will return - incorrectly -
|
|
||||||
without merge/sorting. %]
|
|
||||||
first_load = false;
|
|
||||||
|
|
||||||
[%# - sel keeps the array of products we are selected.
|
|
||||||
- merging says if it is a full list or just a list of products that
|
|
||||||
were added to the current selection. %]
|
|
||||||
var merging = false;
|
|
||||||
var sel = Array();
|
|
||||||
|
|
||||||
[%# if nothing selected, pick all %]
|
|
||||||
var findall = f.product.selectedIndex == -1;
|
|
||||||
sel = getSelection(f.product, findall, false);
|
|
||||||
if (!findall) {
|
|
||||||
[%# save sel for the next invocation of selectProduct() %]
|
|
||||||
var tmp = sel;
|
|
||||||
|
|
||||||
[%# this is an optimization: if we have just added products to an
|
|
||||||
existing selection, no need to clear the form controls and add
|
|
||||||
everybody again; just merge the new ones with the existing
|
|
||||||
options. %]
|
|
||||||
if ((last_sel.length > 0) && (last_sel.length < sel.length)) {
|
|
||||||
sel = fake_diff_array(sel, last_sel);
|
|
||||||
merging = true;
|
|
||||||
}
|
|
||||||
last_sel = tmp;
|
|
||||||
}
|
|
||||||
[%# save original options selected %]
|
|
||||||
var saved_cpts = getSelection(f.component, false, true);
|
|
||||||
var saved_vers = getSelection(f.version, false, true);
|
|
||||||
[% IF Param('usetargetmilestone') %]
|
|
||||||
var saved_tms = getSelection(f.target_milestone, false, true);
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[%# do the actual fill/update, reselect originally selected options %]
|
|
||||||
updateSelect(cpts, sel, f.component, merging);
|
|
||||||
restoreSelection(f.component, saved_cpts);
|
|
||||||
updateSelect(vers, sel, f.version, merging);
|
|
||||||
restoreSelection(f.version, saved_vers);
|
|
||||||
[% IF Param('usetargetmilestone') %]
|
|
||||||
updateSelect(tms, sel, f.target_milestone, merging);
|
|
||||||
restoreSelection(f.target_milestone, saved_tms);
|
|
||||||
[% END %]
|
|
||||||
}
|
|
||||||
|
|
||||||
// -->
|
|
||||||
</script>
|
|
||||||
|
|
||||||
[% query_variants = [
|
|
||||||
{ value => "allwordssubstr", description => "contains all of the words/strings" },
|
|
||||||
{ value => "anywordssubstr", description => "contains any of the words/strings" },
|
|
||||||
{ value => "substring", description => "contains the string" },
|
|
||||||
{ value => "casesubstring", description => "contains the string (exact case)" },
|
|
||||||
{ value => "allwords", description => "contains all of the words" },
|
|
||||||
{ value => "anywords", description => "contains any of the words" },
|
|
||||||
{ value => "regexp", description => "matches the regexp" },
|
|
||||||
{ value => "notregexp", description => "doesn’t match the regexp" } ] %]
|
|
||||||
|
|
||||||
<form method="get" action="buglist.cgi" name="queryform">
|
|
||||||
|
|
||||||
[%# *** Summary *** %]
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th align="right">Summary:</th>
|
|
||||||
<td>
|
|
||||||
<select name="short_desc_type">
|
|
||||||
[% FOREACH qv = query_variants %]
|
|
||||||
<option value="[% qv.value %]"
|
|
||||||
[% " selected" IF default.short_desc_type.0 == qv.value %]>[% qv.description %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input name="short_desc" size="40" value="[% default.short_desc.0 FILTER html %]">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="submit" value="Search">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
[%# *** Product Component Version Target *** %]
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td colspan="4">
|
|
||||||
<table>
|
|
||||||
<tr valign="bottom">
|
|
||||||
<th align="left">Product:</th>
|
|
||||||
<th align="left"><a href="describecomponents.cgi">Component</a>:</th>
|
|
||||||
<th align="left">Version:</th>
|
|
||||||
|
|
||||||
[% IF (Param("usetargetmilestone")) %]
|
|
||||||
<th align="left">Target:</th>
|
|
||||||
[% END %]
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr valign="top">
|
|
||||||
|
|
||||||
[%# Can't use the select block here because of onChange and the fact that
|
|
||||||
'component' is a toolkit reserved word - we use 'component_' instead. %]
|
|
||||||
<td align="left">
|
|
||||||
<select name="product" multiple size="5" onChange="selectProduct(this.form);">
|
|
||||||
[% FOREACH p = product %]
|
|
||||||
<option value="[% p FILTER html %]"
|
|
||||||
[% " selected" IF lsearch(default.product, p) != -1 %]>
|
|
||||||
[% p FILTER html %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td align="left">
|
|
||||||
<select name="component" 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>
|
|
||||||
|
|
||||||
[% PROCESS select sel = { name => 'version', size => 5 } %]
|
|
||||||
|
|
||||||
[% IF Param('usetargetmilestone') && target_milestone.size > 0 %]
|
|
||||||
[% PROCESS select sel = { name => 'target_milestone', size => 5 } %]
|
|
||||||
[% END %]
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
[%# *** Comment URL Whiteboard Keywords *** %]
|
|
||||||
|
|
||||||
[% FOREACH field = [
|
|
||||||
{ name => "long_desc", description => "A comment" },
|
|
||||||
{ name => "bug_file_loc", description => "The URL" },
|
|
||||||
{ name => "status_whiteboard", description => "Whiteboard" } ] %]
|
|
||||||
|
|
||||||
[% UNLESS field.name == 'status_whiteboard' AND NOT Param('usestatuswhiteboard') %]
|
|
||||||
<tr>
|
|
||||||
<th align="right">[% field.description %]:</th>
|
|
||||||
<td>
|
|
||||||
<select name="[% field.name %]_type">
|
|
||||||
[% FOREACH qv = query_variants %]
|
|
||||||
[% type = "${field.name}_type" %]
|
|
||||||
<option value="[% qv.value %]"
|
|
||||||
[% " selected" IF default.$type.0 == qv.value %]>[% qv.description %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td><input name="[% field.name %]" size="40" value="
|
|
||||||
[% default.${field.name}.0 FILTER html %]">
|
|
||||||
</td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
[% END %]
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[% IF have_keywords %]
|
|
||||||
<tr>
|
|
||||||
<th align="right"><a href="describekeywords.cgi">Keywords</a>:</th>
|
|
||||||
<td>
|
|
||||||
<select name="keywords_type">
|
|
||||||
[% FOREACH qv = [
|
|
||||||
{ name => "anywords", description => "contains any of the keywords" },
|
|
||||||
{ name => "allwords", description => "contains all of the keywords" },
|
|
||||||
{ name => "nowords", description => "contains none of the keywords" } ] %]
|
|
||||||
|
|
||||||
<option value="[% qv.name %]"
|
|
||||||
[% " selected" IF default.keywords_type.0 == qv.name %]>
|
|
||||||
[% qv.description %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input name="keywords" size="40" value="[% default.keywords.0 FILTER html %]">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
[% END %]
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
[%# *** Status Resolution Severity Priority Hardware OS *** %]
|
[% PROCESS "search/boolean-charts.html.tmpl" %]
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#status">Status</a>:</th>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#resolution">Resolution</a>:</th>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#severity">Severity</a>:</th>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#priority">Priority</a>:</th>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#platform">Hardware</a>:</th>
|
|
||||||
<th align="left"><a href="queryhelp.cgi#opsys">OS</a>:</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr valign="top">
|
|
||||||
[% PROCESS select sel = { name => 'bug_status', size => 7 } %]
|
|
||||||
[% PROCESS select sel = { name => 'resolution', size => 7 } %]
|
|
||||||
[% PROCESS select sel = { name => 'bug_severity', size => 7 } %]
|
|
||||||
[% PROCESS select sel = { name => 'priority', size => 7 } %]
|
|
||||||
[% PROCESS select sel = { name => 'rep_platform', size => 7 } %]
|
|
||||||
[% PROCESS select sel = { name => 'op_sys', size => 7 } %]
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
Give me a <a href="queryhelp.cgi">clue</a> about how to use this form.
|
||||||
|
</p>
|
||||||
|
|
||||||
[%# *** Email Numbering Votes *** %]
|
</form>
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<fieldset>
|
|
||||||
<legend>
|
|
||||||
<strong>
|
|
||||||
<a href="queryhelp.cgi#peopleinvolved">Email</a> and Numbering
|
|
||||||
</strong>
|
|
||||||
</legend>
|
|
||||||
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
[% FOREACH n = [1, 2] %]
|
|
||||||
<td>
|
|
||||||
|
|
||||||
|
|
||||||
<table cellspacing="0" cellpadding="0">
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
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 %]">
|
|
||||||
bug owner
|
|
||||||
</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 %]">
|
|
||||||
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 %]">
|
|
||||||
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 %]">
|
|
||||||
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 %]">
|
|
||||||
commenter
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<select name="emailtype[% n %]">
|
|
||||||
[% FOREACH qv = [
|
|
||||||
{ name => "substring", description => "contains" },
|
|
||||||
{ name => "exact", description => "is" },
|
|
||||||
{ 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="20" value="[% default.email.$n FILTER html %]">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
[% END %]
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<select name="bugidtype">
|
|
||||||
<option value="include"[% " selected" IF default.bugidtype.0 == "include" %]>Only include</option>
|
|
||||||
<option value="exclude"[% " selected" IF default.bugidtype.0 == "exclude" %]>Exclude</option>
|
|
||||||
</select>
|
|
||||||
bugs numbered:
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="text" name="bug_id" value="[% default.bug_id.0 FILTER html %]" size="20">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td></td>
|
|
||||||
<td>(comma-separated list)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="right">
|
|
||||||
Only bugs with at least:
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input name="votes" size="3" value="[% default.votes.0 FILTER html %]"> votes
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
</fieldset>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
[%# *** Bug Changes *** %]
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<fieldset>
|
|
||||||
<legend><strong>Bug Changes</strong></legend>
|
|
||||||
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>Only bugs changed in the last </dt>
|
|
||||||
<dd><input name=changedin size=3 value="[% default.changedin.0 FILTER html %]"> days</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>Only bugs where any of the fields</dt>
|
|
||||||
<dd>
|
|
||||||
<select name="chfield" multiple size="4">
|
|
||||||
[% FOREACH field = chfield %]
|
|
||||||
<option value="[% field FILTER html %]"
|
|
||||||
[% " selected" IF lsearch(default.chfield, field) != -1 %]>
|
|
||||||
[% field FILTER html %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>were changed between</dt>
|
|
||||||
<dd>
|
|
||||||
<input name="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)
|
|
||||||
</dd>
|
|
||||||
<dt>to this value: (optional)</dt>
|
|
||||||
<dd>
|
|
||||||
<input name="chfieldvalue" size="20" value="[% default.chfieldvalue.0 FILTER html %]">
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
|
|
||||||
</fieldset>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
[%# *** Action Selection *** %]
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td colspan="2">
|
|
||||||
|
|
||||||
[% IF NOT userid %]
|
|
||||||
<input type="hidden" name="cmdtype" value="doit">
|
|
||||||
[% ELSE %]
|
|
||||||
<br>
|
|
||||||
<input type="radio" name="cmdtype" value="doit" checked> Run this query
|
|
||||||
<br>
|
|
||||||
|
|
||||||
[% IF namedqueries.size > 0 %]
|
|
||||||
<p>
|
|
||||||
<table cellspacing="0" cellpadding="0">
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<input type="radio" name="cmdtype" value="editnamed">
|
|
||||||
Load my remembered query:
|
|
||||||
</td>
|
|
||||||
<td rowspan="3">
|
|
||||||
<select name="namedcmd">
|
|
||||||
[% FOREACH query = namedqueries %]
|
|
||||||
<option value="[% query FILTER html %]">[% query FILTER html %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<input type="radio" name="cmdtype" value="runnamed">
|
|
||||||
Run my remembered query:
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<input type="radio" name="cmdtype" value="forgetnamed">
|
|
||||||
Forget my remembered query:
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</p>
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
<input type="radio" name="cmdtype" value="asdefault">
|
|
||||||
Remember this as my default query
|
|
||||||
<br>
|
|
||||||
<input type="radio" name="cmdtype" value="asnamed">
|
|
||||||
Remember this query, and name it:
|
|
||||||
<input type="text" name="newqueryname">
|
|
||||||
<br> <input type="checkbox" name="tofooter" value="1">
|
|
||||||
and put it in my page footer
|
|
||||||
<br>
|
|
||||||
[% END %]
|
|
||||||
<br>
|
|
||||||
<div>
|
|
||||||
Sort results by:
|
|
||||||
<select name="order">
|
|
||||||
[% FOREACH order = orders %]
|
|
||||||
<option value="[% order FILTER html %]"
|
|
||||||
[% " selected" IF default.order.0 == order %]>[% order FILTER html %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<input type="submit" value="Search">
|
|
||||||
[% IF userdefaultquery %]
|
|
||||||
<p>
|
|
||||||
<a href="query.cgi?nukedefaultquery=1">
|
|
||||||
Set my default query back to the system default</a>
|
|
||||||
</p>
|
|
||||||
[% END %]
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
[%# *** Boolean Charts *** %]
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
[% types = [
|
|
||||||
{ name => "noop", description => "---" },
|
|
||||||
{ name => "equals", description => "is equal to" },
|
|
||||||
{ name => "notequals", description => "is not equal to" },
|
|
||||||
{ name => "substring", description => "contains the string" },
|
|
||||||
{ name => "casesubstring", description => "contains the string (exact case)" },
|
|
||||||
{ name => "notsubstring", description => "does not contain the string" },
|
|
||||||
{ name => "allwordssubstr", description => "contains all of the strings" },
|
|
||||||
{ name => "anywordssubstr", description => "contains any of the strings" },
|
|
||||||
{ name => "regexp", description => "contains regexp" },
|
|
||||||
{ name => "notregexp", description => "does not contain regexp" },
|
|
||||||
{ name => "lessthan", description => "is less than" },
|
|
||||||
{ name => "greaterthan", description => "is greater than" },
|
|
||||||
{ name => "anywords", description => "contains any of the words" },
|
|
||||||
{ name => "allwords", description => "contains all of the words" },
|
|
||||||
{ name => "nowords", description => "contains none of the words" },
|
|
||||||
{ name => "changedbefore", description => "changed before" },
|
|
||||||
{ name => "changedafter", description => "changed after" },
|
|
||||||
{ name => "changedfrom", description => "changed from" },
|
|
||||||
{ name => "changedto", description => "changed to" },
|
|
||||||
{ name => "changedby", description => "changed by" } ] %]
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<strong>
|
|
||||||
<a name="chart" href="queryhelp.cgi#advancedquerying">
|
|
||||||
Advanced Querying Using Boolean Charts</a>:
|
|
||||||
</strong>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
[%# Whoever wrote the original version of boolean charts had a seriously twisted mind %]
|
|
||||||
|
|
||||||
[% jsmagic = "onclick=\"document.forms[0].action='query.cgi#chart'; document.forms[0].method='POST'; return 1;\"" %]
|
|
||||||
|
|
||||||
[% FOREACH chart = default.charts %]
|
|
||||||
[% chartnum = loop.count - 1 %]
|
|
||||||
<table>
|
|
||||||
[% FOREACH row = chart %]
|
|
||||||
[% rownum = loop.count - 1 %]
|
|
||||||
<tr>
|
|
||||||
[% FOREACH col = row %]
|
|
||||||
[% colnum = loop.count - 1 %]
|
|
||||||
<td>
|
|
||||||
<select name="[% "field${chartnum}-${rownum}-${colnum}" %]">
|
|
||||||
[% FOREACH field = fields %]
|
|
||||||
<option value="[% field.name %]"
|
|
||||||
[%- " selected" IF field.name == col.field %]>[% field.description %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select name="[% "type${chartnum}-${rownum}-${colnum}" %]">
|
|
||||||
[% FOREACH type = types %]
|
|
||||||
<option value="[% type.name %]"
|
|
||||||
[%- " selected" IF type.name == col.type %]>[% type.description %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<input name="[% "value${chartnum}-${rownum}-${colnum}" %]"
|
|
||||||
value="[% col.value FILTER html %]">
|
|
||||||
</td>
|
|
||||||
|
|
||||||
[% IF NOT col == row.last %]
|
|
||||||
<td align="center">
|
|
||||||
Or
|
|
||||||
</td>
|
|
||||||
[% ELSE %]
|
|
||||||
<td>
|
|
||||||
[% newor = colnum + 1 %]
|
|
||||||
<input type="submit" value="Or"
|
|
||||||
name="cmd-add[% "${chartnum}-${rownum}-${newor}" %]" [% $jsmagic %]>
|
|
||||||
</td>
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[% END %]
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
[% IF NOT row == chart.last %]
|
|
||||||
<tr>
|
|
||||||
<td>And</td>
|
|
||||||
</tr>
|
|
||||||
[% ELSE %]
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
[% newand = rownum + 1; newchart = chartnum + 1 %]
|
|
||||||
<input type="submit" value="And"
|
|
||||||
name="cmd-add[% "${chartnum}-${newand}-0" %]"[% $jsmagic %]>
|
|
||||||
|
|
||||||
<input type="submit" value="Add another boolean chart"
|
|
||||||
name="cmd-add[% newchart %]-0-0" [% $jsmagic %]>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
[% END %]
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
[% END %]
|
|
||||||
|
|
||||||
<p>Give me a <a href="queryhelp.cgi">clue</a> about how to use this form.</p>
|
|
||||||
|
|
||||||
</FORM>
|
|
||||||
|
|
||||||
[% PROCESS global/footer.html.tmpl %]
|
[% PROCESS global/footer.html.tmpl %]
|
||||||
|
|
||||||
[%############################################################################%]
|
|
||||||
[%# Block for SELECT fields #%]
|
|
||||||
[%############################################################################%]
|
|
||||||
|
|
||||||
[% BLOCK select %]
|
|
||||||
<td align="left">
|
|
||||||
<select name="[% sel.name %]" multiple size="[% sel.size %]">
|
|
||||||
[% FOREACH name = ${sel.name} %]
|
|
||||||
<option value="[% name FILTER html %]"
|
|
||||||
[% " selected" IF lsearch(default.${sel.name}, name) != -1 %]>
|
|
||||||
[% name FILTER html %]</option>
|
|
||||||
[% END %]
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
[% END %]
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче