]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Fix for bug 123030: Move query.cgi javascript to separate file. Create
authorkiko%async.com.br <>
Wed, 21 Jul 2004 07:58:44 +0000 (07:58 +0000)
committerkiko%async.com.br <>
Wed, 21 Jul 2004 07:58:44 +0000 (07:58 +0000)
productform.js that contains functions to handle the various select
boxes in the advanced search page, and update the callsites to use
it. r,a=myk.

js/productform.js [new file with mode: 0644]
template/en/default/search/form.html.tmpl
template/en/default/search/search-advanced.html.tmpl

diff --git a/js/productform.js b/js/productform.js
new file mode 100644 (file)
index 0000000..0be0d49
--- /dev/null
@@ -0,0 +1,295 @@
+/* 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): Christian Reis <kiko@async.com.br>
+ */
+
+/* this file contains functions to update form controls based on a
+ * collection of javascript arrays containing strings */
+
+/* selectProduct reads the selection from the product control and
+ * updates version, component and milestone controls accordingly.
+ * 
+ *     - product, component, version and milestone: form controls
+ *
+ * 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(product, component, version, milestone) {
+
+    if (!product) {
+        /* this is to avoid handling events that occur before the form
+         * itself is ready, which could happen in buggy browsers. */
+        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) && (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 = product.selectedIndex == -1;
+    sel = get_selection(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;
+    }
+
+    /* do the actual fill/update */
+    if (component) {
+        var saved_cpts = get_selection(component, false, true);
+        updateSelect(cpts, sel, component, merging);
+        restoreSelection(component, saved_cpts);
+    }
+
+    if (version) {
+        var saved_vers = get_selection(version, false, true);
+        updateSelect(vers, sel, version, merging);
+        restoreSelection(version, saved_vers);
+    }
+
+    if (milestone) {
+        var saved_tms = get_selection(milestone, false, true);
+        updateSelect(tms, sel, milestone, merging);
+        restoreSelection(milestone, saved_tms);
+    }
+}
+
+
+/* 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;
+}
+
+
+/* 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;
+            }
+        }
+    }
+}
+
+
+/* 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;
+}
+
index 2fd458148ba7b6ef5f143ece83b31bffc3423dcc..f875f35411773b061660c71b872b84cb6f43940c 100644 (file)
 
 [% 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" },
@@ -379,7 +83,7 @@ function selectProduct(f) {
                 <td align="left">
                   <label for="product" accesskey="p">
                     <select name="product" multiple="multiple" size="5" id="product"
-                            onchange="selectProduct(this.form);">
+                            onchange="doOnSelectProduct();">
                     [% FOREACH p = product %]
                       <option value="[% p.name FILTER html %]"
                         [% " selected" IF lsearch(default.product, p.name) != -1 %]>
index bbed6c2d6eae0f37b752cda6d7b6a0781430a180..89938adbe7cf13c946d214d6332dc6543f6b5266 100644 (file)
 [% USE Bugzilla %]
 [% cgi = Bugzilla.cgi %]
 
+
+[% js_data = BLOCK %]
+function doOnSelectProduct() {
+    var f = document.forms['queryform'];
+    milestone = (typeof(f.target_milestone) == "undefined" ? 
+                                               null : f.target_milestone);
+    selectProduct(f.product, f.component, f.version, milestone);
+}
+
+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 %]
+
+[% END %]
+
 [% PROCESS global/header.html.tmpl
   title = "Search for $terms.bugs"
   h1 = ""
-  onload = "selectProduct(document.forms['queryform']);initHelp();"
+  onload = "doOnSelectProduct(); initHelp();"
+  javascript = js_data
+  javascript_urls = [ "js/productform.js" ]
   style = "td.selected_tab {
              border-width: 2px 2px 0px;
              border-style: solid;