Bug 45485, Bug 53617 - Multiple visibility values for fields and values. Рефакнутые, с убранным безумием на 500 строк.
git-svn-id: svn://svn.office.custis.ru/3rdparty/bugzilla.org/trunk@681 6955db30-a419-402b-8a0d-67ecbb4d7f56master
parent
8681814366
commit
44729bd176
|
@ -212,9 +212,10 @@ sub update_params {
|
|||
# --- REMOVE OLD PARAMS ---
|
||||
|
||||
my %oldparams;
|
||||
my %actual = map { $_->{name} => 1 } @param_list;
|
||||
# Remove any old params
|
||||
foreach my $item (keys %$param) {
|
||||
if (!grep($_ eq $item, map ($_->{'name'}, @param_list))) {
|
||||
if (!$actual{$item}) {
|
||||
$oldparams{$item} = $param->{$item};
|
||||
delete $param->{$item};
|
||||
}
|
||||
|
|
|
@ -218,6 +218,8 @@ use constant FIELD_TABLE_SCHEMA => {
|
|||
sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'TRUE'},
|
||||
# CustIS Bug 53617 - visibility_value_id is removed from here
|
||||
# (migrated to fieldvaluecontrol table)
|
||||
],
|
||||
# Note that bz_add_field_table should prepend the table name
|
||||
# to these index names.
|
||||
|
@ -664,10 +666,11 @@ use constant ABSTRACT_SCHEMA => {
|
|||
DEFAULT => 'FALSE'},
|
||||
buglist => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'FALSE'},
|
||||
visibility_field_id => {TYPE => 'INT3',
|
||||
visibility_field_id => {TYPE => 'INT3',
|
||||
REFERENCES => {TABLE => 'fielddefs',
|
||||
COLUMN => 'id'}},
|
||||
visibility_value_id => {TYPE => 'INT2'},
|
||||
# CustIS Bug 53617 - visibility_value_id is removed from here
|
||||
# (migrated to fieldvaluecontrol table)
|
||||
value_field_id => {TYPE => 'INT3',
|
||||
REFERENCES => {TABLE => 'fielddefs',
|
||||
COLUMN => 'id'}},
|
||||
|
@ -730,7 +733,6 @@ use constant ABSTRACT_SCHEMA => {
|
|||
bug_status_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
bug_status_sortkey_idx => ['sortkey', 'value'],
|
||||
bug_status_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
|
@ -740,7 +742,6 @@ use constant ABSTRACT_SCHEMA => {
|
|||
resolution_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
resolution_sortkey_idx => ['sortkey', 'value'],
|
||||
resolution_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
|
@ -750,7 +751,6 @@ use constant ABSTRACT_SCHEMA => {
|
|||
bug_severity_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
bug_severity_sortkey_idx => ['sortkey', 'value'],
|
||||
bug_severity_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
|
@ -760,7 +760,6 @@ use constant ABSTRACT_SCHEMA => {
|
|||
priority_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
priority_sortkey_idx => ['sortkey', 'value'],
|
||||
priority_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
|
@ -770,7 +769,6 @@ use constant ABSTRACT_SCHEMA => {
|
|||
rep_platform_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
rep_platform_sortkey_idx => ['sortkey', 'value'],
|
||||
rep_platform_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
|
@ -780,7 +778,6 @@ use constant ABSTRACT_SCHEMA => {
|
|||
op_sys_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
op_sys_sortkey_idx => ['sortkey', 'value'],
|
||||
op_sys_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
|
|
|
@ -71,13 +71,15 @@ package Bugzilla::Field;
|
|||
use strict;
|
||||
|
||||
use base qw(Exporter Bugzilla::Object);
|
||||
@Bugzilla::Field::EXPORT = qw(check_field get_field_id get_legal_field_values);
|
||||
@Bugzilla::Field::EXPORT = qw(check_field get_field_id get_legal_field_values update_visibility_values);
|
||||
|
||||
use Bugzilla::Constants;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::Util;
|
||||
|
||||
use Scalar::Util qw(blessed);
|
||||
use Encode;
|
||||
use JSON;
|
||||
|
||||
###############################
|
||||
#### Initialization ####
|
||||
|
@ -98,7 +100,6 @@ use constant DB_COLUMNS => qw(
|
|||
enter_bug
|
||||
buglist
|
||||
visibility_field_id
|
||||
visibility_value_id
|
||||
value_field_id
|
||||
);
|
||||
|
||||
|
@ -118,7 +119,6 @@ use constant VALIDATORS => {
|
|||
|
||||
use constant UPDATE_VALIDATORS => {
|
||||
value_field_id => \&_check_value_field_id,
|
||||
visibility_value_id => \&_check_control_value,
|
||||
};
|
||||
|
||||
use constant UPDATE_COLUMNS => qw(
|
||||
|
@ -129,7 +129,6 @@ use constant UPDATE_COLUMNS => qw(
|
|||
enter_bug
|
||||
buglist
|
||||
visibility_field_id
|
||||
visibility_value_id
|
||||
value_field_id
|
||||
|
||||
type
|
||||
|
@ -340,22 +339,6 @@ sub _check_visibility_field_id {
|
|||
return $field->id;
|
||||
}
|
||||
|
||||
sub _check_control_value {
|
||||
my ($invocant, $value_id, $field_id) = @_;
|
||||
my $field;
|
||||
if (blessed $invocant) {
|
||||
$field = $invocant->visibility_field;
|
||||
}
|
||||
elsif ($field_id) {
|
||||
$field = $invocant->new($field_id);
|
||||
}
|
||||
# When no field is set, no value is set.
|
||||
return undef if !$field;
|
||||
my $value_obj = Bugzilla::Field::Choice->type($field)
|
||||
->check({ id => $value_id });
|
||||
return $value_obj->id;
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=head2 Instance Properties
|
||||
|
@ -486,9 +469,9 @@ objects.
|
|||
|
||||
=cut
|
||||
|
||||
sub is_select {
|
||||
return ($_[0]->type == FIELD_TYPE_SINGLE_SELECT
|
||||
|| $_[0]->type == FIELD_TYPE_MULTI_SELECT) ? 1 : 0
|
||||
sub is_select {
|
||||
return ($_[0]->type == FIELD_TYPE_SINGLE_SELECT
|
||||
|| $_[0]->type == FIELD_TYPE_MULTI_SELECT) ? 1 : 0
|
||||
}
|
||||
|
||||
sub legal_values {
|
||||
|
@ -505,9 +488,9 @@ sub legal_values {
|
|||
sub restricted_legal_values
|
||||
{
|
||||
my $self = shift;
|
||||
my ($value) = @_;
|
||||
return $self->legal_values unless $value;
|
||||
return $value->controlled_plus_generic->{$self->name};
|
||||
my ($controller_value) = @_;
|
||||
return $self->legal_values unless $controller_value;
|
||||
return $controller_value->controlled_plus_generic->{$self->name};
|
||||
}
|
||||
|
||||
=pod
|
||||
|
@ -528,36 +511,50 @@ Returns undef if there is no field that controls this field's visibility.
|
|||
sub visibility_field {
|
||||
my $self = shift;
|
||||
if ($self->{visibility_field_id}) {
|
||||
$self->{visibility_field} ||=
|
||||
$self->{visibility_field} ||=
|
||||
$self->new($self->{visibility_field_id});
|
||||
}
|
||||
return $self->{visibility_field};
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=over
|
||||
|
||||
=item C<visibility_value>
|
||||
|
||||
If we have a L</visibility_field>, then what value does that field have to
|
||||
be set to in order to show this field? Returns a L<Bugzilla::Field::Choice>
|
||||
or undef if there is no C<visibility_field> set.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
sub visibility_value {
|
||||
sub visibility_values
|
||||
{
|
||||
my $self = shift;
|
||||
if ($self->{visibility_field_id}) {
|
||||
require Bugzilla::Field::Choice;
|
||||
$self->{visibility_value} ||=
|
||||
Bugzilla::Field::Choice->type($self->visibility_field)->new(
|
||||
$self->{visibility_value_id});
|
||||
my $f;
|
||||
if ($self->visibility_field && !($f = $self->{visibility_values}))
|
||||
{
|
||||
$f = Bugzilla->dbh->selectcol_arrayref(
|
||||
"SELECT visibility_value_id FROM fieldvaluecontrol WHERE field_id=? AND value_id=0",
|
||||
undef, $self->id);
|
||||
if (@$f)
|
||||
{
|
||||
my $type = Bugzilla::Field::Choice->type($self->visibility_field);
|
||||
$f = $type->match({ id => $f });
|
||||
}
|
||||
$self->{visibility_values} = $f;
|
||||
}
|
||||
return $self->{visibility_value};
|
||||
return $f;
|
||||
}
|
||||
|
||||
sub has_visibility_value
|
||||
{
|
||||
my $self = shift;
|
||||
my ($value) = @_;
|
||||
ref $value and $value = $value->id;
|
||||
my %f = map { $_->id => 1 } @{$self->visibility_values};
|
||||
return $f{$value};
|
||||
}
|
||||
|
||||
# Check visibility of field for a bug
|
||||
sub check_visibility
|
||||
{
|
||||
my $self = shift;
|
||||
my ($bug) = @_;
|
||||
my $field = $self->visibility_field;
|
||||
$bug && $field or return 1;
|
||||
$field = $bug->{$field->name};
|
||||
my %f = map { $_->name => 1 } @{$self->visibility_values};
|
||||
return $f{$field};
|
||||
}
|
||||
|
||||
=pod
|
||||
|
@ -575,7 +572,7 @@ field controls the visibility of.
|
|||
|
||||
sub controls_visibility_of {
|
||||
my $self = shift;
|
||||
$self->{controls_visibility_of} ||=
|
||||
$self->{controls_visibility_of} ||=
|
||||
Bugzilla::Field->match({ visibility_field_id => $self->id });
|
||||
return $self->{controls_visibility_of};
|
||||
}
|
||||
|
@ -648,8 +645,6 @@ They will throw an error if you try to set the values to something invalid.
|
|||
|
||||
=item C<set_visibility_field>
|
||||
|
||||
=item C<set_visibility_value>
|
||||
|
||||
=item C<set_value_field>
|
||||
|
||||
=back
|
||||
|
@ -662,18 +657,26 @@ sub set_obsolete { $_[0]->set('obsolete', $_[1]); }
|
|||
sub set_sortkey { $_[0]->set('sortkey', $_[1]); }
|
||||
sub set_in_new_bugmail { $_[0]->set('mailhead', $_[1]); }
|
||||
sub set_buglist { $_[0]->set('buglist', $_[1]); }
|
||||
sub set_visibility_field {
|
||||
|
||||
sub set_visibility_field
|
||||
{
|
||||
my ($self, $value) = @_;
|
||||
$self->set('visibility_field_id', $value);
|
||||
delete $self->{visibility_field};
|
||||
delete $self->{visibility_value};
|
||||
delete $self->{visibility_values};
|
||||
}
|
||||
sub set_visibility_value {
|
||||
my ($self, $value) = @_;
|
||||
$self->set('visibility_value_id', $value);
|
||||
delete $self->{visibility_value};
|
||||
|
||||
sub set_visibility_values
|
||||
{
|
||||
my $self = shift;
|
||||
my ($value_ids) = @_;
|
||||
update_visibility_values($self->visibility_field, $self, 0, $self->visibility_values, $value_ids);
|
||||
delete $self->{visibility_values};
|
||||
return @$value_ids;
|
||||
}
|
||||
sub set_value_field {
|
||||
|
||||
sub set_value_field
|
||||
{
|
||||
my ($self, $value) = @_;
|
||||
$self->set('value_field_id', $value);
|
||||
delete $self->{value_field};
|
||||
|
@ -760,7 +763,9 @@ sub remove_from_db {
|
|||
$dbh->bz_drop_field_tables($self);
|
||||
}
|
||||
|
||||
$dbh->bz_commit_transaction()
|
||||
$self->set_visibility_values(undef);
|
||||
|
||||
$dbh->bz_commit_transaction();
|
||||
}
|
||||
|
||||
=pod
|
||||
|
@ -839,10 +844,6 @@ sub run_create_validators {
|
|||
"SELECT MAX(sortkey) + 100 FROM fielddefs") || 100;
|
||||
}
|
||||
|
||||
$params->{visibility_value_id} =
|
||||
$class->_check_control_value($params->{visibility_value_id},
|
||||
$params->{visibility_field_id});
|
||||
|
||||
my $type = $params->{type} || 0;
|
||||
$params->{value_field_id} =
|
||||
$class->_check_value_field_id($params->{value_field_id},
|
||||
|
@ -851,17 +852,6 @@ sub run_create_validators {
|
|||
return $params;
|
||||
}
|
||||
|
||||
sub update {
|
||||
my $self = shift;
|
||||
my $changes = $self->SUPER::update(@_);
|
||||
my $dbh = Bugzilla->dbh;
|
||||
if ($changes->{value_field_id} && $self->is_select) {
|
||||
$dbh->do("UPDATE " . $self->name . " SET visibility_value_id = NULL");
|
||||
}
|
||||
return $changes;
|
||||
}
|
||||
|
||||
|
||||
=pod
|
||||
|
||||
=over
|
||||
|
@ -1089,6 +1079,66 @@ sub get_field_id {
|
|||
return $id
|
||||
}
|
||||
|
||||
# Shared between Bugzilla::Field and Bugzilla::Field::Choice
|
||||
sub update_visibility_values
|
||||
{
|
||||
my ($controller_field, $controlled_field, $controlled_value, $old_ids, $value_ids) = @_;
|
||||
Bugzilla->dbh->do(
|
||||
"DELETE FROM fieldvaluecontrol WHERE field_id=? AND value_id=?",
|
||||
undef, $controlled_field->id, $controlled_value);
|
||||
defined($value_ids) or return undef;
|
||||
ref $value_ids or $value_ids = [ $value_ids ];
|
||||
my $type = Bugzilla::Field::Choice->type($controller_field);
|
||||
@$value_ids = map { $_ ? $type->check({ id => $_ }) : () } @$value_ids;
|
||||
my ($a, $r) = diff_arrays([map { $_->id } @$value_ids], [map { $_->id } @$old_ids]);
|
||||
if (@$value_ids)
|
||||
{
|
||||
Bugzilla->dbh->do(
|
||||
"INSERT INTO fieldvaluecontrol (field_id, value_id, visibility_value_id) VALUES ".
|
||||
join(",", ("(?,?,?)") x @$value_ids),
|
||||
undef, map { ($controlled_field->id, $controlled_value, $_->id) } @$value_ids);
|
||||
}
|
||||
}
|
||||
|
||||
# Moved from bug/field-events.js.tmpl
|
||||
sub json_visibility
|
||||
{
|
||||
my $self = shift;
|
||||
my $show = { fields => {}, values => {} };
|
||||
foreach my $controlled (@{$self->controls_visibility_of})
|
||||
{
|
||||
$show->{fields}->{$controlled->name} = { map { $_->id => 1 } @{$controlled->visibility_values} };
|
||||
}
|
||||
$show->{legal} = [ map { [ $_->id, $_->name ] } @{$self->legal_values} ];
|
||||
foreach my $value (@{$self->legal_values})
|
||||
{
|
||||
foreach my $controlled_field (keys %{$value->controlled_values})
|
||||
{
|
||||
foreach my $controlled_value (@{$value->controlled_values->{$controlled_field}})
|
||||
{
|
||||
$show->{values}->{$controlled_field}->{$controlled_value->id}->{$value->id} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
$show = encode_json($show);
|
||||
Encode::_utf8_on($show);
|
||||
return $show;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
[% FOREACH controlled_field = field.controls_visibility_of %]
|
||||
[% FOREACH val = controlled_field.visibility_values %]
|
||||
showFieldWhen['[% field.name | js %]']['[% val.name | js %]']['[% controlled_field.name | js %]'] = true;
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
[% FOREACH legal_value = field.legal_values %]
|
||||
[% FOREACH controlled_field = legal_value.controlled_plus_generic.keys %]
|
||||
[% FOREACH val = legal_value.controlled_plus_generic.$controlled_field %]
|
||||
showValueWhen['[% field.name | js %]'][[% val.id %]]['[% controlled_field | js %]'][[% legal_value.id %]] = true;
|
||||
[% END %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
|
|
@ -193,7 +193,7 @@ sub remove_from_db {
|
|||
{ field => $self->field, value => $self });
|
||||
}
|
||||
$self->_check_if_controller();
|
||||
$self->set_visibility_values([]);
|
||||
$self->set_visibility_values(undef);
|
||||
$self->SUPER::remove_from_db();
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ sub _check_if_controller {
|
|||
my $self = shift;
|
||||
my $vis_fields = $self->controls_visibility_of_fields;
|
||||
my $values = $self->controlled_values;
|
||||
if (@$vis_fields || scalar(keys %$values)) {
|
||||
if (@$vis_fields || scalar grep { @{$values->{$_}} } keys %$values) {
|
||||
ThrowUserError('fieldvalue_is_controller',
|
||||
{ value => $self, fields => [map($_->name, @$vis_fields)],
|
||||
vals => $values });
|
||||
|
@ -269,89 +269,101 @@ sub is_static {
|
|||
return 0;
|
||||
}
|
||||
|
||||
sub controls_visibility_of_fields {
|
||||
sub controls_visibility_of_fields
|
||||
{
|
||||
my $self = shift;
|
||||
$self->{controls_visibility_of_fields} ||= Bugzilla::Field->match(
|
||||
{ visibility_field_id => $self->field->id,
|
||||
visibility_value_id => $self->id });
|
||||
return $self->{controls_visibility_of_fields};
|
||||
my $f;
|
||||
unless ($f = $self->{controls_visibility_of_fields})
|
||||
{
|
||||
$f = Bugzilla->dbh->selectcol_arrayref(
|
||||
"SELECT f.id FROM fielddefs f, fieldvaluecontrol c WHERE c.field_id=f.id".
|
||||
" AND f.visibility_field_id=? AND c.visibility_value_id=? AND c.value_id=0",
|
||||
undef, $self->field->id, $self->id
|
||||
);
|
||||
$f = Bugzilla::Field->match({ id => $f });
|
||||
$self->{controls_visibility_of_fields} = $f;
|
||||
}
|
||||
return $f;
|
||||
}
|
||||
|
||||
sub controlled_values
|
||||
{
|
||||
my $self = shift;
|
||||
return $self->{controlled_values} if defined $self->{controlled_values};
|
||||
my $fields = $self->field->controls_values_of;
|
||||
my %controlled_values;
|
||||
# TODO move this into Bugzilla::Field::Choice::match() with MATCH_JOIN
|
||||
# but no MATCH_JOIN by now is available
|
||||
foreach my $field (@$fields) {
|
||||
my $type = Bugzilla::Field::Choice->type($field);
|
||||
my $sql =
|
||||
"SELECT f.".join(", f.", $type->DB_COLUMNS).
|
||||
" FROM fieldvaluecontrol c, ".$type->DB_TABLE." f".
|
||||
" WHERE c.field_id=? AND c.visibility_value_id=? AND c.value_id=f.id".
|
||||
" ORDER BY f.sortkey";
|
||||
# Обходим самозарождение греха при конкатенации DB_COLUMNS и DB_TABLE
|
||||
trick_taint($sql);
|
||||
my $f = Bugzilla->dbh->selectall_arrayref($sql, {Slice=>{}}, $field->id, $self->id) || [];
|
||||
$f = [ map { bless $_, $type } @$f ];
|
||||
$controlled_values{$field->name} = $f;
|
||||
my $controlled_values;
|
||||
unless ($controlled_values = $self->{controlled_values})
|
||||
{
|
||||
$controlled_values = {};
|
||||
my $fields = $self->field->controls_values_of;
|
||||
foreach my $field (@$fields)
|
||||
{
|
||||
my $f = Bugzilla->dbh->selectcol_arrayref(
|
||||
"SELECT value_id FROM fieldvaluecontrol WHERE field_id=? AND visibility_value_id=? AND value_id!=0",
|
||||
undef, $field->id, $self->id);
|
||||
if (@$f)
|
||||
{
|
||||
my $type = Bugzilla::Field::Choice->type($field);
|
||||
$f = $type->match({ id => $f });
|
||||
}
|
||||
$controlled_values->{$field->name} = $f;
|
||||
}
|
||||
$self->{controlled_values} = $controlled_values;
|
||||
}
|
||||
$self->{controlled_values} = \%controlled_values;
|
||||
return $self->{controlled_values};
|
||||
return $controlled_values;
|
||||
}
|
||||
|
||||
sub controlled_plus_generic
|
||||
{
|
||||
my $self = shift;
|
||||
return $self->{controlled_plus_generic} if defined $self->{controlled_plus_generic};
|
||||
my $fields = $self->field->controls_values_of;
|
||||
my %controlled_values;
|
||||
# TODO move this into Bugzilla::Field::Choice::match() with MATCH_JOIN
|
||||
# but no MATCH_JOIN by now is available
|
||||
foreach my $field (@$fields) {
|
||||
my $type = Bugzilla::Field::Choice->type($field);
|
||||
my $sql =
|
||||
"(SELECT f.".join(", f.", $type->DB_COLUMNS).
|
||||
" FROM fieldvaluecontrol c, ".$type->DB_TABLE." f".
|
||||
" WHERE c.field_id=? AND c.visibility_value_id=? AND c.value_id=f.id)".
|
||||
" UNION ALL (SELECT f.".join(", f.", $type->DB_COLUMNS).
|
||||
" FROM ".$type->DB_TABLE." f LEFT JOIN fieldvaluecontrol c ON c.value_id=f.id AND c.field_id=?".
|
||||
" WHERE c.field_id IS NULL)".
|
||||
" ORDER BY sortkey";
|
||||
# Обходим самозарождение греха при конкатенации DB_COLUMNS и DB_TABLE
|
||||
trick_taint($sql);
|
||||
my $f = Bugzilla->dbh->selectall_arrayref($sql, {Slice=>{}}, $field->id, $self->id, $field->id) || [];
|
||||
$f = [ map { bless $_, $type } @$f ];
|
||||
$controlled_values{$field->name} = $f;
|
||||
my $controlled_values;
|
||||
unless ($controlled_values = $self->{controlled_plus_generic})
|
||||
{
|
||||
my $fields = $self->field->controls_values_of;
|
||||
foreach my $field (@$fields)
|
||||
{
|
||||
my $f = Bugzilla->dbh->selectcol_arrayref(
|
||||
"SELECT value_id FROM fieldvaluecontrol WHERE field_id=? AND visibility_value_id=? AND value_id!=0
|
||||
UNION ALL SELECT id FROM ".$field->name." f LEFT JOIN fieldvaluecontrol c ON c.value_id=f.id AND c.field_id=? WHERE c.visibility_value_id IS NULL",
|
||||
undef, $field->id, $self->id, $field->id);
|
||||
if (@$f)
|
||||
{
|
||||
my $type = Bugzilla::Field::Choice->type($field);
|
||||
$f = $type->match({ id => $f });
|
||||
}
|
||||
$controlled_values->{$field->name} = $f;
|
||||
}
|
||||
$self->{controlled_plus_generic} = $controlled_values;
|
||||
}
|
||||
$self->{controlled_plus_generic} = \%controlled_values;
|
||||
return $self->{controlled_plus_generic};
|
||||
return $controlled_values;
|
||||
}
|
||||
|
||||
sub visibility_values
|
||||
{
|
||||
my $self = shift;
|
||||
my $f;
|
||||
unless ($f = $self->{visibility_values})
|
||||
if ($self->field->value_field && !($f = $self->{visibility_values}))
|
||||
{
|
||||
# TODO move this into Bugzilla::Field::Choice::match() with MATCH_JOIN
|
||||
# but no MATCH_JOIN by now is available
|
||||
my $type = Bugzilla::Field::Choice->type($self->field->value_field);
|
||||
my $sql =
|
||||
"SELECT f.".join(", f.", $type->DB_COLUMNS).
|
||||
" FROM fieldvaluecontrol c, ".$type->DB_TABLE." f".
|
||||
" WHERE c.field_id=? AND c.visibility_value_id=f.id AND c.value_id=?";
|
||||
# Обходим самозарождение греха при конкатенации DB_COLUMNS и DB_TABLE
|
||||
trick_taint($sql);
|
||||
$f = Bugzilla->dbh->selectall_arrayref($sql, {Slice=>{}}, $self->field->id, $self->id) || [];
|
||||
$f = [ map { bless $_, $type } @$f ];
|
||||
$f = Bugzilla->dbh->selectcol_arrayref(
|
||||
"SELECT visibility_value_id FROM fieldvaluecontrol WHERE field_id=? AND value_id=?",
|
||||
undef, $self->field->id, $self->id);
|
||||
if (@$f)
|
||||
{
|
||||
my $type = Bugzilla::Field::Choice->type($self->field->value_field);
|
||||
$f = $type->match({ id => $f });
|
||||
}
|
||||
$self->{visibility_values} = $f;
|
||||
}
|
||||
return $f;
|
||||
}
|
||||
|
||||
sub has_visibility_value
|
||||
{
|
||||
my $self = shift;
|
||||
my ($value) = @_;
|
||||
ref $value and $value = $value->id;
|
||||
my %f = map { $_->id => 1 } @{$self->visibility_values};
|
||||
return $f{$value};
|
||||
}
|
||||
|
||||
############
|
||||
# Mutators #
|
||||
############
|
||||
|
@ -363,21 +375,7 @@ sub set_visibility_values
|
|||
{
|
||||
my $self = shift;
|
||||
my ($value_ids) = @_;
|
||||
return undef if !ref $value_ids || $value_ids !~ 'ARRAY';
|
||||
my $type = Bugzilla::Field::Choice->type($self->field->value_field);
|
||||
@$value_ids = map { $_ ? $type->check({ id => $_ }) : () } @$value_ids;
|
||||
my ($a, $r) = diff_arrays([map { $_->id } @$value_ids], [map { $_->id } @{$self->visibility_values}]);
|
||||
return undef unless @$a || @$r;
|
||||
Bugzilla->dbh->do(
|
||||
"DELETE FROM fieldvaluecontrol WHERE field_id=? AND value_id=?",
|
||||
undef, $self->field->id, $self->id);
|
||||
if (@$value_ids)
|
||||
{
|
||||
Bugzilla->dbh->do(
|
||||
"INSERT INTO fieldvaluecontrol (field_id, value_id, visibility_value_id) VALUES ".
|
||||
join(",", ("(?,?,?)") x @$value_ids),
|
||||
undef, map { ($self->field->id, $self->id, $_->id) } @$value_ids);
|
||||
}
|
||||
update_visibility_values($self->field->value_field, $self->field, $self->id, $self->visibility_values, $value_ids);
|
||||
delete $self->{visibility_values};
|
||||
return @$value_ids;
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ sub update_fielddefs_definition {
|
|||
}
|
||||
|
||||
$dbh->bz_add_column('fielddefs', 'visibility_field_id', {TYPE => 'INT3'});
|
||||
$dbh->bz_add_column('fielddefs', 'visibility_value_id', {TYPE => 'INT2'});
|
||||
# visibility_value_id is not added anymore during update - it's now in fieldvaluecontrol
|
||||
$dbh->bz_add_column('fielddefs', 'value_field_id', {TYPE => 'INT3'});
|
||||
$dbh->bz_add_index('fielddefs', 'fielddefs_value_field_id_idx',
|
||||
['value_field_id']);
|
||||
|
|
|
@ -55,6 +55,7 @@ use File::Find;
|
|||
use File::Path qw(rmtree mkpath);
|
||||
use File::Spec;
|
||||
use IO::Dir;
|
||||
use JSON;
|
||||
|
||||
use base qw(Template);
|
||||
|
||||
|
@ -530,6 +531,11 @@ sub create {
|
|||
return $var;
|
||||
},
|
||||
|
||||
json => sub {
|
||||
my ($var) = @_;
|
||||
return encode_json($var);
|
||||
},
|
||||
|
||||
# Converts data to base64
|
||||
base64 => sub {
|
||||
my ($data) = @_;
|
||||
|
|
|
@ -56,7 +56,7 @@ elsif ($action eq 'add') {
|
|||
elsif ($action eq 'new') {
|
||||
check_token_data($token, 'add_field');
|
||||
|
||||
$vars->{'field'} = Bugzilla::Field->create({
|
||||
my $field = $vars->{'field'} = Bugzilla::Field->create({
|
||||
name => scalar $cgi->param('name'),
|
||||
description => scalar $cgi->param('desc'),
|
||||
type => scalar $cgi->param('type'),
|
||||
|
@ -67,9 +67,9 @@ elsif ($action eq 'new') {
|
|||
custom => 1,
|
||||
buglist => (scalar $cgi->param('type') == FIELD_TYPE_MULTI_SELECT ? 0 : 1),
|
||||
visibility_field_id => scalar $cgi->param('visibility_field_id'),
|
||||
visibility_value_id => scalar $cgi->param('visibility_value_id'),
|
||||
value_field_id => scalar $cgi->param('value_field_id'),
|
||||
});
|
||||
$field->set_visibility_values([ $cgi->param('visibility_value_id') ]);
|
||||
|
||||
delete_token($token);
|
||||
|
||||
|
@ -108,7 +108,7 @@ elsif ($action eq 'update') {
|
|||
# At the moment, though, it has no effect for non-custom fields.
|
||||
$field->set_enter_bug($cgi->param('enter_bug'));
|
||||
$field->set_visibility_field($cgi->param('visibility_field_id'));
|
||||
$field->set_visibility_value($cgi->param('visibility_value_id'));
|
||||
$field->set_visibility_values([ $cgi->param('visibility_value_id') ]);
|
||||
$field->set_value_field($cgi->param('value_field_id'));
|
||||
}
|
||||
$field->update();
|
||||
|
|
|
@ -105,26 +105,40 @@ if (!$dbh->bz_column_info('components', 'default_version'))
|
|||
}
|
||||
|
||||
# Bug 53617 - Ограничение Custom Fields двумя и более значениями контролирующего поля
|
||||
my @standard_fields =
|
||||
qw(bug_status resolution priority bug_severity op_sys rep_platform);
|
||||
my $custom_fields = $dbh->selectcol_arrayref(
|
||||
'SELECT name FROM fielddefs WHERE custom = 1 AND type IN (?,?)',
|
||||
undef, FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT);
|
||||
foreach my $field (@standard_fields, @$custom_fields)
|
||||
my @standard_fields = qw(bug_status resolution priority bug_severity op_sys rep_platform);
|
||||
my $custom_fields = $dbh->selectall_arrayref(
|
||||
'SELECT * FROM fielddefs WHERE (custom=1 AND type IN (?,?)) OR name IN ('.
|
||||
join(',',('?') x @standard_fields).')', {Slice=>{}},
|
||||
FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT, @standard_fields);
|
||||
foreach my $field (@$custom_fields)
|
||||
{
|
||||
next unless $dbh->bz_table_info($field);
|
||||
if ($dbh->bz_column_info($field, 'visibility_value_id'))
|
||||
if ($dbh->bz_table_info($field->{name}) &&
|
||||
$dbh->bz_column_info($field->{name}, 'visibility_value_id'))
|
||||
{
|
||||
print "Migrating $field visibility_value_id into fieldvaluecontrol\n";
|
||||
print "Migrating $field->{name}'s visibility_value_id into fieldvaluecontrol\n";
|
||||
$dbh->do(
|
||||
"REPLACE INTO fieldvaluecontrol (field_id, visibility_value_id, value_id)".
|
||||
" SELECT f.id, v.visibility_value_id, v.id FROM fielddefs f, $field v".
|
||||
" WHERE f.name=? AND v.visibility_value_id IS NOT NULL", undef, $field);
|
||||
# Пока не удаляем никаких колонок
|
||||
#$dbh->bz_drop_column($field, 'visibility_value_id');
|
||||
" SELECT f.id, v.visibility_value_id, v.id FROM fielddefs f, `$field->{name}` v".
|
||||
" WHERE f.name=? AND v.visibility_value_id IS NOT NULL", undef, $field->{name});
|
||||
print "Making backup of table $field->{name}\n";
|
||||
$dbh->do("CREATE TABLE `backup_$field->{name}_".time."` AS SELECT * FROM `$field->{name}`");
|
||||
print "Dropping column $field->{name}.visibility_value_id\n";
|
||||
#$dbh->bz_drop_column($field->{name}, 'visibility_value_id');
|
||||
}
|
||||
}
|
||||
|
||||
if ($dbh->bz_column_info('fielddefs', 'visibility_value_id'))
|
||||
{
|
||||
print "Migrating fielddefs's visibility_value_id into fieldvaluecontrol\n";
|
||||
$dbh->do(
|
||||
"REPLACE INTO fieldvaluecontrol (field_id, visibility_value_id, value_id)".
|
||||
" SELECT id, visibility_value_id, 0 FROM fielddefs WHERE visibility_value_id IS NOT NULL");
|
||||
print "Making backup of table fielddefs\n";
|
||||
$dbh->do("CREATE TABLE `backup_fielddefs_".time."` AS SELECT * FROM fielddefs");
|
||||
print "Dropping column fielddefs.visibility_value_id\n";
|
||||
#$dbh->bz_drop_column('fielddefs', 'visibility_value_id');
|
||||
}
|
||||
|
||||
# Testopia:
|
||||
if ($dbh->bz_table_info('test_fielddefs'))
|
||||
{
|
||||
|
|
|
@ -164,29 +164,30 @@ sub fetch_wiki_category_xml
|
|||
$_[0] = $wiki_url;
|
||||
my $uri = URI->new($wiki_url . '?title=Special:Export&action=submit')->canonical;
|
||||
# Дёргаем Special:Export и вытаскиваем список страниц категории
|
||||
utf8::decode($category);
|
||||
utf8::encode($category);
|
||||
my $response = $ua->request(POST "$uri", [ addcat => 'Add', catname => $category, closure => 1 ]);
|
||||
my $r = POST "$uri", Content => "addcat=Add&catname=".url_quote($category)."&closure=1";
|
||||
my $response = $ua->request($r);
|
||||
if (!$response->is_success)
|
||||
{
|
||||
# TODO показать ошибку
|
||||
die "Could not POST $uri addcat=Добавить&catname=$category: ".$response->status_line;
|
||||
die "Could not POST $uri addcat=Add&catname=$category: ".$response->status_line;
|
||||
}
|
||||
my $text = $response->content;
|
||||
($text) = $text =~ m!<textarea[^<>]*>(.*?)</textarea>!iso;
|
||||
decode_entities($text);
|
||||
utf8::decode($text);
|
||||
utf8::encode($text);
|
||||
decode_entities($text);
|
||||
# Дёргаем Special:Export и вытаскиваем саму XML-ку с последними ревизиями
|
||||
$response = $ua->request(POST $uri, [
|
||||
wpDownload => 1,
|
||||
curonly => 1,
|
||||
pages => $text,
|
||||
]);
|
||||
$response = $ua->request(POST $uri, Content => "wpDownload=1&curonly=1&pages=".url_quote($text));
|
||||
if (!$response->is_success)
|
||||
{
|
||||
# TODO показать ошибку
|
||||
die "Could not retrieve export XML file: ".$response->status_line;
|
||||
}
|
||||
return $response->content;
|
||||
my $xml = $response->content;
|
||||
if ($xml !~ /<\?\s*xml/so)
|
||||
{
|
||||
my ($line) = $xml =~ /^\s*([^\n]*)/so;
|
||||
# TODO показать ошибку
|
||||
die "Could not retrieve export XML file, got $line instead";
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
Bugzilla->hook_args->{panel_modules}->{Testopia} = 'extensions::testopia::lib::Testopia::Config';
|
275
js/field.js
275
js/field.js
|
@ -21,6 +21,99 @@
|
|||
/* This library assumes that the needed YUI libraries have been loaded
|
||||
already. */
|
||||
|
||||
var show_fields = {};
|
||||
YAHOO.util.Event.addListener(window, 'load', initControlledFields);
|
||||
|
||||
function initControlledFields()
|
||||
{
|
||||
for (var i in show_fields)
|
||||
initControlledField(i);
|
||||
}
|
||||
|
||||
function initControlledField(i)
|
||||
{
|
||||
var f = document.getElementById(i);
|
||||
YAHOO.util.Event.addListener(f, 'change', handleControllerField, f);
|
||||
}
|
||||
|
||||
function getSelectedIds(sel)
|
||||
{
|
||||
var lm = sel.id.length+2;
|
||||
var opt = {};
|
||||
for (var i = 0; i < sel.options.length; i++)
|
||||
{
|
||||
if (sel.options[i].selected)
|
||||
{
|
||||
id = sel.options[i].id;
|
||||
opt[id.substr(1, id.length-lm)] = true;
|
||||
}
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
|
||||
function handleControllerField(e, controller)
|
||||
{
|
||||
var vis, label_container, field_container, id;
|
||||
var opt = getSelectedIds(controller);
|
||||
for (var controlled_id in show_fields[controller.id]['fields'])
|
||||
{
|
||||
vis = false;
|
||||
for (var value in show_fields[controller.id]['fields'][controlled_id])
|
||||
{
|
||||
if (opt[value])
|
||||
{
|
||||
vis = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
label_container = document.getElementById('field_label_' + controlled_id);
|
||||
field_container = document.getElementById('field_container_' + controlled_id);
|
||||
if (vis)
|
||||
{
|
||||
YAHOO.util.Dom.removeClass(label_container, 'bz_hidden_field');
|
||||
YAHOO.util.Dom.removeClass(field_container, 'bz_hidden_field');
|
||||
}
|
||||
else
|
||||
{
|
||||
YAHOO.util.Dom.addClass(label_container, 'bz_hidden_field');
|
||||
YAHOO.util.Dom.addClass(field_container, 'bz_hidden_field');
|
||||
}
|
||||
}
|
||||
var item, controlled, copt, controlled_value;
|
||||
for (var controlled_id in show_fields[controller.id]['values'])
|
||||
{
|
||||
controlled = document.getElementById(controlled_id);
|
||||
copt = getSelectedIds(controlled);
|
||||
bz_clearOptions(controlled);
|
||||
for (var i in show_fields[controlled.id]['legal'])
|
||||
{
|
||||
controlled_value = show_fields[controlled.id]['legal'][i];
|
||||
vis = false;
|
||||
item = show_fields[controller.id]['values'][controlled_id][controlled_value[0]];
|
||||
if (!item)
|
||||
vis = true;
|
||||
else
|
||||
{
|
||||
for (var value in item)
|
||||
{
|
||||
if (opt[value])
|
||||
{
|
||||
vis = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vis)
|
||||
{
|
||||
item = bz_createOptionInSelect(controlled, controlled_value[1], controlled_value[1]);
|
||||
item.id = 'v'+controlled_value[0]+'_'+controlled_id;
|
||||
if (copt[controlled_value[0]])
|
||||
item.selected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createCalendar(name) {
|
||||
var cal = new YAHOO.widget.Calendar('calendar_' + name,
|
||||
'con_calendar_' + name);
|
||||
|
@ -373,190 +466,8 @@ function updateCommentTagControl(checkbox, form) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Says that a field should only be displayed when another field has
|
||||
* a certain value. May only be called after the controller has already
|
||||
* been added to the DOM.
|
||||
*/
|
||||
function showFieldWhen(controlled_id, controller_id, value) {
|
||||
var controller = document.getElementById(controller_id);
|
||||
// Note that we don't get an object for "controlled" here, because it
|
||||
// might not yet exist in the DOM. We just pass along its id.
|
||||
YAHOO.util.Event.addListener(controller, 'change',
|
||||
handleVisControllerValueChange, [controlled_id, controller, value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by showFieldWhen when a field's visibility controller
|
||||
* changes values.
|
||||
*/
|
||||
function handleVisControllerValueChange(e, args) {
|
||||
var controlled_id = args[0];
|
||||
var controller = args[1];
|
||||
var value = args[2];
|
||||
|
||||
var label_container =
|
||||
document.getElementById('field_label_' + controlled_id);
|
||||
var field_container =
|
||||
document.getElementById('field_container_' + controlled_id);
|
||||
if (bz_valueSelected(controller, value)) {
|
||||
YAHOO.util.Dom.removeClass(label_container, 'bz_hidden_field');
|
||||
YAHOO.util.Dom.removeClass(field_container, 'bz_hidden_field');
|
||||
}
|
||||
else {
|
||||
YAHOO.util.Dom.addClass(label_container, 'bz_hidden_field');
|
||||
YAHOO.util.Dom.addClass(field_container, 'bz_hidden_field');
|
||||
}
|
||||
}
|
||||
|
||||
function showValueWhen(controlled_field_id, controlled_value_ids,
|
||||
controller_field_id, controller_value_id)
|
||||
{
|
||||
var controller_field = document.getElementById(controller_field_id);
|
||||
// Note that we don't get an object for the controlled field here,
|
||||
// because it might not yet exist in the DOM. We just pass along its id.
|
||||
YAHOO.util.Event.addListener(controller_field, 'change',
|
||||
handleValControllerChange, [controlled_field_id, controlled_value_ids,
|
||||
controller_field, controller_value_id]);
|
||||
}
|
||||
|
||||
function handleValControllerChange(e, args) {
|
||||
var controlled_field = document.getElementById(args[0]);
|
||||
var controlled_value_ids = args[1];
|
||||
var controller_field = args[2];
|
||||
var controller_value_id = args[3];
|
||||
|
||||
var controller_item = document.getElementById(
|
||||
_value_id(controller_field.id, controller_value_id));
|
||||
|
||||
for (var i = 0; i < controlled_value_ids.length; i++) {
|
||||
var item = getPossiblyHiddenOption(controlled_field,
|
||||
controlled_value_ids[i]);
|
||||
if (item.disabled && controller_item && controller_item.selected) {
|
||||
item = showOptionInIE(item, controlled_field);
|
||||
YAHOO.util.Dom.removeClass(item, 'bz_hidden_option');
|
||||
item.disabled = false;
|
||||
}
|
||||
else if (!item.disabled) {
|
||||
YAHOO.util.Dom.addClass(item, 'bz_hidden_option');
|
||||
if (item.selected) {
|
||||
item.selected = false;
|
||||
bz_fireEvent(controlled_field, 'change');
|
||||
}
|
||||
item.disabled = true;
|
||||
hideOptionInIE(item, controlled_field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A convenience function to generate the "id" tag of an <option>
|
||||
// based on the numeric id that Bugzilla uses for that value.
|
||||
function _value_id(field_name, id) {
|
||||
return 'v' + id + '_' + field_name;
|
||||
}
|
||||
|
||||
/*********************************/
|
||||
/* Code for Hiding Options in IE */
|
||||
/*********************************/
|
||||
|
||||
/* IE 7 and below (and some other browsers) don't respond to "display: none"
|
||||
* on <option> tags. However, you *can* insert a Comment Node as a
|
||||
* child of a <select> tag. So we just insert a Comment where the <option>
|
||||
* used to be. */
|
||||
var ie_hidden_options = new Array();
|
||||
function hideOptionInIE(anOption, aSelect) {
|
||||
if (browserCanHideOptions(aSelect)) return;
|
||||
|
||||
var commentNode = document.createComment(anOption.value);
|
||||
commentNode.id = anOption.id;
|
||||
// This keeps the interface of Comments and Options the same for
|
||||
// our other functions.
|
||||
commentNode.disabled = true;
|
||||
// replaceChild is very slow on IE in a <select> that has a lot of
|
||||
// options, so we use replaceNode when we can.
|
||||
if (anOption.replaceNode) {
|
||||
anOption.replaceNode(commentNode);
|
||||
}
|
||||
else {
|
||||
aSelect.replaceChild(commentNode, anOption);
|
||||
}
|
||||
|
||||
// Store the comment node for quick access for getPossiblyHiddenOption
|
||||
if (!ie_hidden_options[aSelect.id]) {
|
||||
ie_hidden_options[aSelect.id] = new Array();
|
||||
}
|
||||
ie_hidden_options[aSelect.id][anOption.id] = commentNode;
|
||||
}
|
||||
|
||||
function showOptionInIE(aNode, aSelect) {
|
||||
if (browserCanHideOptions(aSelect)) return aNode;
|
||||
|
||||
// We do this crazy thing with innerHTML and createElement because
|
||||
// this is the ONLY WAY that this works properly in IE.
|
||||
var optionNode = document.createElement('option');
|
||||
optionNode.innerHTML = aNode.data;
|
||||
optionNode.value = aNode.data;
|
||||
optionNode.id = aNode.id;
|
||||
// replaceChild is very slow on IE in a <select> that has a lot of
|
||||
// options, so we use replaceNode when we can.
|
||||
if (aNode.replaceNode) {
|
||||
aNode.replaceNode(optionNode);
|
||||
}
|
||||
else {
|
||||
aSelect.replaceChild(optionNode, aNode);
|
||||
}
|
||||
delete ie_hidden_options[aSelect.id][optionNode.id];
|
||||
return optionNode;
|
||||
}
|
||||
|
||||
function initHidingOptionsForIE(select_name) {
|
||||
var aSelect = document.getElementById(select_name);
|
||||
if (browserCanHideOptions(aSelect)) return;
|
||||
|
||||
for (var i = 0; ;i++) {
|
||||
var item = aSelect.options[i];
|
||||
if (!item) break;
|
||||
if (item.disabled) {
|
||||
hideOptionInIE(item, aSelect);
|
||||
i--; // Hiding an option means that the options array has changed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getPossiblyHiddenOption(aSelect, optionId) {
|
||||
// Works always for <option> tags, and works for commentNodes
|
||||
// in IE (but not in Webkit).
|
||||
var id = _value_id(aSelect.id, optionId);
|
||||
var val = document.getElementById(id);
|
||||
|
||||
// This is for WebKit and other browsers that can't "display: none"
|
||||
// an <option> and also can't getElementById for a commentNode.
|
||||
if (!val && ie_hidden_options[aSelect.id]) {
|
||||
val = ie_hidden_options[aSelect.id][id];
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
var browser_can_hide_options;
|
||||
function browserCanHideOptions(aSelect) {
|
||||
/* As far as I can tell, browsers that don't hide <option> tags
|
||||
* also never have a X position for <option> tags, even if
|
||||
* they're visible. This is the only reliable way I found to
|
||||
* differentiate browsers. So we create a visible option, see
|
||||
* if it has a position, and then remove it. */
|
||||
if (typeof(browser_can_hide_options) == "undefined") {
|
||||
var new_opt = bz_createOptionInSelect(aSelect, '', '');
|
||||
var opt_pos = YAHOO.util.Dom.getX(new_opt);
|
||||
aSelect.removeChild(new_opt);
|
||||
if (opt_pos) {
|
||||
browser_can_hide_options = true;
|
||||
}
|
||||
else {
|
||||
browser_can_hide_options = false;
|
||||
}
|
||||
}
|
||||
return browser_can_hide_options;
|
||||
}
|
||||
|
||||
/* (end) option hiding code */
|
||||
|
|
|
@ -26,11 +26,11 @@ function toggleCheckbox(this_checkbox, other_checkbox_id) {
|
|||
var select_values = new Array();
|
||||
[% USE Bugzilla %]
|
||||
[% FOREACH sel_field = Bugzilla.get_fields({ is_select => 1 }) %]
|
||||
select_values[[% sel_field.id FILTER js %]] = [
|
||||
select_values[[% sel_field.id FILTER js %]] = [
|
||||
[% FOREACH legal_value = sel_field.legal_values %]
|
||||
[[% legal_value.id FILTER js %], '[% legal_value.name FILTER js %]'][% ',' UNLESS loop.last %]
|
||||
[% END %]
|
||||
];
|
||||
];
|
||||
[% END %]
|
||||
|
||||
function onChangeType(type_field) {
|
||||
|
|
|
@ -106,9 +106,15 @@
|
|||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
<label for="visibility_value_id"><strong>is set to:</strong></label>
|
||||
<select name="visibility_value_id" id="visibility_value_id">
|
||||
<option value=""></option>
|
||||
<label for="visibility_value_id"><strong> is set to one of:</strong></label>
|
||||
</td>
|
||||
<td rowspan="2">
|
||||
<select style="min-width: 100px" id="visibility_value_id" name="visibility_value_id" size="3" multiple="multiple" [% IF loop.first %]id="visibility_value_id"[% END %]>
|
||||
[% FOREACH value = field.visibility_field.legal_values %]
|
||||
<option value="[% value.id FILTER html %]"[% ' selected="selected"' IF field.has_visibility_value(value.id) %]>
|
||||
[% value.name FILTER html %]
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -98,14 +98,14 @@
|
|||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
<label for="visibility_value_id"><strong>is set to:</strong></label>
|
||||
<select name="visibility_value_id" id="visibility_value_id">
|
||||
<label for="visibility_value_id"><strong> is set to one of:</strong></label>
|
||||
</td>
|
||||
<td rowspan="2">
|
||||
<select style="min-width: 100px" id="visibility_value_id" name="visibility_value_id" size="3" multiple="multiple" [% IF loop.first %]id="visibility_value_id"[% END %]>
|
||||
[% FOREACH value = field.visibility_field.legal_values %]
|
||||
<option value="[% value.id FILTER html %]"
|
||||
[% ' selected="selected"'
|
||||
IF field.visibility_value.id == value.id %]>
|
||||
[% value.name FILTER html %]
|
||||
</option>
|
||||
<option value="[% value.id FILTER html %]"[% ' selected="selected"' IF field.has_visibility_value(value.id) %]>
|
||||
[% value.name FILTER html %]
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
</td>
|
||||
|
|
|
@ -70,46 +70,22 @@
|
|||
</label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="button" onclick="add_visibility_value()" value="Add an option" />
|
||||
(Leave unset to have this value always appear.)
|
||||
<a href="javascript:void(0)" onclick="document.getElementById('visibility_value_id').selectedIndex=-1">clear options</a> to make this value always appear
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td id="visibility_values_td">
|
||||
<select name="visibility_value_id" id="visibility_value_id_0">
|
||||
<td></td><td>
|
||||
<select name="visibility_value_id" id="visibility_value_id" multiple="multiple" size="3">
|
||||
<option></option>
|
||||
[% FOREACH field_value = field.value_field.legal_values %]
|
||||
[% NEXT IF field_value.name == '' %]
|
||||
<option value="[% field_value.id FILTER none %]">
|
||||
<option value="[% field_value.id FILTER none %]" [% ' selected="selected"' IF value.has_visibility_value(field_value.id) %]>
|
||||
[%- field_value.name FILTER html -%]
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<script language="JavaScript">
|
||||
<!--
|
||||
function add_visibility_value()
|
||||
{
|
||||
var td = document.getElementById('visibility_values_td');
|
||||
var sel = document.getElementById('visibility_value_id_0');
|
||||
var o;
|
||||
var n = document.createElement('span');
|
||||
n.innerHTML = ' or <br>';
|
||||
td.appendChild(n);
|
||||
n = document.createElement('select');
|
||||
n.name = "visibility_value_id";
|
||||
for (var i = 0; i < sel.options.length; i++)
|
||||
{
|
||||
o = document.createElement('option');
|
||||
o.value = sel.options[i].value;
|
||||
o.text = sel.options[i].text;
|
||||
n.options.add(o);
|
||||
}
|
||||
td.appendChild(n);
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
[% END %]
|
||||
</table>
|
||||
<input type="submit" id="create" value="Add">
|
||||
|
|
|
@ -64,55 +64,22 @@
|
|||
Only appears when [%+ field.value_field.description FILTER html %] is set to:
|
||||
</th>
|
||||
<td>
|
||||
<input type="button" onclick="add_visibility_value()" value="Add an option" />
|
||||
(Leave unset to have this value always appear.)
|
||||
<a href="javascript:void(0)" onclick="document.getElementById('visibility_value_id').selectedIndex=-1">clear options</a> to make this value always appear
|
||||
</td>
|
||||
</tr>
|
||||
[% vis_values = value.visibility_values %]
|
||||
[% SET vis_values = [{ id => -1 }] IF !vis_values OR vis_values.size <= 0 %]
|
||||
[% SET vv_i = 0 %]
|
||||
<tr>
|
||||
<td></td><td id="visibility_values_td">
|
||||
[% FOR vv = vis_values %]
|
||||
[% " or <br>" IF vv_i %]
|
||||
<select name="visibility_value_id" id="visibility_value_id_[% vv_i %]">
|
||||
<td></td><td>
|
||||
<select name="visibility_value_id" id="visibility_value_id" multiple="multiple" size="3">
|
||||
<option></option>
|
||||
[% FOREACH field_value = field.value_field.legal_values %]
|
||||
[% NEXT IF field_value.name == '' %]
|
||||
<option value="[% field_value.id FILTER none %]"
|
||||
[% ' selected="selected"'
|
||||
IF field_value.id == vv.id %]>
|
||||
<option value="[% field_value.id FILTER none %]" [% ' selected="selected"' IF value.has_visibility_value(field_value.id) %]>
|
||||
[%- field_value.name FILTER html -%]
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
[% SET vv_i = vv_i + 1 %]
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
<script language="JavaScript">
|
||||
<!--
|
||||
function add_visibility_value()
|
||||
{
|
||||
var td = document.getElementById('visibility_values_td');
|
||||
var sel = document.getElementById('visibility_value_id_0');
|
||||
var o;
|
||||
var n = document.createElement('span');
|
||||
n.innerHTML = ' or <br>';
|
||||
td.appendChild(n);
|
||||
n = document.createElement('select');
|
||||
n.name = "visibility_value_id";
|
||||
for (var i = 0; i < sel.options.length; i++)
|
||||
{
|
||||
o = document.createElement('option');
|
||||
o.value = sel.options[i].value;
|
||||
o.text = sel.options[i].text;
|
||||
n.options.add(o);
|
||||
}
|
||||
td.appendChild(n);
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
[% END %]
|
||||
</table>
|
||||
|
||||
|
|
|
@ -374,8 +374,8 @@ TUI_hide_default('expert_fields');
|
|||
|
||||
[% IF Param('useopsys') %]
|
||||
<tr>
|
||||
[% INCLUDE bug/field.html.tmpl
|
||||
bug = default, field = select_fields.op_sys, editable = 1,
|
||||
[% INCLUDE bug/field.html.tmpl
|
||||
bug = default, field = select_fields.op_sys, editable = 1,
|
||||
value = default.op_sys %]
|
||||
</tr>
|
||||
[% END %]
|
||||
|
@ -392,7 +392,7 @@ TUI_hide_default('expert_fields');
|
|||
|
||||
[% IF Param('letsubmitterchoosepriority') %]
|
||||
[% INCLUDE bug/field.html.tmpl
|
||||
bug = default, field = select_fields.priority, editable = 1,
|
||||
bug = default, field = select_fields.priority, editable = 1,
|
||||
value = default.priority %]
|
||||
[% ELSE %]
|
||||
<td colspan="2"> </td>
|
||||
|
@ -799,12 +799,11 @@ TUI_hide_default('expert_fields');
|
|||
</select>
|
||||
|
||||
[% IF sel.name == "bug_status" %]
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
[%+ INCLUDE "bug/field-events.js.tmpl"
|
||||
field = select_fields.bug_status %]
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
show_fields['bug_status'] = [% select_fields.bug_status.json_visibility %];
|
||||
//-->
|
||||
</script>
|
||||
[% END %]
|
||||
</td>
|
||||
[% END %]
|
||||
|
|
|
@ -459,7 +459,7 @@ document.changeform = document.[% cfname %];
|
|||
[%#############%]
|
||||
[%# PRODUCT #%]
|
||||
[%#############%]
|
||||
|
||||
|
||||
<tr>
|
||||
[% IF bug.check_can_change_field('product', 0, 1) %]
|
||||
[% prod_list = user.get_enterable_products %]
|
||||
|
@ -470,11 +470,11 @@ document.changeform = document.[% cfname %];
|
|||
|
||||
[% INCLUDE bug/field.html.tmpl
|
||||
bug = bug, field = select_fields.product,
|
||||
override_legal_values = prod_list
|
||||
override_legal_values = prod_list,
|
||||
desc_url = 'describecomponents.cgi', value = bug.product
|
||||
editable = bug.check_can_change_field('product', 0, 1) %]
|
||||
</tr>
|
||||
[%###############%]
|
||||
[%###############%]
|
||||
[%# Component #%]
|
||||
[%###############%]
|
||||
<tr>
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
[%# 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 the San Jose State
|
||||
# University Foundation. Portions created by the Initial Developer
|
||||
# are Copyright (C) 2008 the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
|
||||
#%]
|
||||
|
||||
[%# INTERFACE:
|
||||
# field: a Bugzilla::Field object
|
||||
#%]
|
||||
|
||||
[% FOREACH controlled_field = field.controls_visibility_of %]
|
||||
showFieldWhen('[% controlled_field.name FILTER js %]',
|
||||
'[% field.name FILTER js %]',
|
||||
'[% controlled_field.visibility_value.name FILTER js %]');
|
||||
[% END %]
|
||||
[% FOREACH legal_value = field.legal_values %]
|
||||
[% FOREACH controlled_field = legal_value.controlled_values.keys %]
|
||||
[% SET cont_ids = [] %]
|
||||
[% FOREACH val = legal_value.controlled_values.$controlled_field %]
|
||||
[% cont_ids.push(val.id) %]
|
||||
[% END %]
|
||||
showValueWhen('[% controlled_field FILTER js %]',
|
||||
[[% cont_ids.join(',') FILTER js %]],
|
||||
'[% field.name FILTER js %]',
|
||||
[% legal_value.id FILTER js %]);
|
||||
[% END %]
|
||||
[% END %]
|
|
@ -39,14 +39,7 @@
|
|||
# with default field values being displayed on a page.
|
||||
#%]
|
||||
|
||||
[% SET hidden = 0 %]
|
||||
[% IF field.visibility_field.defined %]
|
||||
[% IF !bug.${field.visibility_field.name}
|
||||
.contains(field.visibility_value.name)
|
||||
%]
|
||||
[% SET hidden = 1 %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
[% SET hidden = !field.check_visibility(bug) %]
|
||||
|
||||
[% IF NOT no_tds %]
|
||||
<th class="field_label [% ' bz_hidden_field' IF hidden %]"
|
||||
|
@ -137,17 +130,15 @@
|
|||
[% SET control_field = field.value_field.name %]
|
||||
[% SET control_field = "product_obj" IF control_field == "product" %]
|
||||
[% SET control_field = "component_obj" IF control_field == "component" %]
|
||||
[% legal_values = field.restricted_legal_values(bug.${control_field}) %]
|
||||
[% legal_values = field.restricted_legal_values(bug.$control_field) %]
|
||||
[% END %]
|
||||
[% FOREACH legal_value = legal_values %]
|
||||
<option value="[% legal_value.name FILTER html %]"
|
||||
id="v[% legal_value.id FILTER html %]_
|
||||
[%- field.name FILTER html %]"
|
||||
[%# We always show selected values, even if they should be
|
||||
# hidden %]
|
||||
id="v[% legal_value.id FILTER html %]_[% field.name FILTER html %]"
|
||||
[% IF value.contains(legal_value.name).size %]
|
||||
selected="selected"
|
||||
[% END %]>
|
||||
[% END %]
|
||||
>
|
||||
[%- legal_value.name FILTER html %]</option>
|
||||
[% END %]
|
||||
</select>
|
||||
|
@ -164,8 +155,7 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
initHidingOptionsForIE('[% field.name FILTER js %]');
|
||||
[%+ INCLUDE "bug/field-events.js.tmpl" field = field %]
|
||||
show_fields['[% field.name | js %]'] = [% field.json_visibility %];
|
||||
//-->
|
||||
</script>
|
||||
|
||||
|
|
|
@ -138,8 +138,8 @@
|
|||
['[% "is_duplicate" IF bug.dup_id %]',
|
||||
'[% bug.bug_status FILTER js %]'] );
|
||||
|
||||
[% INCLUDE "bug/field-events.js.tmpl" field = select_fields.bug_status %]
|
||||
[% INCLUDE "bug/field-events.js.tmpl" field = select_fields.resolution %]
|
||||
show_fields['bug_status'] = [% select_fields.bug_status.json_visibility %];
|
||||
show_fields['resolution'] = [% select_fields.resolution.json_visibility %];
|
||||
</script>
|
||||
|
||||
[%# Common actions %]
|
||||
|
@ -149,7 +149,7 @@
|
|||
<option selected value="[% bug.bug_status FILTER html %]">
|
||||
[% get_status(bug.bug_status) FILTER html %]
|
||||
</option>
|
||||
[% IF !bug.isopened %]
|
||||
[% IF !bug.isopened %]
|
||||
[% show_resolution = 1 %]
|
||||
[% filtered_status = bug.bug_status FILTER js %]
|
||||
[% closed_status_array.push(filtered_status) %]
|
||||
|
|
|
@ -358,18 +358,16 @@
|
|||
[% IF value.visibility_values.size > 0 %]
|
||||
<li>It only appears when
|
||||
[%+ value.field.value_field.description | html %] is set to
|
||||
[% SET vv_i = 0 %]
|
||||
[% FOR vv = value.visibility_values %]
|
||||
[% IF vv_i %] or [% END %]
|
||||
'[%+ vv.name | html %]'
|
||||
[% SET vv_i = vv_i+1 %]
|
||||
'[%+ vv.name | html %]'
|
||||
[% " or " UNLESS loop.last %]
|
||||
[% END %]
|
||||
</li>
|
||||
[% ELSE %]
|
||||
<li>It now always appears, no matter what
|
||||
[%+ value.field.value_field.description | html %] is set to.
|
||||
</li>
|
||||
[% END %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
</ul>
|
||||
[% ELSE %]
|
||||
|
|
|
@ -37,11 +37,11 @@ use Testopia::Constants;
|
|||
|
||||
###############################################################################
|
||||
# tr_new_plan.cgi
|
||||
# Presents a webform to the user for the creation of a new test plan.
|
||||
# Creates a new testplan via Ajax
|
||||
# Presents a webform to the user for the creation of a new test plan.
|
||||
# Creates a new testplan via Ajax
|
||||
#
|
||||
# INTERFACE:
|
||||
# action:
|
||||
# action:
|
||||
# undef - Present form for new plan creation
|
||||
# "add" - Form has been submitted with plan data. Create the test
|
||||
# plan.
|
||||
|
@ -55,7 +55,7 @@ use Testopia::Constants;
|
|||
# file_desc1-5: string - (OPTIONAL) Description of file to attach
|
||||
#
|
||||
#
|
||||
################################################################################
|
||||
################################################################################
|
||||
|
||||
my $vars = {};
|
||||
my $template = Bugzilla->template;
|
||||
|
@ -70,20 +70,20 @@ my $action = $cgi->param('action') || '';
|
|||
if ($action eq 'add'){
|
||||
Bugzilla->error_mode(ERROR_MODE_AJAX);
|
||||
ThrowUserError("testopia-create-denied", {'object' => 'Test Plan'}) unless Bugzilla->user->in_group('Testers');
|
||||
|
||||
|
||||
my $plan = Testopia::TestPlan->create({
|
||||
'product_id' => $cgi->param('product_id'),
|
||||
'author_id' => Bugzilla->user->id,
|
||||
'type_id' => $cgi->param('type'),
|
||||
'default_product_version' => $cgi->param('prod_version'),
|
||||
'name' => $cgi->param('plan_name'),
|
||||
'text' => $cgi->param("plandoc") || '',
|
||||
'product_id' => $cgi->param('product_id'),
|
||||
'author_id' => Bugzilla->user->id,
|
||||
'type_id' => $cgi->param('type'),
|
||||
'default_product_version' => $cgi->param('prod_version'),
|
||||
'name' => $cgi->param('plan_name'),
|
||||
'text' => $cgi->param("plandoc") || '',
|
||||
});
|
||||
|
||||
|
||||
my $err = JSON::false;
|
||||
for (my $i=1; $i<5; $i++){
|
||||
next unless defined $cgi->upload("file$i");
|
||||
|
||||
|
||||
my $fh = $cgi->upload("file$i");
|
||||
my $data;
|
||||
# enable 'slurp' mode
|
||||
|
@ -94,19 +94,19 @@ if ($action eq 'add'){
|
|||
Bugzilla->error_mode(ERROR_MODE_DIE);
|
||||
eval {
|
||||
my $attachment = Testopia::Attachment->create({
|
||||
plan_id => $plan->id,
|
||||
submitter_id => Bugzilla->user->id,
|
||||
description => $cgi->param("file_desc$i") || 'Attachment',
|
||||
filename => $cgi->upload("file$i"),
|
||||
mime_type => $cgi->uploadInfo($cgi->param("file$i"))->{'Content-Type'},
|
||||
contents => $data
|
||||
plan_id => $plan->id,
|
||||
submitter_id => Bugzilla->user->id,
|
||||
description => $cgi->param("file_desc$i") || 'Attachment',
|
||||
filename => $cgi->upload("file$i"),
|
||||
mime_type => $cgi->uploadInfo($cgi->param("file$i"))->{'Content-Type'},
|
||||
contents => $data
|
||||
});
|
||||
};
|
||||
if ($@){
|
||||
$err = JSON::true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
print "{success: true, plan: '". $plan->id ."', err: $err}";
|
||||
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ else {
|
|||
ThrowUserError('testopia-read-only', {'object' => $product}) unless $product->canedit;
|
||||
$vars->{'product'} = $product;
|
||||
}
|
||||
|
||||
|
||||
ThrowUserError("testopia-create-denied", {'object' => 'Test Plan'}) unless Bugzilla->user->in_group('Testers');
|
||||
$vars->{'plan'} = Testopia::TestPlan->new({});
|
||||
$template->process("testopia/plan/add.html.tmpl", $vars) ||
|
||||
|
|
Loading…
Reference in New Issue