2011-02-16 20:02:17 +03:00
|
|
|
/* 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): Vitaliy Filippov <vitalif@mail.ru>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
JavaScript code to hide and show values of select fields on the query form.
|
|
|
|
I.e. hide dependent values when their controlling value is hidden.
|
|
|
|
This code uses client-side cached qfVisibility hash data generated by
|
|
|
|
fieldvaluecontrol.cgi?type=search.
|
|
|
|
|
|
|
|
qfVisibility format: {
|
|
|
|
// for each field:
|
|
|
|
field_name : {
|
|
|
|
// all legal values for the field:
|
|
|
|
legal : [ { id : 0, name : "NAME" }, ... ],
|
|
|
|
// visibility data for field values:
|
|
|
|
values : { controlled_field_name : { controlled_value_id : { visibility_value_id : 1, ... }, ... }, ... },
|
|
|
|
},
|
|
|
|
...
|
|
|
|
};
|
|
|
|
|
|
|
|
Important nuances of implementation:
|
|
|
|
|
|
|
|
Non-custom product-dependent Bugzilla fields (component, version, target_milestone)
|
|
|
|
values are not uniquely identified by their name. There could be many values with
|
|
|
|
same name belonging to different products.
|
|
|
|
|
|
|
|
Logically, such behavior is more convenient than one implemented in Bugzilla
|
|
|
|
custom fields, where each value has a unique name and could be "visible"
|
|
|
|
inside some, for example, products (you cannot possibly add different
|
|
|
|
descriptions for the value inside different products). So we need to support it
|
|
|
|
and remove duplicate names inside selectboxes.
|
|
|
|
|
|
|
|
But simply using names instead of IDs for filtering is insufficient: if
|
|
|
|
someday we'll have a custom field (say cf_1) depending on one of such "non-unique-value-name"
|
|
|
|
fields (say milestone), then selecting a product AND a milestone will display
|
|
|
|
the list of cf_1 values which are visible for ANY of milestones with selected name
|
|
|
|
ignoring selected product.
|
|
|
|
|
|
|
|
So we need to remember "which IDs of each name" are active now and filter
|
|
|
|
dependent values accordingly. I.e. when ONE product is selected, only ONE ID
|
|
|
|
could be present for each milestone displayed in selectbox.
|
|
|
|
|
|
|
|
We also need to preserve the sort order of dependent "non-unique-value-name" values,
|
|
|
|
respecting this "list of active IDs".
|
|
|
|
|
|
|
|
*/
|
2010-11-10 21:21:19 +03:00
|
|
|
|
2010-11-13 20:35:55 +03:00
|
|
|
var qfHandling = {};
|
2010-11-10 21:21:19 +03:00
|
|
|
YAHOO.util.Event.addListener(window, 'load', initQueryformFields);
|
|
|
|
|
|
|
|
function initQueryformFields()
|
|
|
|
{
|
|
|
|
for (var i in qfVisibility)
|
2010-11-13 20:35:55 +03:00
|
|
|
{
|
|
|
|
if (!qfHandling[i])
|
|
|
|
handleQueryformField(null, document.getElementById(i));
|
2010-11-10 21:21:19 +03:00
|
|
|
initQueryformField(i);
|
2010-11-13 20:35:55 +03:00
|
|
|
}
|
2010-11-10 21:21:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function initQueryformField(i)
|
|
|
|
{
|
|
|
|
var f = document.getElementById(i);
|
|
|
|
YAHOO.util.Event.addListener(f, 'change', handleQueryformField, f);
|
|
|
|
}
|
|
|
|
|
2011-02-16 20:02:17 +03:00
|
|
|
// Get selected IDs of names selected in selectbox sel
|
2010-11-10 21:21:19 +03:00
|
|
|
function getQueryformSelectedIds(sel)
|
|
|
|
{
|
|
|
|
var opt = {};
|
|
|
|
var a;
|
|
|
|
var has_selected;
|
2011-02-16 20:02:17 +03:00
|
|
|
var l2 = sel.id.length+4;
|
|
|
|
// No selection is equivalent to full selection
|
2010-11-10 21:21:19 +03:00
|
|
|
for (var i = 0; i < sel.options.length; i++)
|
|
|
|
{
|
|
|
|
if (sel.options[i].selected)
|
|
|
|
{
|
|
|
|
has_selected = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-02-16 20:02:17 +03:00
|
|
|
// Iterate over all options
|
2010-11-10 21:21:19 +03:00
|
|
|
for (var i = 0; i < sel.options.length; i++)
|
|
|
|
{
|
|
|
|
if (sel.options[i].selected || !has_selected)
|
|
|
|
{
|
2011-02-16 20:02:17 +03:00
|
|
|
// IDs of options are qf_SELECTBOXID_1_2_3_...
|
|
|
|
// where 1_2_3 is the list of IDs mapped to this option name
|
|
|
|
// which are currently visible.
|
|
|
|
a = sel.options[i].id.substr(l2).split('_');
|
2010-11-10 21:21:19 +03:00
|
|
|
for (var j in a)
|
|
|
|
opt[a[j]] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return opt;
|
|
|
|
}
|
|
|
|
|
2011-02-16 20:02:17 +03:00
|
|
|
// Get the array with values of options selected in sel selectbox
|
2010-11-10 21:21:19 +03:00
|
|
|
function getPlainSelectedIds(sel)
|
|
|
|
{
|
|
|
|
var o = {};
|
|
|
|
for (var i = 0; i < sel.options.length; i++)
|
|
|
|
if (sel.options[i].selected)
|
|
|
|
o[sel.options[i].value] = true;
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2011-02-16 20:02:17 +03:00
|
|
|
// Handle change of selection inside a selectbox 'controller'
|
|
|
|
// Update all dependent fields
|
|
|
|
function handleQueryformField(event, controller)
|
2010-11-10 21:21:19 +03:00
|
|
|
{
|
|
|
|
var controlled, controlled_selected;
|
2011-02-16 20:02:17 +03:00
|
|
|
var vis, item, legal, name2id, name2id_order, valueVD;
|
2011-06-20 21:18:51 +04:00
|
|
|
qfHandling[controller.id] = true; // prevent double-action during init
|
2011-02-16 20:02:17 +03:00
|
|
|
var VD = qfVisibility[controller.id];
|
|
|
|
var visibility_selected = getQueryformSelectedIds(controller);
|
|
|
|
for (var controlled_id in VD.values)
|
2010-11-10 21:21:19 +03:00
|
|
|
{
|
|
|
|
controlled = document.getElementById(controlled_id);
|
|
|
|
if (!controlled)
|
|
|
|
continue;
|
2011-02-16 20:02:17 +03:00
|
|
|
// Save and clear old selection for dependent field:
|
2010-11-10 21:21:19 +03:00
|
|
|
controlled_selected = getPlainSelectedIds(controlled);
|
|
|
|
bz_clearOptions(controlled);
|
2011-02-16 20:02:17 +03:00
|
|
|
// Loop over all legal values and remember currently
|
|
|
|
// visible IDs inside name2id preserving their original
|
|
|
|
// order using name2id_order
|
|
|
|
legal = qfVisibility[controlled_id]['legal'];
|
|
|
|
name2id = {};
|
|
|
|
name2id_order = [];
|
|
|
|
for (var i in legal)
|
2010-11-10 21:21:19 +03:00
|
|
|
{
|
2011-02-16 20:02:17 +03:00
|
|
|
valueVD = VD.values[controlled_id][legal[i].id]
|
|
|
|
// Visible also if valueVD is an empty hash:
|
|
|
|
vis = true;
|
|
|
|
if (valueVD)
|
2010-11-10 21:21:19 +03:00
|
|
|
{
|
2011-02-16 20:02:17 +03:00
|
|
|
for (var cid in valueVD)
|
2010-11-10 21:21:19 +03:00
|
|
|
{
|
2011-02-16 20:02:17 +03:00
|
|
|
vis = false;
|
|
|
|
if (visibility_selected[cid])
|
2010-11-10 21:21:19 +03:00
|
|
|
{
|
2011-02-16 20:02:17 +03:00
|
|
|
vis = true;
|
|
|
|
break;
|
2010-11-10 21:21:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-02-16 20:02:17 +03:00
|
|
|
if (vis)
|
|
|
|
{
|
|
|
|
// This value is now visible
|
|
|
|
if (!name2id[legal[i].name])
|
|
|
|
{
|
|
|
|
name2id[legal[i].name] = [];
|
|
|
|
name2id_order.push(legal[i].name);
|
|
|
|
}
|
|
|
|
name2id[legal[i].name].push(legal[i].id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Create options
|
|
|
|
for (var i in name2id_order)
|
|
|
|
{
|
|
|
|
i = name2id_order[i];
|
|
|
|
item = bz_createOptionInSelect(controlled, i, i);
|
|
|
|
/* Save particular selected IDs for the same name
|
|
|
|
for cascade selection of such fields.
|
|
|
|
At the moment, only component, version and target_milestone fields
|
|
|
|
can have many values with the same name, and they do not affect the
|
|
|
|
case of cascade selection when there are no custom fields depending
|
|
|
|
on them. */
|
|
|
|
item.id = 'qf_'+controlled_id+'_'+name2id[i].join('_');
|
|
|
|
if (controlled_selected[i])
|
2010-11-10 21:21:19 +03:00
|
|
|
{
|
2011-02-16 20:02:17 +03:00
|
|
|
// Restore selection
|
|
|
|
item.selected = true;
|
2010-11-10 21:21:19 +03:00
|
|
|
}
|
|
|
|
}
|
2011-02-16 20:07:33 +03:00
|
|
|
handleQueryformField(event, controlled);
|
2010-11-10 21:21:19 +03:00
|
|
|
item = document.getElementById(controlled_id+'_cont');
|
|
|
|
if (item)
|
2011-02-16 20:02:17 +03:00
|
|
|
{
|
|
|
|
// Hide fields with no options
|
2010-11-10 21:21:19 +03:00
|
|
|
item.style.display = controlled.options.length ? '' : 'none';
|
2011-02-16 20:02:17 +03:00
|
|
|
}
|
2010-11-10 21:21:19 +03:00
|
|
|
}
|
|
|
|
}
|