Bug 135368 - Redesign product group control page

git-svn-id: svn://svn.office.custis.ru/3rdparty/bugzilla.org/trunk@1839 6955db30-a419-402b-8a0d-67ecbb4d7f56
master
akrasilnikov 2013-10-04 11:17:27 +00:00
parent 17cf2d121f
commit b85c47d0d8
6 changed files with 330 additions and 186 deletions

View File

@ -331,16 +331,23 @@ if ($action eq 'updategroupcontrols') {
my @now_na = ();
my @now_mandatory = ();
my %membercontrol_g;
my %othercontrol_g;
foreach my $f ($cgi->param()) {
if ($f =~ /^membercontrol_(\d+)$/) {
my $id = $1;
if ($cgi->param($f) == CONTROLMAPNA) {
push @now_na,$id;
} elsif ($cgi->param($f) == CONTROLMAPMANDATORY) {
push @now_mandatory,$id;
if ($f =~ /^group_(\d+)$/) {
my $count_id = $1;
my $id = $cgi->param($f);
trick_taint($id);
if ($cgi->param("membercontrol_" . $count_id) == CONTROLMAPNA) {
push @now_na, $id;
} elsif ($cgi->param("membercontrol_" . $count_id) == CONTROLMAPMANDATORY) {
push @now_mandatory, $id;
}
$membercontrol_g{$id} = $cgi->param("membercontrol_" . $count_id);
$othercontrol_g{$id} = $cgi->param("othercontrol_" . $count_id);
}
}
if (!defined $cgi->param('confirmed')) {
my $na_groups;
if (@now_na) {
@ -396,8 +403,8 @@ if ($action eq 'updategroupcontrols') {
my $group_id = $group->id;
$product->set_group_controls($group,
{entry => scalar $cgi->param("entry_$group_id") || 0,
membercontrol => scalar $cgi->param("membercontrol_$group_id") || CONTROLMAPNA,
othercontrol => scalar $cgi->param("othercontrol_$group_id") || CONTROLMAPNA,
membercontrol => scalar %membercontrol_g->{$group_id} || CONTROLMAPNA,
othercontrol => scalar %othercontrol_g->{$group_id} || CONTROLMAPNA,
canedit => scalar $cgi->param("canedit_$group_id") || 0,
editcomponents => scalar $cgi->param("editcomponents_$group_id") || 0,
editbugs => scalar $cgi->param("editbugs_$group_id") || 0,

159
js/admin_groupcontrol.js Normal file
View File

@ -0,0 +1,159 @@
function helpToggle(btn_id, div_id)
{
var b = document.getElementById(btn_id);
var d = document.getElementById(div_id);
if (d.style.display == 'none')
{
b.value = 'Hide \u25B4';
d.style.display = '';
}
else
{
b.value = 'Show \u25BE';
d.style.display = 'none';
}
}
function copySelect(prefix, suffix)
{
var o = document.getElementById(prefix+'new');
var e = document.createElement('select');
e.id = e.name = prefix+suffix;
e.innerHTML = o.innerHTML;
e.selectedIndex = o.selectedIndex;
return e;
}
function flashItem(e)
{
var i = 0;
clearTimeout(e.flashIntervalId);
e.style.background = 'red';
e.flashIntervalId = setInterval(function() {
if (++i < 6)
e.style.background = e.style.backgroundColor == 'red' ? '' : 'red';
else
clearTimeout(e.flashIntervalId);
}, 100);
}
function addListGroup(list_name)
{
var group_select = document.getElementById('add_'+list_name);
var group_id = group_select.value;
var group_name = group_select.options[group_select.selectedIndex].text;
var added_li = document.getElementById('li_'+list_name+'_'+group_id);
if (added_li)
{
// Flash the already added group entry
document.getElementById(list_name+'_'+group_id).focus();
flashItem(added_li);
return;
}
added_li = document.getElementById('li_'+list_name+'_empty');
if (added_li)
added_li.parentNode.removeChild(added_li);
added_li = document.createElement('li');
added_li.id = 'li_'+list_name+'_'+group_id;
var e = document.createElement('input');
e.type = 'checkbox';
e.value = '1';
e.checked = true;
e.name = e.id = list_name+'_'+group_id;
added_li.appendChild(e);
e = document.createElement('label');
e.htmlFor = list_name+'_'+group_id;
e.appendChild(document.createTextNode(' ' + group_name));
added_li.appendChild(e);
var list = document.getElementById(list_name+'_list');
list.appendChild(added_li);
}
function clearSelectedOption(el) {
var aValue = el.getAttribute("data-lastvalue");
el.setAttribute("data-lastvalue", el.value);
var options = el.options;
var length = options.length;
for (var i = 0; i < length; i++) {
if (options[i].value == aValue) {
options[i].selected = true;
options[i].setAttribute("selected", "selected");
} else {
options[i].selected = false;
options[i].removeAttribute("selected");
}
}
}
function deleteGroup(el_link, grp_id) {
var el = document.getElementById('control_' + grp_id);
var el_group = document.getElementById('group_' + grp_id);
var el_membercontrol = document.getElementById('membercontrol_' + grp_id);
var el_othercontrol = document.getElementById('othercontrol_' + grp_id);
if (el.getAttribute("data-deleted") == null) {
el.setAttribute("data-deleted", "1")
el.style.textDecoration = 'line-through';
el_group.setAttribute('disabled', true);
el_membercontrol.setAttribute('disabled', true);
el_othercontrol.setAttribute('disabled', true);
clearSelectedOption(el_membercontrol);
clearSelectedOption(el_othercontrol);
el_link.innerHTML = 'Undo delete';
} else {
el.removeAttribute("data-deleted");
el.style.textDecoration = 'none';
el_group.removeAttribute('disabled');
el_membercontrol.removeAttribute('disabled');
el_othercontrol.removeAttribute('disabled');
clearSelectedOption(el_membercontrol);
clearSelectedOption(el_othercontrol);
el_link.innerHTML = 'Delete';
}
}
function existElement(el_id) {
var el = document.getElementById(el_id);
if (typeof (el) != undefined && typeof (el) != null && typeof (el) != 'undefined' && el !== null) {
return true;
} else {
return false;
}
}
function addNewGroup() {
if (existElement("control_empty")) {
var empty_el = document.getElementById('control_empty');
empty_el.parentNode.removeChild(empty_el);
}
var etalon_control = document.getElementById('etalon_control');
var table = document.getElementById('control_list')
var row = table.insertRow(-1);
row.id = 'control_' + count_rows;
var cell_groups = row.insertCell(0);
var cell_control_1 = row.insertCell(1);
var cell_control_2 = row.insertCell(2);
var cell_empty = row.insertCell(3);
var cell_action = row.insertCell(4);
cell_action.innerHTML = '<a href="#" class="icon-delete" onclick="deleteGroup(this, ' + count_rows + '); return false;">Delete</a>';
var etalon_group = document.getElementById('etalon_groups');
var new_group = document.createElement('select');
new_group.id = 'group_' + count_rows;
new_group.name = 'group_' + count_rows;
new_group.onchange = 'saveNewGroup(this.value)';
new_group.innerHTML = '<option></option>' + etalon_group.innerHTML;
cell_groups.appendChild(new_group);
var new_control_1 = document.createElement('select');
new_control_1.id = 'membercontrol_' + count_rows;
new_control_1.name = 'membercontrol_' + count_rows;
new_control_1.innerHTML = etalon_control.innerHTML;
cell_control_1.appendChild(new_control_1);
var new_control_2 = document.createElement('select');
new_control_2.id = 'othercontrol_' + count_rows;
new_control_2.name = 'othercontrol_' + count_rows;
new_control_2.innerHTML = etalon_control.innerHTML;
cell_control_2.appendChild(new_control_2);
count_rows++;
}

View File

@ -0,0 +1,78 @@
.group_list
{
list-style-type: none;
padding: 0.3em;
margin: 0 0 1em 1em;
float: left;
border: 1px solid gray;
border-radius: 5px;
background: white;
box-shadow: 0 5px 5px gray;
}
.group_list input, .group_list select { vertical-align: middle; }
.group_list li { padding: 0.25em 0.5em; float: left; }
.group_empty { color: gray; }
.help_popup
{
border: 1px solid gray;
border-radius: 5px;
margin: 0 0 1em 0;
padding: 0 1em;
background: white;
box-shadow: 0 5px 5px gray;
}
.help_table { border-collapse: collapse; }
.help_table td, .help_table th { border: 1px solid gray; font-size: 10pt; padding: 2px; }
.help_table tr td:nth-child(1) { text-align: center; }
.help_table tr td:nth-child(2) { text-align: center; }
.table_group_list {
border-collapse: collapse;
margin: 10px 0px;
}
.table_group_list td {
padding: 0.5em 1em;
border: solid 1px #222;
vertical-align: middle;
}
a.icon-delete {
background: url('global/delete-icon.png') no-repeat center left;
padding-left: 1.5em;
width: 80px;
display: inline-block;
}
a.icon-add {
background: url('global/add-icon.png') no-repeat center left;
padding-left: 1.5em;
}
#control_add {
padding-left: 0.5em;
border-bottom: 1px dotted #000000;
padding-bottom: 0.5em;
}
#control_add select {
display: none;
}
.control_column_left {
width: 48%;
float: left;
}
.control_column_right {
width: 49%;
float: right;
}
.control_save {
border-top: 1px dotted #000000;
padding-top: 0.5em;
clear: both;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -7,8 +7,12 @@
[% title = BLOCK %]
Edit Group Controls for [% product.name FILTER html %]
[% END %]
[% PROCESS global/header.html.tmpl
title = title
[% PROCESS global/header.html.tmpl
title = title
style_urls = ['skins/standard/admin_groupcontrol.css']
javascript_urls = ["js/admin_groupcontrol.js"]
%]
[% control_options = [
@ -21,8 +25,16 @@
[% all_groups = product.group_controls_full_data.values.sort("name") %]
[% groups = product.group_controls.values.sort("name") %]
[% BLOCK control_select %]
[% BLOCK group_select %]
<select name="[% id %]" id="[% id %]">
[% FOR g = all_groups %]
<option value="[% g.id %]" [% " selected=\"selected\"" IF group_id == g.id %]>[% g.name | html %]</option>
[% END %]
</select>
[% END %]
[% BLOCK control_select %]
<select name="[% id %]" id="[% id %]" data-lastvalue="0">
[% FOR i = control_options %]
<option value="[% i %]" [% " selected=\"selected\"" IF control == i %]>[% lc_messages.control_options.$i %]</option>
[% END %]
@ -54,138 +66,10 @@
<option value="[% g.id %]">[% g.name | html %]</option>
[% END %]
</select>
<input type="button" value="Add &rarr;" onclick="addListGroup('[% name %]')" />
<a href="#" class="icon-add" onclick="addListGroup('[% name %]'); return false;">Add new group</a>
</p>
[% END %]
<script language="JavaScript">
function helpToggle(btn_id, div_id)
{
var b = document.getElementById(btn_id);
var d = document.getElementById(div_id);
if (d.style.display == 'none')
{
b.value = 'Hide \u25B4';
d.style.display = '';
}
else
{
b.value = 'Show \u25BE';
d.style.display = 'none';
}
}
function copySelect(prefix, suffix)
{
var o = document.getElementById(prefix+'new');
var e = document.createElement('select');
e.id = e.name = prefix+suffix;
e.innerHTML = o.innerHTML;
e.selectedIndex = o.selectedIndex;
return e;
}
function flashItem(e)
{
var i = 0;
clearTimeout(e.flashIntervalId);
e.style.background = 'red';
e.flashIntervalId = setInterval(function() {
if (++i < 6)
e.style.background = e.style.backgroundColor == 'red' ? '' : 'red';
else
clearTimeout(e.flashIntervalId);
}, 100);
}
function addControlGroup()
{
var group_select = document.getElementById('add_control');
var group_id = group_select.value;
var group_name = group_select.options[group_select.selectedIndex].text;
var added_li = document.getElementById('li_control_'+group_id);
if (added_li)
{
// Flash the already added group entry
document.getElementById('membercontrol_'+group_id).focus();
flashItem(added_li);
return;
}
added_li = document.getElementById('li_control_empty');
if (added_li)
added_li.parentNode.removeChild(added_li);
added_li = document.createElement('li');
added_li.id = 'li_control_'+group_id;
added_li.appendChild(document.createTextNode(group_name + ': '));
added_li.appendChild(copySelect('membercontrol_', group_id));
added_li.appendChild(document.createTextNode(' / '));
added_li.appendChild(copySelect('othercontrol_', group_id));
var list = document.getElementById('control_list');
list.appendChild(added_li);
}
function addListGroup(list_name)
{
var group_select = document.getElementById('add_'+list_name);
var group_id = group_select.value;
var group_name = group_select.options[group_select.selectedIndex].text;
var added_li = document.getElementById('li_'+list_name+'_'+group_id);
if (added_li)
{
// Flash the already added group entry
document.getElementById(list_name+'_'+group_id).focus();
flashItem(added_li);
return;
}
added_li = document.getElementById('li_'+list_name+'_empty');
if (added_li)
added_li.parentNode.removeChild(added_li);
added_li = document.createElement('li');
added_li.id = 'li_'+list_name+'_'+group_id;
var e = document.createElement('input');
e.type = 'checkbox';
e.value = '1';
e.checked = true;
e.name = e.id = list_name+'_'+group_id;
added_li.appendChild(e);
e = document.createElement('label');
e.htmlFor = list_name+'_'+group_id;
e.appendChild(document.createTextNode(' ' + group_name));
added_li.appendChild(e);
var list = document.getElementById(list_name+'_list');
list.appendChild(added_li);
}
</script>
<style>
.group_list
{
list-style-type: none;
padding: 0.3em;
margin: 0 0 1em 1em;
float: left;
border: 1px solid gray;
border-radius: 5px;
background: white;
box-shadow: 0 5px 5px gray;
}
.group_list input, .group_list select { vertical-align: middle; }
.group_list li { padding: 0.25em 0.5em; }
.group_empty { color: gray; }
.help_popup
{
border: 1px solid gray;
border-radius: 5px;
margin: 0 0 1em 0;
padding: 0 1em;
background: white;
box-shadow: 0 5px 5px gray;
}
.help_table { border-collapse: collapse; }
.help_table td, .help_table th { border: 1px solid gray; font-size: 10pt; padding: 2px; }
.help_table tr td:nth-child(1) { text-align: center; }
.help_table tr td:nth-child(2) { text-align: center; }
</style>
<form method="post" action="editproducts.cgi">
<input type="hidden" name="action" value="updategroupcontrols">
@ -194,70 +78,78 @@ function addListGroup(list_name)
<h2>Group controls for product [% product.name | html %]</h2>
<h3>Access control (Member/Other):</h4>
<h3>Access control (Member/Other):</h3>
<p>
Help on Member/Other group control combinations:
<input type="button" id="control_help_btn" value="Show &#x25BE;" onclick="helpToggle(this.id, 'control_help')" />
</p>
<div id="control_help" class="help_popup" style="display: none">
[% PROCESS help_control %]
</div>
<ul id="control_list" class="group_list">
[% foundone = 0 %]
[% cnt_row = 1 %]
<table id="control_list" class="table_group_list">
[% FOR group = groups %]
[% IF group.membercontrol OR group.othercontrol %]
[% foundone = 1 %]
<li id="li_control_[% group.id %]">
[% group.name | html %]:
[%+ PROCESS control_select id='membercontrol_' _ group.id, control=group.membercontrol %] /
[%+ PROCESS control_select id='othercontrol_' _ group.id, control=group.othercontrol %]
(used in [% group.bug_count || 0 %] bugs)
</li>
<tr id="control_[% cnt_row %]">
<td>[%+ PROCESS group_select id='group_' _ cnt_row, group_id=group.id %]</td>
<td>[%+ PROCESS control_select id='membercontrol_' _ cnt_row, control=group.membercontrol %]</td>
<td>[%+ PROCESS control_select id='othercontrol_' _ cnt_row, control=group.othercontrol %]</td>
<td>used in [% group.bug_count || 0 %] bugs</td>
<td><a href="#" class="icon-delete" onclick="deleteGroup(this, [% cnt_row %]); return false;">Delete</a></td>
</tr>
[% cnt_row = cnt_row + 1 %]
[% END %]
[% END %]
[% IF NOT foundone %]
<li id="li_control_empty" class="group_empty">
&lt;no control groups&gt;
</li>
<tr id="control_empty" class="group_empty">
<td colspan="5">
&lt;no control groups&gt;
</td>
</tr>
[% END %]
</ul>
<p style="clear: both">
Add another group:
<select id="add_control">
[% FOR g = all_groups %]
<option value="[% g.id %]">[% g.name | html %]</option>
[% END %]
</select>
with
[%+ PROCESS control_select id='membercontrol_new' control=0 %] /
[%+ PROCESS control_select id='othercontrol_new' control=0 %]
<input type="button" value="Add &rarr;" onclick="addControlGroup()" />
</p>
</table>
<h3>Restrict bug entry to intersection of following groups:</h4>
[% PROCESS help_entry %]
[% PROCESS group_list name='entry' %]
<div id="control_add">
<a href="#" class="icon-add" onclick="addNewGroup(); return false;">Add new group</a>
<h3>Restrict editing and commenting bugs to:</h4>
[% PROCESS help_canedit %]
[% PROCESS group_list name='canedit' %]
<select id="etalon_groups">
[% FOR g = all_groups %]
<option value="[% g.id %]">[% g.name | html %]</option>
[% END %]
</select>
<h3>Allow product and component administration for members of any of the following groups:</h4>
[% PROCESS help_editcomponents %]
[% PROCESS group_list name='editcomponents' %]
[%+ PROCESS control_select id='etalon_control', control=0 %]
</div>
<h3>Allow to confirm bugs for:</h4>
[% PROCESS help_canconfirm %]
[% PROCESS group_list name='canconfirm' %]
<script language="JavaScript">
var count_rows = [% cnt_row %];
</script>
<h3>Allow to change any field of this product bugs for:</h4>
[% PROCESS help_editbugs %]
[% PROCESS group_list name='editbugs' %]
<div class="control_column_left">
<h3>Restrict bug entry to intersection of following groups:</h3>
[% PROCESS help_entry %]
[% PROCESS group_list name='entry' %]
<input type="submit" value="Save changes" />
<h3>Restrict editing and commenting bugs to:</h3>
[% PROCESS help_canedit %]
[% PROCESS group_list name='canedit' %]
</div>
<div class="control_column_right">
<h3>Allow product and component administration for members of any of the following groups:</h3>
[% PROCESS help_editcomponents %]
[% PROCESS group_list name='editcomponents' %]
<h3>Allow to confirm bugs for:</h3>
[% PROCESS help_canconfirm %]
[% PROCESS group_list name='canconfirm' %]
<h3>Allow to change any field of this product bugs for:</h3>
[% PROCESS help_editbugs %]
[% PROCESS group_list name='editbugs' %]
</div>
<div class="control_save">
<input type="submit" value="Save changes" />
</div>
</form>
[% BLOCK help_entry %]
@ -300,6 +192,13 @@ in this group to edit all fields of [% terms.bugs %] in this product.
[% END %]
[% BLOCK help_control %]
<p>
Help on Member/Other group control combinations:
<input type="button" id="control_help_btn" value="Show &#x25BE;" onclick="helpToggle(this.id, 'control_help')" />
</p>
<div id="control_help" class="help_popup" style="display: none">
<p>
Every bug can be 'placed' into number of groups. The more groups bug is placed in,
the more secret it is.
@ -452,6 +351,7 @@ for the <b>MemberControl</b> and <b>OtherControl</b> field settings.
Attempting to submit a combination not listed there (e.g. Mandatory/NA,
Default/Shown, etc.) will produce an error message.
</p>
</div>
[% END %]
[% PROCESS global/footer.html.tmpl %]