bugzilla-4intranet/js/query-visibility.js

205 lines
6.5 KiB
JavaScript
Raw Normal View History

/* 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".
*/
var qfHandling = {};
YAHOO.util.Event.addListener(window, 'load', initQueryformFields);
function initQueryformFields()
{
for (var i in qfVisibility)
{
if (!qfHandling[i])
handleQueryformField(null, document.getElementById(i));
initQueryformField(i);
}
}
function initQueryformField(i)
{
var f = document.getElementById(i);
YAHOO.util.Event.addListener(f, 'change', handleQueryformField, f);
}
// Get selected IDs of names selected in selectbox sel
function getQueryformSelectedIds(sel)
{
var opt = {};
var a;
var has_selected;
var l2 = sel.id.length+4;
// No selection is equivalent to full selection
for (var i = 0; i < sel.options.length; i++)
{
if (sel.options[i].selected)
{
has_selected = true;
break;
}
}
// Iterate over all options
for (var i = 0; i < sel.options.length; i++)
{
if (sel.options[i].selected || !has_selected)
{
// 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('_');
for (var j in a)
opt[a[j]] = true;
}
}
return opt;
}
// Get the array with values of options selected in sel selectbox
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;
}
// Handle change of selection inside a selectbox 'controller'
// Update all dependent fields
function handleQueryformField(event, controller)
{
var controlled, controlled_selected;
var vis, item, legal, name2id, name2id_order, valueVD;
qfHandling[controller.id] = true; // prevent double-action during init
var VD = qfVisibility[controller.id];
var visibility_selected = getQueryformSelectedIds(controller);
for (var controlled_id in VD.values)
{
controlled = document.getElementById(controlled_id);
if (!controlled)
continue;
// Save and clear old selection for dependent field:
controlled_selected = getPlainSelectedIds(controlled);
bz_clearOptions(controlled);
// 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)
{
valueVD = VD.values[controlled_id][legal[i].id]
// Visible also if valueVD is an empty hash:
vis = true;
if (valueVD)
{
for (var cid in valueVD)
{
vis = false;
if (visibility_selected[cid])
{
vis = true;
break;
}
}
}
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])
{
// Restore selection
item.selected = true;
}
}
handleQueryformField(event, controlled);
item = document.getElementById(controlled_id+'_cont');
if (item)
{
// Hide fields with no options
item.style.display = controlled.options.length ? '' : 'none';
}
}
}