form.html.tmpl 24.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
<!-- 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>
  #%]
23 24 25

[% PROCESS global/variables.none.tmpl %]

26 27 28 29 30 31 32 33 34 35 36 37 38 39
  [%# 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 %]

40
[%# Create three arrays of components, versions and target milestones, indexed
41 42 43 44
  # numerically according to the product they refer to. #%]

[% n = 0 %]
[% FOREACH p = product %]
45
  cpts[[% n %]] = [
46
    [%- FOREACH item = p.components %]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
47
  vers[[% n %]] = [
48
    [%- FOREACH item = p.versions -%]'[%  item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
49
  [% IF Param('usetargetmilestone') %]
50
  tms[[% n %]]  = [
51
     [%- FOREACH item = p.milestones %]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ];
52 53 54 55 56 57 58 59 60 61
  [% 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
62
  #   product.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
  # - 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) {
83

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
    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;
}

124
[%# Returns elements in a that are not in b.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
  # 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
208
  #    - findall: boolean, store all options when true or just the selected
209 210 211
  #      indexes
  #    - want_values: boolean; we store values when true and indexes when
  #      false %]
212
function get_selection(control, findall, want_values) {
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
    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;
    }
268

269 270 271 272 273 274 275 276 277
    [%# 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;

278
    [%# - sel keeps the array of products we are selected.
279 280 281 282 283 284 285
        - 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;
286
    sel = get_selection(f.product, findall, false);
287 288 289
    if (!findall) {
        [%# save sel for the next invocation of selectProduct() %]
        var tmp = sel;
290

291
        [%# this is an optimization: if we have just added products to an
292 293
            existing selection, no need to clear the form controls and add
            everybody again; just merge the new ones with the existing
294 295 296 297 298 299 300 301
            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 %]
302 303
    var saved_cpts = get_selection(f.component, false, true);
    var saved_vers = get_selection(f.version, false, true);
304
    [% IF Param('usetargetmilestone') %]
305
    var saved_tms = get_selection(f.target_milestone, false, true);
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
    [% 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>

322
[% query_variants = [
323 324 325 326 327 328 329
  { 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" },
330
  { value => "notregexp", description => "doesn't match the regexp" } ] %]
331

332
[% PROCESS "global/field-descs.none.tmpl" %]
333

334
[%# If we resubmit to ourselves, we need to know if we are using a format. %]
335
<input type="hidden" name="query_format" value="[% format FILTER html %]">
336

337 338 339 340
[%# *** Summary *** %]

<table>
  <tr>
341
    <th align="right"><u>S</u>ummary:</th>
342 343 344 345 346
    <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>
347
      [% END %]
348 349 350
      </select>
    </td>
    <td>
351 352
      <input name="short_desc" size="40" accesskey="s"
             value="[% default.short_desc.0 FILTER html %]">
353 354 355 356
    </td>
    <td>
      <input type="submit" value="[% button_name %]">
    </td>
357
  </tr>
358 359 360 361 362 363

[%# *** Product Component Version Target *** %]

  <tr>
    <td colspan="4">
      <table>
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
        <tr>
          <td valign="top">
            <table>
              <tr valign="bottom">
                <th align="left"><u>P</u>roduct:</th>
              </tr>
              <tr valign="top">
                [%# Can't use the select block here because of the onChange %]
                <td align="left">
                  <label for="product" accesskey="p">
                    <select name="product" multiple="multiple" size="5" id="product"
                            onchange="selectProduct(this.form);">
                    [% FOREACH p = product %]
                      <option value="[% p.name FILTER html %]"
                        [% " selected" IF lsearch(default.product, p.name) != -1 %]>
                        [% p.name FILTER html %]</option>
                    [% END %]
                    </select>
                  </label>
                </td>
              </tr>
            </table>
386
          </td>
387 388 389 390 391 392 393 394 395 396 397 398
          <td valign="top">
            <table>
              <tr valign="bottom">
                <th align="left">
                  <a href="describecomponents.cgi">Co<u>m</u>ponent</a>:
                </th>
              </tr>
              <tr valign="top">
                [%# Can't use the select block here because 'component' is a toolkit
                    reserved word - we use 'component_' instead. %]
                <td align="left">
                  <label for="component" accesskey="m">
399
                    <select name="component" id="component"
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
                            multiple="multiple" size="5">
                    [% FOREACH c = component_ %]
                      <option value="[% c FILTER html %]"
                        [% " selected" IF lsearch(default.component, c) != -1 %]>
                        [% c FILTER html %]</option>
                    [% END %]
                    </select>
                  </label>
                </td>
              </tr>
            </table>
          </td>
          <td valign="top">
            <table>
              <tr valign="bottom">
                <th align="left"><u>V</u>ersion:</th>
              </tr>
              <tr valign="top">
418 419
                [% PROCESS select sel = { name => 'version',
                                          size => 5,
420 421 422 423 424 425 426 427 428 429 430
                                          accesskey => 'v' } %]
              </tr>
            </table>
          </td>
        [% IF Param('usetargetmilestone') %]
          <td valign="top">
            <table>
              <tr valign="bottom">
                <th align="left"><u>T</u>arget:</th>
              </tr>
              <tr valign="top">
431
                [% PROCESS select sel = { name => 'target_milestone',
432 433 434 435
                                          size => 5,
                                          accesskey => 't' } %]
              </tr>
            </table>
436 437 438 439 440 441
          </td>
        [% END %]
        </tr>
      </table>
    </td>
  </tr>
442

443 444
[%# *** Comment URL Whiteboard Keywords *** %]

445 446
  [% FOREACH field = [
    { name => "long_desc", description => "A&nbsp;<u>C</u>omment",
447
      accesskey => 'c' },
448
    { name => "bug_file_loc", description => "The&nbsp;<u>U</u>RL",
449
      accesskey => 'u' },
450
    { name => "status_whiteboard", description => "<u>W</u>hiteboard",
451
      accesskey => 'w' } ] %]
452 453 454 455 456 457 458

    [% 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 %]
459
          [% type = "${field.name}_type" %]
460 461
          <option value="[% qv.value %]"
            [% " selected" IF default.$type.0 == qv.value %]>[% qv.description %]</option>
462
        [% END %]
463 464
        </select>
      </td>
465 466 467
      <td><input name="[% field.name %]" size="40"
                 accesskey="[% field.accesskey %]"
                 value="[% default.${field.name}.0 FILTER html %]">
468 469
      </td>
      <td></td>
470
    </tr>
471 472 473 474 475
    [% END %]
  [% END %]

  [% IF have_keywords %]
    <tr>
476 477 478
      <th align="right">
        <a href="describekeywords.cgi"><u>K</u>eywords</a>:
      </th>
479 480
      <td>
        <select name="keywords_type">
481
        [% FOREACH qv = [
482
          { name => "allwords", description => "contains all of the keywords" },
483
          { name => "anywords", description => "contains any of the keywords" },
484 485 486 487 488 489 490 491 492
          { 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>
493 494
        <input name="keywords" size="40" accesskey="k"
               value="[% default.keywords.0 FILTER html %]">
495 496 497
      </td>
    </tr>
  [% END %]
498
</table>
499 500 501 502 503 504 505

<hr>

[%# *** Status Resolution Severity Priority Hardware OS *** %]

<table>
  <tr>
506 507 508 509 510 511
    <td>
      <table>
        <tr>
          <th align="left"><a href="queryhelp.cgi#status">St<u>a</u>tus</a>:</th>
        </tr>
        <tr valign="top">
512
          [% PROCESS select sel = { name => 'bug_status',
513 514 515 516 517 518 519 520 521 522 523 524 525
                                    size => 7,
                                    accesskey => 'a' } %]
        </tr>
      </table>
    </td>
    <td>
      <table>
        <tr>
          <th align="left">
            <a href="queryhelp.cgi#resolution"><u>R</u>esolution</a>:
          </th>
        </tr>
        <tr valign="top">
526
          [% PROCESS select sel = { name => 'resolution',
527 528 529 530 531 532 533 534 535 536 537
                                    size => 7,
                                    accesskey => 'r' } %]
        </tr>
      </table>
    </td>
    <td>
      <table>
        <tr>
          <th align="left"><a href="queryhelp.cgi#severity">S<u>e</u>verity</a>:</th>
        </tr>
        <tr valign="top">
538
          [% PROCESS select sel = { name => 'bug_severity',
539
                                    size => 7,
540
                                    accesskey => 'e' } %]
541 542 543 544 545 546 547 548 549
        </tr>
      </table>
    </td>
    <td>
      <table>
        <tr>
          <th align="left"><a href="queryhelp.cgi#priority">Pr<u>i</u>ority</a>:</th>
        </tr>
        <tr valign="top">
550 551 552
          [% PROCESS select sel = { name => 'priority',
                                    size => 7,
                                    accesskey => 'i' } %]
553 554 555 556 557 558 559 560 561
        </tr>
      </table>
    </td>
    <td>
      <table>
        <tr>
          <th align="left"><a href="queryhelp.cgi#platform"><u>H</u>ardware</a>:</th>
        </tr>
        <tr valign="top">
562
          [% PROCESS select sel = { name => 'rep_platform',
563 564 565 566 567 568 569 570 571 572 573
                                    size => 7,
                                    accesskey => 'h' } %]
        </tr>
      </table>
    </td>
    <td>
      <table>
        <tr>
          <th align="left"><a href="queryhelp.cgi#opsys"><u>O</u>S</a>:</th>
        </tr>
        <tr valign="top">
574 575
          [% PROCESS select sel = { name => 'op_sys',
                                    size => 7,
576 577 578 579
                                    accesskey => 'o' } %]
        </tr>
      </table>
    </td>
580 581 582 583 584 585 586 587 588 589 590 591 592 593
  </tr>
</table>

<p>

[%# *** Email Numbering Votes *** %]

<table>
  <tr>
    <td>
      <fieldset>
        <legend>
          <strong>
            <a href="queryhelp.cgi#peopleinvolved">Email</a> and Numbering
594
          </strong>
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
        </legend>


<table>
  <tr>
  [% FOREACH n = [1, 2] %]
    <td>


<table cellspacing="0" cellpadding="0">
  <tr>
    <td>
      Any of:
    </td>
  </tr>
  <tr>
    <td>
612
      <input type="checkbox" name="emailassigned_to[% n %]"
613 614 615
             id="emailassigned_to[% n %]" value="1"
             [% " checked" IF default.emailassigned_to.$n %]>
      <label for="emailassigned_to[% n %]">
616
        [% terms.bug %] owner
617 618 619 620 621
      </label>
    </td>
  </tr>
  <tr>
    <td>
622
      <input type="checkbox" name="emailreporter[% n %]"
623 624 625 626 627 628 629 630 631 632
             id="emailreporter[% n %]" value="1"
             [% " checked" IF default.emailreporter.$n %]>
      <label for="emailreporter[% n %]">
        reporter
      </label>
    </td>
  </tr>
  [% IF Param('useqacontact') %]
  <tr>
    <td>
633
      <input type="checkbox" name="emailqa_contact[% n %]"
634 635 636 637 638 639 640 641 642 643
             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>
644
      <input type="checkbox" name="emailcc[% n %]"
645 646 647 648 649 650 651 652 653
             id="emailcc[% n %]" value="1"
             [% " checked" IF default.emailcc.$n %]>
      <label for="emailcc[% n %]">
        CC list member
      </label>
    </td>
  </tr>
  <tr>
    <td>
654
        <input type="checkbox" name="emaillongdesc[% n %]"
655 656 657 658 659 660 661 662 663 664
               id="emaillongdesc[% n %]" value="1"
               [% " checked" IF default.emaillongdesc.$n %]>
      <label for="emaillongdesc[% n %]">
        commenter
      </label>
    </td>
  </tr>
  <tr>
    <td>
      <select name="emailtype[% n %]">
665
      [% FOREACH qv = [
666 667 668
        { name => "substring", description => "contains" },
        { name => "exact", description => "is" },
        { name => "regexp", description => "matches regexp" },
669
        { name => "notregexp", description => "doesn't match regexp" } ] %]
670

671 672 673 674 675 676 677 678 679 680 681 682 683
        <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>

684

685 686 687 688 689
    </td>
  [% END %]
  </tr>
</table>
<hr>
690
<table>
691 692 693 694 695 696
  <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>
697
      [% terms.bugs %] numbered:
698 699 700 701 702 703 704 705 706
    </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>
707 708 709
  [% IF Param('usevotes') %]
    <tr>
      <td align="right">
710
        Only [% terms.bugs %] with at least:
711 712 713 714 715 716
      </td>
      <td>
        <input name="votes" size="3" value="[% default.votes.0 FILTER html %]"> votes
      </td>
    </tr>
  [% END %]
717 718 719 720 721 722 723 724 725 726
</table>


      </fieldset>
    </td>
   
[%# *** Bug Changes *** %]

    <td valign="top">
      <fieldset>
727
        <legend><strong>[% terms.Bug %] Changes</strong></legend>
728 729 730


<dl>
731
  <dt>Only [% terms.bugs %] changed between:</dt>
732 733 734 735 736 737
  <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 or <a href="queryhelp.cgi#changedbetween">relative dates</a>)
  </dd><br>
  <dt>where one or more of the following changed:</dt>
738
  <dd>
739
    <select name="chfield" multiple="multiple" size="4">
740 741 742
    [% FOREACH field = chfield %]
      <option value="[% field FILTER html %]"
        [% " selected" IF lsearch(default.chfield, field) != -1 %]>
743
        [% (field_descs.$field || field) FILTER html %]</option>
744 745
    [% END %]
    </select>
746 747
  </dd><br>
  <dt>and the new value was:</dt>
748 749
  <dd>
    <input name="chfieldvalue" size="20" value="[% default.chfieldvalue.0 FILTER html %]">
750
  </dd><br>
751 752 753 754 755 756 757 758 759 760 761 762 763
</dl>

       </fieldset>
     </td>
  </tr>
</table>

[%############################################################################%]
[%# Block for SELECT fields                                                  #%]
[%############################################################################%]

[% BLOCK select %]
  <td align="left">
764 765 766 767 768 769 770 771 772 773
    <label for="[% sel.name %]" accesskey="[% sel.accesskey %]">
      <select name="[% sel.name %]" id="[% sel.name %]"
              multiple="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>
    </label>
774 775
  </td>
[% END %]