Bug 308253: Ability to add select (enum) fields to a bug whose list of values depends on the value of another field
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=bbaetz, a=mkanat git-svn-id: svn://10.0.0.236/trunk@254946 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
af622992a6
commit
cf61f39555
@ -210,6 +210,26 @@ use constant SCHEMA_VERSION => '2.00';
|
||||
use constant ADD_COLUMN => 'ADD COLUMN';
|
||||
# This is a reasonable default that's true for both PostgreSQL and MySQL.
|
||||
use constant MAX_IDENTIFIER_LEN => 63;
|
||||
|
||||
use constant FIELD_TABLE_SCHEMA => {
|
||||
FIELDS => [
|
||||
id => {TYPE => 'SMALLSERIAL', NOTNULL => 1,
|
||||
PRIMARYKEY => 1},
|
||||
value => {TYPE => 'varchar(64)', NOTNULL => 1},
|
||||
sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'TRUE'},
|
||||
visibility_value_id => {TYPE => 'INT2'},
|
||||
],
|
||||
# Note that bz_add_field_table should prepend the table name
|
||||
# to these index names.
|
||||
INDEXES => [
|
||||
value_idx => {FIELDS => ['value'], TYPE => 'UNIQUE'},
|
||||
sortkey_idx => ['sortkey', 'value'],
|
||||
visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
};
|
||||
|
||||
use constant ABSTRACT_SCHEMA => {
|
||||
|
||||
# BUG-RELATED TABLES
|
||||
@ -638,11 +658,15 @@ use constant ABSTRACT_SCHEMA => {
|
||||
REFERENCES => {TABLE => 'fielddefs',
|
||||
COLUMN => 'id'}},
|
||||
visibility_value_id => {TYPE => 'INT2'},
|
||||
value_field_id => {TYPE => 'INT3',
|
||||
REFERENCES => {TABLE => 'fielddefs',
|
||||
COLUMN => 'id'}},
|
||||
],
|
||||
INDEXES => [
|
||||
fielddefs_name_idx => {FIELDS => ['name'],
|
||||
TYPE => 'UNIQUE'},
|
||||
fielddefs_sortkey_idx => ['sortkey'],
|
||||
fielddefs_value_field_id_idx => ['value_field_id'],
|
||||
],
|
||||
},
|
||||
|
||||
@ -688,98 +712,65 @@ use constant ABSTRACT_SCHEMA => {
|
||||
|
||||
bug_status => {
|
||||
FIELDS => [
|
||||
id => {TYPE => 'SMALLSERIAL', NOTNULL => 1,
|
||||
PRIMARYKEY => 1},
|
||||
value => {TYPE => 'varchar(64)', NOTNULL => 1},
|
||||
sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'TRUE'},
|
||||
@{ dclone(FIELD_TABLE_SCHEMA->{FIELDS}) },
|
||||
is_open => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'},
|
||||
|
||||
],
|
||||
INDEXES => [
|
||||
bug_status_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
bug_status_sortkey_idx => ['sortkey', 'value'],
|
||||
bug_status_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
resolution => {
|
||||
FIELDS => [
|
||||
id => {TYPE => 'SMALLSERIAL', NOTNULL => 1,
|
||||
PRIMARYKEY => 1},
|
||||
value => {TYPE => 'varchar(64)', NOTNULL => 1},
|
||||
sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'TRUE'},
|
||||
],
|
||||
FIELDS => dclone(FIELD_TABLE_SCHEMA->{FIELDS}),
|
||||
INDEXES => [
|
||||
resolution_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
resolution_sortkey_idx => ['sortkey', 'value'],
|
||||
resolution_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
bug_severity => {
|
||||
FIELDS => [
|
||||
id => {TYPE => 'SMALLSERIAL', NOTNULL => 1,
|
||||
PRIMARYKEY => 1},
|
||||
value => {TYPE => 'varchar(64)', NOTNULL => 1},
|
||||
sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'TRUE'},
|
||||
],
|
||||
FIELDS => dclone(FIELD_TABLE_SCHEMA->{FIELDS}),
|
||||
INDEXES => [
|
||||
bug_severity_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
bug_severity_sortkey_idx => ['sortkey', 'value'],
|
||||
bug_severity_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
priority => {
|
||||
FIELDS => [
|
||||
id => {TYPE => 'SMALLSERIAL', NOTNULL => 1,
|
||||
PRIMARYKEY => 1},
|
||||
value => {TYPE => 'varchar(64)', NOTNULL => 1},
|
||||
sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'TRUE'},
|
||||
],
|
||||
FIELDS => dclone(FIELD_TABLE_SCHEMA->{FIELDS}),
|
||||
INDEXES => [
|
||||
priority_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
priority_sortkey_idx => ['sortkey', 'value'],
|
||||
priority_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
rep_platform => {
|
||||
FIELDS => [
|
||||
id => {TYPE => 'SMALLSERIAL', NOTNULL => 1,
|
||||
PRIMARYKEY => 1},
|
||||
value => {TYPE => 'varchar(64)', NOTNULL => 1},
|
||||
sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'TRUE'},
|
||||
],
|
||||
FIELDS => dclone(FIELD_TABLE_SCHEMA->{FIELDS}),
|
||||
INDEXES => [
|
||||
rep_platform_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
rep_platform_sortkey_idx => ['sortkey', 'value'],
|
||||
rep_platform_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
op_sys => {
|
||||
FIELDS => [
|
||||
id => {TYPE => 'SMALLSERIAL', NOTNULL => 1,
|
||||
PRIMARYKEY => 1},
|
||||
value => {TYPE => 'varchar(64)', NOTNULL => 1},
|
||||
sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'TRUE'},
|
||||
],
|
||||
FIELDS => dclone(FIELD_TABLE_SCHEMA->{FIELDS}),
|
||||
INDEXES => [
|
||||
op_sys_value_idx => {FIELDS => ['value'],
|
||||
TYPE => 'UNIQUE'},
|
||||
op_sys_sortkey_idx => ['sortkey', 'value'],
|
||||
op_sys_visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
},
|
||||
|
||||
@ -1409,23 +1400,6 @@ use constant ABSTRACT_SCHEMA => {
|
||||
|
||||
};
|
||||
|
||||
use constant FIELD_TABLE_SCHEMA => {
|
||||
FIELDS => [
|
||||
id => {TYPE => 'SMALLSERIAL', NOTNULL => 1,
|
||||
PRIMARYKEY => 1},
|
||||
value => {TYPE => 'varchar(64)', NOTNULL => 1},
|
||||
sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'TRUE'},
|
||||
],
|
||||
# Note that bz_add_field_table should prepend the table name
|
||||
# to these index names.
|
||||
INDEXES => [
|
||||
value_idx => {FIELDS => ['value'], TYPE => 'UNIQUE'},
|
||||
sortkey_idx => ['sortkey', 'value'],
|
||||
],
|
||||
};
|
||||
|
||||
# Foreign Keys are added in Bugzilla::DB::bz_add_field_tables
|
||||
use constant MULTI_SELECT_VALUE_TABLE => {
|
||||
FIELDS => [
|
||||
|
||||
@ -98,6 +98,7 @@ use constant DB_COLUMNS => qw(
|
||||
enter_bug
|
||||
visibility_field_id
|
||||
visibility_value_id
|
||||
value_field_id
|
||||
);
|
||||
|
||||
use constant REQUIRED_CREATE_FIELDS => qw(name description);
|
||||
@ -110,10 +111,11 @@ use constant VALIDATORS => {
|
||||
obsolete => \&_check_obsolete,
|
||||
sortkey => \&_check_sortkey,
|
||||
type => \&_check_type,
|
||||
visibility_field_id => \&_check_control_field,
|
||||
visibility_field_id => \&_check_visibility_field_id,
|
||||
};
|
||||
|
||||
use constant UPDATE_VALIDATORS => {
|
||||
value_field_id => \&_check_value_field_id,
|
||||
visibility_value_id => \&_check_control_value,
|
||||
};
|
||||
|
||||
@ -125,6 +127,7 @@ use constant UPDATE_COLUMNS => qw(
|
||||
enter_bug
|
||||
visibility_field_id
|
||||
visibility_value_id
|
||||
value_field_id
|
||||
|
||||
type
|
||||
);
|
||||
@ -292,7 +295,16 @@ sub _check_type {
|
||||
return $type;
|
||||
}
|
||||
|
||||
sub _check_control_field {
|
||||
sub _check_value_field_id {
|
||||
my ($invocant, $field_id, $is_select) = @_;
|
||||
$is_select = $invocant->is_select if !defined $is_select;
|
||||
if ($field_id && !$is_select) {
|
||||
ThrowUserError('field_value_control_select_only');
|
||||
}
|
||||
return $invocant->_check_visibility_field_id($field_id);
|
||||
}
|
||||
|
||||
sub _check_visibility_field_id {
|
||||
my ($invocant, $field_id) = @_;
|
||||
$field_id = trim($field_id);
|
||||
return undef if !$field_id;
|
||||
@ -310,7 +322,7 @@ sub _check_control_field {
|
||||
sub _check_control_value {
|
||||
my ($invocant, $value_id, $field_id) = @_;
|
||||
my $field;
|
||||
if (blessed($invocant)) {
|
||||
if (blessed $invocant) {
|
||||
$field = $invocant->visibility_field;
|
||||
}
|
||||
elsif ($field_id) {
|
||||
@ -528,6 +540,48 @@ sub controls_visibility_of {
|
||||
|
||||
=pod
|
||||
|
||||
=over
|
||||
|
||||
=item C<value_field>
|
||||
|
||||
The Bugzilla::Field that controls the list of values for this field.
|
||||
|
||||
Returns undef if there is no field that controls this field's visibility.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub value_field {
|
||||
my $self = shift;
|
||||
if ($self->{value_field_id}) {
|
||||
$self->{value_field} ||= $self->new($self->{value_field_id});
|
||||
}
|
||||
return $self->{value_field};
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=over
|
||||
|
||||
=item C<controls_values_of>
|
||||
|
||||
An arrayref of C<Bugzilla::Field> objects, representing fields that this
|
||||
field controls the values of.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub controls_values_of {
|
||||
my $self = shift;
|
||||
$self->{controls_values_of} ||=
|
||||
Bugzilla::Field->match({ value_field_id => $self->id });
|
||||
return $self->{controls_values_of};
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=head2 Instance Mutators
|
||||
|
||||
These set the particular field that they are named after.
|
||||
@ -552,6 +606,8 @@ They will throw an error if you try to set the values to something invalid.
|
||||
|
||||
=item C<set_visibility_value>
|
||||
|
||||
=item C<set_value_field>
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
@ -572,6 +628,11 @@ sub set_visibility_value {
|
||||
$self->set('visibility_value_id', $value);
|
||||
delete $self->{visibility_value};
|
||||
}
|
||||
sub set_value_field {
|
||||
my ($self, $value) = @_;
|
||||
$self->set('value_field_id', $value);
|
||||
delete $self->{value_field};
|
||||
}
|
||||
|
||||
# This is only used internally by upgrade code in Bugzilla::Field.
|
||||
sub _set_type { $_[0]->set('type', $_[1]); }
|
||||
@ -734,9 +795,24 @@ sub run_create_validators {
|
||||
$class->_check_control_value($params->{visibility_value_id},
|
||||
$params->{visibility_field_id});
|
||||
|
||||
my $type = $params->{type};
|
||||
$params->{value_field_id} =
|
||||
$class->_check_value_field_id($params->{value_field_id},
|
||||
($type == FIELD_TYPE_SINGLE_SELECT
|
||||
|| $type == FIELD_TYPE_MULTI_SELECT) ? 1 : 0);
|
||||
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
|
||||
|
||||
|
||||
@ -40,11 +40,13 @@ use constant DB_COLUMNS => qw(
|
||||
id
|
||||
value
|
||||
sortkey
|
||||
visibility_value_id
|
||||
);
|
||||
|
||||
use constant UPDATE_COLUMNS => qw(
|
||||
value
|
||||
sortkey
|
||||
visibility_value_id
|
||||
);
|
||||
|
||||
use constant NAME_FIELD => 'value';
|
||||
@ -55,6 +57,7 @@ use constant REQUIRED_CREATE_FIELDS => qw(value);
|
||||
use constant VALIDATORS => {
|
||||
value => \&_check_value,
|
||||
sortkey => \&_check_sortkey,
|
||||
visibility_value_id => \&_check_visibility_value_id,
|
||||
};
|
||||
|
||||
use constant CLASS_MAP => {
|
||||
@ -186,9 +189,12 @@ sub remove_from_db {
|
||||
ThrowUserError("fieldvalue_still_has_bugs",
|
||||
{ field => $self->field, value => $self });
|
||||
}
|
||||
if (my @vis_fields = @{ $self->controls_visibility_of_fields }) {
|
||||
my $vis_fields = $self->controls_visibility_of_fields;
|
||||
my $values = $self->controlled_values;
|
||||
if (@$vis_fields || @$values) {
|
||||
ThrowUserError('fieldvalue_is_controller',
|
||||
{ value => $self, fields => [map($_->name, @vis_fields)] });
|
||||
{ value => $self, fields => [map($_->name, @$vis_fields)],
|
||||
vals => $values });
|
||||
}
|
||||
$self->SUPER::remove_from_db();
|
||||
}
|
||||
@ -260,12 +266,41 @@ sub controls_visibility_of_fields {
|
||||
return $self->{controls_visibility_of_fields};
|
||||
}
|
||||
|
||||
sub visibility_value {
|
||||
my $self = shift;
|
||||
if ($self->{visibility_value_id}) {
|
||||
$self->{visibility_value} ||=
|
||||
Bugzilla::Field::Choice->type($self->field->value_field)->new(
|
||||
$self->{visibility_value_id});
|
||||
}
|
||||
return $self->{visibility_value};
|
||||
}
|
||||
|
||||
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;
|
||||
foreach my $field (@$fields) {
|
||||
my $controlled = Bugzilla::Field::Choice->type($field)
|
||||
->match({ visibility_value_id => $self->id });
|
||||
push(@controlled_values, @$controlled);
|
||||
}
|
||||
$self->{controlled_values} = \@controlled_values;
|
||||
return $self->{controlled_values};
|
||||
}
|
||||
|
||||
############
|
||||
# Mutators #
|
||||
############
|
||||
|
||||
sub set_name { $_[0]->set('value', $_[1]); }
|
||||
sub set_sortkey { $_[0]->set('sortkey', $_[1]); }
|
||||
sub set_visibility_value {
|
||||
my ($self, $value) = @_;
|
||||
$self->set('visibility_value_id', $value);
|
||||
delete $self->{visibility_value};
|
||||
}
|
||||
|
||||
##############
|
||||
# Validators #
|
||||
@ -312,6 +347,15 @@ sub _check_sortkey {
|
||||
return $value;
|
||||
}
|
||||
|
||||
sub _check_visibility_value_id {
|
||||
my ($invocant, $value_id) = @_;
|
||||
$value_id = trim($value_id);
|
||||
my $field = $invocant->field->value_field;
|
||||
return undef if !$field || !$value_id;
|
||||
my $value_obj = Bugzilla::Field::Choice->type($field)
|
||||
->check({ id => $value_id });
|
||||
return $value_obj->id;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
||||
@ -88,6 +88,9 @@ sub update_fielddefs_definition {
|
||||
|
||||
$dbh->bz_add_column('fielddefs', 'visibility_field_id', {TYPE => 'INT3'});
|
||||
$dbh->bz_add_column('fielddefs', 'visibility_value_id', {TYPE => 'INT2'});
|
||||
$dbh->bz_add_column('fielddefs', 'value_field_id', {TYPE => 'INT3'});
|
||||
$dbh->bz_add_index('fielddefs', 'fielddefs_value_field_id_idx',
|
||||
['value_field_id']);
|
||||
|
||||
# Remember, this is not the function for adding general table changes.
|
||||
# That is below. Add new changes to the fielddefs table above this
|
||||
@ -539,6 +542,8 @@ sub update_table_definitions {
|
||||
# 2008-09-07 LpSolit@gmail.com - Bug 452893
|
||||
_fix_illegal_flag_modification_dates();
|
||||
|
||||
_add_visiblity_value_to_value_tables();
|
||||
|
||||
################################################################
|
||||
# New --TABLE-- changes should go *** A B O V E *** this point #
|
||||
################################################################
|
||||
@ -2907,7 +2912,25 @@ sub _initialize_workflow {
|
||||
|
||||
# Make sure the bug status used by the 'duplicate_or_move_bug_status'
|
||||
# parameter has all the required transitions set.
|
||||
Bugzilla::Status::add_missing_bug_status_transitions();
|
||||
my $dup_status = Bugzilla->params->{'duplicate_or_move_bug_status'};
|
||||
my $status_id = $dbh->selectrow_array(
|
||||
'SELECT id FROM bug_status WHERE value = ?', undef, $dup_status);
|
||||
# There's a minor chance that this status isn't in the DB.
|
||||
$status_id || return;
|
||||
|
||||
my $missing_statuses = $dbh->selectcol_arrayref(
|
||||
'SELECT id FROM bug_status
|
||||
LEFT JOIN status_workflow ON old_status = id
|
||||
AND new_status = ?
|
||||
WHERE old_status IS NULL', undef, $status_id);
|
||||
|
||||
my $sth = $dbh->prepare('INSERT INTO status_workflow
|
||||
(old_status, new_status) VALUES (?, ?)');
|
||||
|
||||
foreach my $old_status_id (@$missing_statuses) {
|
||||
next if ($old_status_id == $status_id);
|
||||
$sth->execute($old_status_id, $status_id);
|
||||
}
|
||||
}
|
||||
|
||||
sub _make_lang_setting_dynamic {
|
||||
@ -3098,6 +3121,20 @@ sub _fix_illegal_flag_modification_dates {
|
||||
print "$rows flags had an illegal modification date. Fixed!\n" if ($rows =~ /^\d+$/);
|
||||
}
|
||||
|
||||
sub _add_visiblity_value_to_value_tables {
|
||||
my $dbh = Bugzilla->dbh;
|
||||
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) {
|
||||
$dbh->bz_add_column($field, 'visibility_value_id', {TYPE => 'INT2'});
|
||||
$dbh->bz_add_index($field, "${field}_visibility_value_id_idx",
|
||||
['visibility_value_id']);
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
@ -46,13 +46,10 @@ use constant SPECIAL_STATUS_WORKFLOW_ACTIONS => qw(
|
||||
|
||||
use constant DB_TABLE => 'bug_status';
|
||||
|
||||
use constant DB_COLUMNS => qw(
|
||||
id
|
||||
value
|
||||
sortkey
|
||||
isactive
|
||||
is_open
|
||||
);
|
||||
# This has all the standard Bugzilla::Field::Choice columns plus "is_open"
|
||||
sub DB_COLUMNS {
|
||||
return ($_[0]->SUPER::DB_COLUMNS, 'is_open');
|
||||
}
|
||||
|
||||
sub VALIDATORS {
|
||||
my $invocant = shift;
|
||||
|
||||
@ -66,6 +66,7 @@ elsif ($action eq 'new') {
|
||||
custom => 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'),
|
||||
});
|
||||
|
||||
delete_token($token);
|
||||
@ -110,6 +111,7 @@ elsif ($action eq 'update') {
|
||||
$field->set_obsolete($cgi->param('obsolete'));
|
||||
$field->set_visibility_field($cgi->param('visibility_field_id'));
|
||||
$field->set_visibility_value($cgi->param('visibility_value_id'));
|
||||
$field->set_value_field($cgi->param('value_field_id'));
|
||||
$field->update();
|
||||
|
||||
delete_token($token);
|
||||
|
||||
@ -112,10 +112,12 @@ if ($action eq 'add') {
|
||||
if ($action eq 'new') {
|
||||
check_token_data($token, 'add_field_value');
|
||||
|
||||
my $created_value = Bugzilla::Field::Choice->type($field)->create(
|
||||
{ value => scalar $cgi->param('value'),
|
||||
sortkey => scalar $cgi->param('sortkey'),
|
||||
is_open => scalar $cgi->param('is_open') });
|
||||
my $created_value = Bugzilla::Field::Choice->type($field)->create({
|
||||
value => scalar $cgi->param('value'),
|
||||
sortkey => scalar $cgi->param('sortkey'),
|
||||
is_open => scalar $cgi->param('is_open'),
|
||||
visibility_value_id => scalar $cgi->param('visibility_value_id'),
|
||||
});
|
||||
|
||||
delete_token($token);
|
||||
|
||||
@ -180,6 +182,7 @@ if ($action eq 'update') {
|
||||
$vars->{'value_old'} = $value->name;
|
||||
$value->set_name($cgi->param('value_new'));
|
||||
$value->set_sortkey($cgi->param('sortkey'));
|
||||
$value->set_visibility_value($cgi->param('visibility_value_id'));
|
||||
$vars->{'changes'} = $value->update();
|
||||
delete_token($token);
|
||||
$vars->{'message'} = 'field_value_updated';
|
||||
|
||||
@ -359,3 +359,124 @@ function handleVisControllerValueChange(e, args) {
|
||||
YAHOO.util.Dom.addClass(field_container, 'bz_hidden_field');
|
||||
}
|
||||
}
|
||||
|
||||
function showValueWhen(controlled_field_id, controlled_value,
|
||||
controller_field_id, controller_value)
|
||||
{
|
||||
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,
|
||||
controller_field, controller_value]);
|
||||
}
|
||||
|
||||
function handleValControllerChange(e, args) {
|
||||
var controlled_field = document.getElementById(args[0]);
|
||||
var controlled_value = args[1];
|
||||
var controller_field = args[2];
|
||||
var controller_value = args[3];
|
||||
|
||||
var item = getPossiblyHiddenOption(controlled_field, controlled_value);
|
||||
if (bz_valueSelected(controller_field, controller_value)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************/
|
||||
/* 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. */
|
||||
function hideOptionInIE(anOption, aSelect) {
|
||||
if (browserCanHideOptions(aSelect)) return;
|
||||
|
||||
var commentNode = document.createComment(anOption.value);
|
||||
aSelect.replaceChild(commentNode, anOption);
|
||||
}
|
||||
|
||||
function showOptionInIE(aNode, aSelect) {
|
||||
if (browserCanHideOptions(aSelect)) return;
|
||||
// If aNode is an Option
|
||||
if (typeof(aNode.value) != 'undefined') return;
|
||||
|
||||
// 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;
|
||||
var old_node = aSelect.replaceChild(optionNode, aNode);
|
||||
}
|
||||
|
||||
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, aValue) {
|
||||
var val_index = bz_optionIndex(aSelect, aValue);
|
||||
|
||||
/* We have to go fishing for one of our comment nodes if we
|
||||
* don't find the <option>. */
|
||||
if (val_index < 0 && !browserCanHideOptions(aSelect)) {
|
||||
var children = aSelect.childNodes;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var item = children[i];
|
||||
if (item.data == aValue) {
|
||||
// Set this for handleValControllerChange, so that both options
|
||||
// and commentNodes have this.
|
||||
children[i].disabled = true;
|
||||
return children[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise we just return the Option we found. */
|
||||
return aSelect.options[val_index];
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
@ -219,3 +219,37 @@ function bz_valueSelected(aSelect, aValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells you where (what index) in a <select> a particular option is.
|
||||
* Returns -1 if the value is not in the <select>
|
||||
*
|
||||
* @param aSelect The select you're checking.
|
||||
* @param aValue The value you want to know the index of.
|
||||
*/
|
||||
function bz_optionIndex(aSelect, aValue) {
|
||||
for (var i = 0; i < aSelect.options.length; i++) {
|
||||
if (aSelect.options[i].value == aValue) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to fire an event programmatically.
|
||||
*
|
||||
* @param anElement The element you want to fire the event of.
|
||||
* @param anEvent The name of the event you want to fire,
|
||||
* without the word "on" in front of it.
|
||||
*/
|
||||
function bz_fireEvent(anElement, anEvent) {
|
||||
// IE
|
||||
if (document.createEventObject) {
|
||||
var evt = document.createEventObject();
|
||||
return anElement.fireEvent('on' + anEvent, evt);
|
||||
}
|
||||
// Firefox, etc.
|
||||
var evt = document.createEvent("HTMLEvents");
|
||||
evt.initEvent(anEvent, true, true); // event type, bubbling, cancelable
|
||||
return !anElement.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
@ -406,9 +406,12 @@ div.user_match {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.bz_hidden_field {
|
||||
.bz_hidden_field, .bz_hidden_option {
|
||||
display: none;
|
||||
}
|
||||
.bz_hidden_option {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.calendar_button {
|
||||
background: transparent url("global/calendar.png") no-repeat;
|
||||
|
||||
@ -32,6 +32,18 @@ var select_values = new Array();
|
||||
];
|
||||
[% END %]
|
||||
|
||||
function onChangeType(type_field) {
|
||||
var value_field = document.getElementById('value_field_id');
|
||||
if (type_field.value == [% constants.FIELD_TYPE_SINGLE_SELECT %]
|
||||
|| type_field.value == [% constants.FIELD_TYPE_MULTI_SELECT %])
|
||||
{
|
||||
value_field.disabled = false;
|
||||
}
|
||||
else {
|
||||
value_field.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
function onChangeVisibilityField() {
|
||||
var vis_field = document.getElementById('visibility_field_id');
|
||||
var vis_value = document.getElementById('visibility_value_id');
|
||||
|
||||
@ -75,7 +75,7 @@
|
||||
<tr>
|
||||
<th align="right"><label for="type">Type:</label></th>
|
||||
<td>
|
||||
<select id="type" name="type">
|
||||
<select id="type" name="type" onchange="onChangeType(this)">
|
||||
[% FOREACH type = field_types.keys %]
|
||||
[% NEXT IF type == constants.FIELD_TYPE_UNKNOWN %]
|
||||
<option value="[% type FILTER html %]">[% field_types.$type FILTER html %]</option>
|
||||
@ -112,6 +112,28 @@
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2"> </td>
|
||||
<th>
|
||||
<label for="value_field_id">
|
||||
Field that controls the values<br>
|
||||
that appear in this field:
|
||||
</label>
|
||||
</th>
|
||||
|
||||
<td>
|
||||
<select disabled="disabled" name="value_field_id" id="value_field_id">
|
||||
<option></option>
|
||||
[% FOREACH sel_field = Bugzilla.get_fields({ is_select => 1 }) %]
|
||||
<option value="[% sel_field.id FILTER html %]">
|
||||
[% sel_field.description FILTER html %]
|
||||
([% sel_field.name FILTER html %])
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
<input type="hidden" name="action" value="new">
|
||||
|
||||
@ -109,10 +109,32 @@
|
||||
[% IF field.is_select %]
|
||||
<tr>
|
||||
<th> </th>
|
||||
<td colspan="3">
|
||||
<td>
|
||||
<a href="editvalues.cgi?field=[% field.name FILTER url_quote %]">Edit
|
||||
legal values for this field</a>.
|
||||
</td>
|
||||
|
||||
<th>
|
||||
<label for="value_field_id">
|
||||
Field that controls the values<br>
|
||||
that appear in this field:
|
||||
</label>
|
||||
</th>
|
||||
|
||||
<td>
|
||||
<select name="value_field_id" id="value_field_id">
|
||||
<option></option>
|
||||
[% FOREACH sel_field = Bugzilla.get_fields({ is_select => 1 }) %]
|
||||
[% NEXT IF sel_field.id == field.id %]
|
||||
<option value="[% sel_field.id FILTER html %]"
|
||||
[% ' selected="selected"'
|
||||
IF sel_field.id == field.value_field.id %]>
|
||||
[% sel_field.description FILTER html %]
|
||||
([% sel_field.name FILTER html %])
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
</table>
|
||||
|
||||
@ -62,7 +62,8 @@
|
||||
<h2>Confirmation</h2>
|
||||
|
||||
[% IF value.is_default || value.bug_count || (value_count == 1)
|
||||
|| value.controls_visibility_of_fields.size
|
||||
|| value.controls_visibility_of_fields.size
|
||||
|| value.controlled_values.size
|
||||
%]
|
||||
|
||||
<p>Sorry, but the '[% value.name FILTER html %]' value cannot be deleted
|
||||
@ -121,6 +122,20 @@
|
||||
[% END %]
|
||||
</li>
|
||||
[% END %]
|
||||
|
||||
[% IF value.controlled_values.size %]
|
||||
<li>This value controls the visibility of the following values in
|
||||
other fields:<br>
|
||||
[% FOREACH controlled = value.controlled_values %]
|
||||
<a href="editvalues.cgi?action=edit&field=
|
||||
[%- controlled.field.name FILTER url_quote %]&value=
|
||||
[%- controlled.name FILTER url_quote %]">
|
||||
[% controlled.field.description FILTER html %]
|
||||
([% controlled.field.name FILTER html %]):
|
||||
[%+ controlled.name FILTER html %]</a><br>
|
||||
[% END %]
|
||||
</li>
|
||||
[% END %]
|
||||
</ul>
|
||||
|
||||
[% ELSE %]
|
||||
|
||||
@ -62,6 +62,27 @@
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
[% IF field.value_field %]
|
||||
<tr>
|
||||
<th align="right">
|
||||
<label for="visibility_value_id">Only appears when
|
||||
[%+ field.value_field.description FILTER html %] is set to:
|
||||
</label>
|
||||
</th>
|
||||
<td>
|
||||
<select name="visibility_value_id" id="visibility_value_id">
|
||||
<option></option>
|
||||
[% FOREACH field_value = field.value_field.legal_values %]
|
||||
[% NEXT IF field_value.name == '' %]
|
||||
<option value="[% field_value.id FILTER none %]">
|
||||
[%- field_value.name FILTER html -%]
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
<small>(Leave unset to have this value always appear.)</small>
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
</table>
|
||||
<input type="submit" id="create" value="Add">
|
||||
<input type="hidden" name="action" value="new">
|
||||
|
||||
@ -32,7 +32,9 @@
|
||||
<table border="0" cellpadding="4" cellspacing="0">
|
||||
|
||||
<tr>
|
||||
<th valign="top"><label for="value_new">Field Value:</label></th>
|
||||
<th valign="top" align="right">
|
||||
<label for="value_new">Field Value:</label>
|
||||
</th>
|
||||
<td>
|
||||
[% IF value.is_static %]
|
||||
<input type="hidden" name="value_new" id="value_new"
|
||||
@ -56,6 +58,29 @@
|
||||
<td>[% IF value.is_open %]Open[% ELSE %]Closed[% END %]</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
[% IF field.value_field %]
|
||||
<tr>
|
||||
<th align="right">
|
||||
<label for="visibility_value_id">Only appears when
|
||||
[%+ field.value_field.description FILTER html %] is set to:
|
||||
</label>
|
||||
</th>
|
||||
<td>
|
||||
<select name="visibility_value_id" id="visibility_value_id">
|
||||
<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 == value.visibility_value.id %]>
|
||||
[%- field_value.name FILTER html -%]
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
<small>(Leave unset to have this value always appear.)</small>
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
</table>
|
||||
|
||||
<input type="hidden" name="value" value="[% value.name FILTER html %]">
|
||||
|
||||
@ -642,13 +642,12 @@ function handleWantsAttachment(wants_attachment) {
|
||||
</select>
|
||||
|
||||
[% IF sel.name == "bug_status" %]
|
||||
[% FOREACH controlled = select_fields.bug_status.controls_visibility_of %]
|
||||
<script type="text/javascript">
|
||||
showFieldWhen('[% controlled.name FILTER js %]',
|
||||
'bug_status',
|
||||
'[% controlled.visibility_value.name FILTER js %]');
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
[%+ INCLUDE "bug/field-events.js.tmpl"
|
||||
field = select_fields.bug_status %]
|
||||
//-->
|
||||
</script>
|
||||
[% END %]
|
||||
[% END %]
|
||||
</td>
|
||||
[% END %]
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
[%# 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_value = legal_value.controlled_values %]
|
||||
showValueWhen('[% controlled_value.field.name FILTER js %]',
|
||||
'[% controlled_value.name FILTER js %]',
|
||||
'[% field.name FILTER js %]',
|
||||
'[% legal_value.name FILTER js %]');
|
||||
[% END %]
|
||||
[% END %]
|
||||
@ -126,10 +126,20 @@
|
||||
</option>
|
||||
[% END %]
|
||||
[% FOREACH legal_value = field.legal_values %]
|
||||
[% SET control_value = legal_value.visibility_value %]
|
||||
[% SET control_field = field.value_field %]
|
||||
<option value="[% legal_value.name FILTER html %]"
|
||||
[%- " selected=\"selected\""
|
||||
IF value.contains(legal_value.name).size %]>
|
||||
[%- legal_value.name FILTER html %]</option>
|
||||
[%# We always show selected values, even if they should be
|
||||
# hidden %]
|
||||
[% IF value.contains(legal_value.name).size %]
|
||||
selected="selected"
|
||||
[% ELSIF control_field && control_value
|
||||
&& !bug.${control_field.name}.contains(control_value.name)
|
||||
%]
|
||||
class="bz_hidden_option" disabled="disabled"
|
||||
[% END %]>
|
||||
[%- legal_value.name FILTER html -%]
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
[%# When you pass an empty multi-select in the web interface,
|
||||
@ -142,19 +152,19 @@
|
||||
[% IF field.type == constants.FIELD_TYPE_MULTI_SELECT %]
|
||||
<input type="hidden" name="defined_[% field.name FILTER html %]">
|
||||
[% END %]
|
||||
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
initHidingOptionsForIE('[% field.name FILTER js %]');
|
||||
[%+ INCLUDE "bug/field-events.js.tmpl" field = field %]
|
||||
//-->
|
||||
</script>
|
||||
|
||||
[% CASE constants.FIELD_TYPE_TEXTAREA %]
|
||||
[% INCLUDE global/textarea.html.tmpl
|
||||
id = field.name name = field.name minrows = 4 maxrows = 8
|
||||
cols = 60 defaultcontent = value %]
|
||||
[% END %]
|
||||
|
||||
[% FOREACH controlled_field = field.controls_visibility_of %]
|
||||
<script type="text/javascript">
|
||||
showFieldWhen('[% controlled_field.name FILTER js %]',
|
||||
'[% field.name FILTER js %]',
|
||||
'[% controlled_field.visibility_value.name FILTER js %]');
|
||||
</script>
|
||||
[% END %]
|
||||
[% ELSIF field.type == constants.FIELD_TYPE_TEXTAREA %]
|
||||
<div class="uneditable_textarea">[% value FILTER wrap_comment(60)
|
||||
FILTER html %]</div>
|
||||
|
||||
@ -122,16 +122,8 @@
|
||||
['[% "is_duplicate" IF bug.dup_id %]',
|
||||
'[% bug.bug_status FILTER js %]'] );
|
||||
|
||||
[% FOREACH controlled = select_fields.bug_status.controls_visibility_of %]
|
||||
showFieldWhen('[% controlled.name FILTER js %]',
|
||||
'bug_status',
|
||||
'[% controlled.visibility_value.name FILTER js %]');
|
||||
[% END %]
|
||||
[% FOREACH controlled = select_fields.resolution.controls_visibility_of %]
|
||||
showFieldWhen('[% controlled.name FILTER js %]',
|
||||
'resolution',
|
||||
'[% controlled.visibility_value.name FILTER js %]');
|
||||
[% END %]
|
||||
[% INCLUDE "bug/field-events.js.tmpl" field = select_fields.bug_status %]
|
||||
[% INCLUDE "bug/field-events.js.tmpl" field = select_fields.resolution %]
|
||||
</script>
|
||||
|
||||
[%# Common actions %]
|
||||
|
||||
@ -332,6 +332,17 @@
|
||||
<li>Sortkey updated to
|
||||
<em>[% changes.sortkey.1 FILTER html %]</em>.</li>
|
||||
[% END %]
|
||||
[% IF changes.visibility_value_id %]
|
||||
[% IF value.visibility_value.defined %]
|
||||
<li>It only appears when
|
||||
[%+ value.field.value_field.description FILTER html %] is set to
|
||||
'[%+ value.visibility_value.name FILTER html %]'.</li>
|
||||
[% ELSE %]
|
||||
<li>It now always appears, no matter what
|
||||
[%+ value.field.value_field.description FILTER html %] is set to.
|
||||
</li>
|
||||
[% END %]
|
||||
[% END %]
|
||||
</ul>
|
||||
[% ELSE %]
|
||||
No changes made to the field value <em>[% value_old FILTER html %]</em>.
|
||||
|
||||
@ -412,7 +412,7 @@
|
||||
[% ELSIF error == "field_control_must_be_select" %]
|
||||
[% title = "Invalid Field Type Selected" %]
|
||||
Only drop-down and multi-select fields can be used to control
|
||||
the visibility of other fields. [% field.description FILTER html %]
|
||||
the visibility/values of other fields. [% field.description FILTER html %]
|
||||
is not the right type of field.
|
||||
|
||||
[% ELSIF error == "field_invalid_name" %]
|
||||
@ -433,6 +433,11 @@
|
||||
[% title = "Missing Name for Field" %]
|
||||
You must enter a name for this field.
|
||||
|
||||
[% ELSIF error == "field_value_control_select_only" %]
|
||||
[% title = "Invalid Value Control Field" %]
|
||||
Only Drop-Down or Multi-Select fields can have a field that
|
||||
controls their values.
|
||||
|
||||
[% ELSIF error == "fieldname_invalid" %]
|
||||
[% title = "Specified Field Does Not Exist" %]
|
||||
The field '[% field.name FILTER html %]' does not exist or
|
||||
@ -446,8 +451,21 @@
|
||||
[% ELSIF error == "fieldvalue_is_controller" %]
|
||||
[% title = "Value Controls Other Fields" %]
|
||||
You cannot delete the '[% value.name FILTER html %]' value for this
|
||||
field because it controls the visibility of the following other fields:
|
||||
[%+ fields.join(', ') FILTER html %].
|
||||
field because
|
||||
[% IF fields.size %]
|
||||
it controls the visibility of the following fields:
|
||||
[%+ fields.join(', ') FILTER html %].
|
||||
[% END %]
|
||||
[% ' and ' IF fields.size AND vals.size %]
|
||||
[% IF vals.size %]
|
||||
it controls the visibility of the following field values:
|
||||
<ul>
|
||||
[% FOREACH val = vals %]
|
||||
<li>[% val.field.name FILTER html %]:
|
||||
'[% val.name FILTER html %]'</li>
|
||||
[% END %]
|
||||
</ul>
|
||||
[% END %]
|
||||
|
||||
[% ELSIF error == "fieldvalue_is_default" %]
|
||||
[% title = "Specified Field Value Is Default" %]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user