/* Functions used to show/hide dependent bug fields and change their select options * License: Dual-license GPL 3.0+ or MPL 1.1+ * Author(s): Vitaliy Filippov */ onDomReady(initControlledFields); function initControlledFields() { // Initialise fields in correct order (starting with top-most controller fields) var initialised = {}; var doInit = function(f) { if (f && !initialised[f]) { initialised[f] = true; doInit(field_metadata[f].visibility_field); doInit(field_metadata[f].value_field); doInit(field_metadata[f].null_field); doInit(field_metadata[f].default_field); initControlledField(f); } }; for (var i in field_metadata) { doInit(i); } if (navigator.appName == 'Microsoft Internet Explorer') { // :-X reflow page to hide the gap between bugzilla-body and footer in IE8 document.body.className = document.body.className; } } function initControlledField(id) { var f = document.getElementById(id); if (!f || f.nodeName != 'INPUT' || f.type != 'hidden') { handleControlledField(id, !document.forms['Create']); } if (f) { addListener(f, 'change', handleControllerField_this); } } function handleControllerField_this(e, nonfirst) { var m = field_metadata[this.id]; if (!m) { return; } var f = {}; for (var i in { 'fields': 1, 'values': 1, 'null': 1, 'defaults': 1 }) { for (var j in m[i]) { f[j] = true; } } for (var i in f) { handleControlledField(i); } // Cascade events for (var i in f) { handleControllerField_this.apply(document.getElementById(i), [ null, true ]); } if (!nonfirst && navigator.appName == 'Microsoft Internet Explorer') { // :-X reflow page to hide the gap between bugzilla-body and footer in IE8 document.body.className = document.body.className; } } function setFieldValue(f, v) { if (f.nodeName == 'SELECT') { if (f.multiple) { f.selectedIndex = -1; } if (v) { v = v.split(','); for (var i in v) { i = document.getElementById('v' + v[i] + '_' + f.id); if (i) { i.selected = true; } } } else if (!f.multiple) { f.selectedIndex = 0; } } else if (f.type != 'hidden') { f.value = v; } return v; } function handleControlledField(controlled_id, is_initial_editform) { var m = field_metadata[controlled_id]; if (!m) { return; } var controlled = document.getElementById(controlled_id); var vis; // Show/hide the field if (m.visibility_field && document.getElementById(m.visibility_field)) { vis = checkValueVisibility(getSelectedIds(m.visibility_field), field_metadata[m.visibility_field]['fields'][controlled_id]); for (var i in { row: 1, container: 1, label: 1 }) { var field_container = document.getElementById('field_' + i + '_' + controlled_id); (vis ? removeClass : addClass)(field_container, 'bz_hidden_field'); } } if (!controlled) { // Maybe the field is not editable. return; } var df, diff; if (m.default_value || (df = m.default_field && document.getElementById(m.default_field))) { // Check if the value is different from previous default or from empty value // We must check it before re-filling field options because some values may disappear if (controlled.nodeName == 'SELECT') { var copt = getSelectedIds(controlled); delete copt[0]; // skip empty value if (copt.UNKNOWN) { // We are on the bug entry form and some default value is selected, // but its ID is still unknown (because entry form does not prefill select options) diff = true; } if (controlled._oldDefault) { for (var i in controlled._oldDefault) { if (copt[controlled._oldDefault[i]]) delete copt[controlled._oldDefault[i]]; else { diff = true; break; } } } for (var i in copt) { diff = true; break; } } else diff = controlled.value != (controlled._oldDefault || ''); } if (is_initial_editform) { // Skip re-filling of fields on bug edit page load, because // the bug may include incorrect values that must not be hidden initially. // Also remember, but do not select the default value in this case. } else if (controlled.nodeName == 'SELECT') { // Change select options if (m.value_field && document.getElementById(m.value_field)) { // It is more correct to match selected values on name, because a // target_milestone/version/component with the same name may exist for a different product var copt = getSelectedValues(controlled); bz_clearOptions(controlled); var nullable = m.nullable && !controlled.multiple; if (m.null_field && nullable && document.getElementById(m.null_field)) { nullable = checkValueVisibility(getSelectedIds(m.null_field), field_metadata[m.null_field]['null'][controlled_id]); } nullable = nullable || controlled_id == 'component' && document.forms['Create']; if (nullable) { bz_createOptionInSelect(controlled, '---', ''); } var opt = getSelectedIds(m.value_field), controlled_value; var vh = field_metadata[m.value_field]['values'][controlled_id]; for (var i in m.legal) { controlled_value = m.legal[i]; vis = checkValueVisibility(opt, vh && vh[controlled_value[0]]); if (vis) { var item = bz_createOptionInSelect(controlled, controlled_value[1], controlled_value[1]); item.id = 'v'+controlled_value[0]+'_'+controlled_id; if (copt[controlled_value[1]]) { item.selected = true; } } } } else if (m.nullable && !controlled.multiple && m.null_field && document.getElementById(m.null_field)) { // Just enable/disable empty value var nullable = checkValueVisibility(getSelectedIds(m.null_field), field_metadata[m.null_field]['null'][controlled_id]); var has_null = controlled.options[0].value == ''; if (nullable && !has_null) { controlled.insertBefore(new Option('---', ''), controlled.options[0]); } else if (!nullable && has_null) { controlled.removeChild(controlled.options[0]); } } } if (m.default_value || df) { // Remember default value for the new controller var v = m.default_value; if (df && field_metadata[m.default_field]['defaults'][controlled_id]) for (var i in getSelectedIds(m.default_field)) v = field_metadata[m.default_field]['defaults'][controlled_id][i]; controlled._oldDefault = v; if (!diff && !is_initial_editform) { // If the field was empty or equal to the previous default, set it to the new default setFieldValue(controlled, v); } } }