📄 form.html.tmpl
字号:
[%# 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> #%][% PROCESS global/variables.none.tmpl %] [%# 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 = p.components %]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ]; vers[[% n %]] = [ [%- FOREACH item = p.versions -%]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- END -%] ]; [% IF Param('usetargetmilestone') %] tms[[% n %]] = [ [%- FOREACH item = p.milestones %]'[% item FILTER js %]'[% ", " UNLESS loop.last %] [%- 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 get_selection(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 = get_selection(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 = get_selection(f.component, false, true); var saved_vers = get_selection(f.version, false, true); [% IF Param('usetargetmilestone') %] var saved_tms = get_selection(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" } ] %][% PROCESS "global/field-descs.none.tmpl" %][%# If we resubmit to ourselves, we need to know if we are using a format. %][% thisformat = query_format != '' ? query_format : format %]<input type="hidden" name="query_format" value="[% thisformat FILTER html %]">[%# *** Summary *** %]<table> <tr> <th align="right"><u>S</u>ummary:</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" accesskey="s" value="[% default.short_desc.0 FILTER html %]"> <script language="JavaScript" type="text/javascript"> <!-- document.forms['queryform'].short_desc.focus(); // --> </script> </td> <td> [% IF button_name %] <input type="submit" value="[% button_name FILTER html %]"> [% END %] </td> </tr>[%# *** Product Component Version Target *** %] <tr> <td colspan="4"> <table> <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>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -