Bug 81185, Bug 70605 - very global Bugzilla Search optimisation. See http://wiki.4intra.net/Bugzilla-Search for details

Bug 63855 - Fix quicksearch


git-svn-id: svn://svn.office.custis.ru/3rdparty/bugzilla.org/trunk@1295 6955db30-a419-402b-8a0d-67ecbb4d7f56
master
vfilippov 2011-07-20 12:48:26 +00:00
parent d0251edef1
commit 0752e18573
291 changed files with 6844 additions and 5902 deletions

View File

@ -690,18 +690,34 @@ sub switch_to_shadow_db {
return $class->dbh;
}
sub switch_to_main_db {
sub switch_to_main_db
{
my $class = shift;
$class->request_cache->{dbh} = $class->dbh_main;
return $class->dbh_main;
}
sub messages
{
my $class = shift;
my $lc = $class->cgi->cookie('LANG') || 'en';
$lc =~ s/\W+//so;
if (!$INC{'Bugzilla::Language::'.$lc})
{
eval { require 'Bugzilla/Language/'.$lc.'.pm' };
if ($@)
{
$lc = 'en';
require 'Bugzilla/Language/en.pm';
}
}
return $Bugzilla::messages->{$lc};
}
sub cache_fields
{
my $class = shift;
my $rc = $class->request_cache;
#return _fill_fields_cache($rc->{fields} ||= {});
if (!$rc->{fields_delta_ts})
{
($rc->{fields_delta_ts}) = Bugzilla->dbh->selectrow_array(
@ -783,7 +799,16 @@ sub get_fields
}
if ($sort)
{
@fields = sort { $a->{sortkey} <=> $b->{sortkey} } @fields;
# Support sorting on different fields
if ($sort eq 'name' || $sort eq 'description')
{
@fields = sort { $a->{$sort} cmp $b->{$sort} } @fields;
}
else
{
$sort = 'sortkey' if $sort ne 'id';
@fields = sort { $a->{$sort} <=> $b->{$sort} } @fields;
}
}
return @fields;
}

View File

@ -34,6 +34,7 @@ sub get_login_info {
my ($self) = @_;
my $cgi = Bugzilla->cgi;
my $dbh = Bugzilla->dbh;
################ return { user_id => $cgi->param('user_id') }; # hack
my $ip_addr = remote_ip();
my $login_cookie = $cgi->cookie("Bugzilla_logincookie");

View File

@ -331,13 +331,13 @@ sub sql_group_by {
my $expression = "GROUP BY $needed_columns";
$expression .= ", " . $optional_columns if $optional_columns;
return $expression;
}
sub sql_string_concat {
my ($self, @params) = @_;
return '(' . join(' || ', @params) . ')';
}
@ -413,7 +413,9 @@ sub bz_last_key {
$table, $column);
}
sub bz_check_regexp {
# Check a regexp for validity
sub bz_check_regexp
{
my ($self, $pattern) = @_;
eval { $self->do("SELECT " . $self->sql_regexp($self->quote("a"), $pattern, 1)) };

View File

@ -75,6 +75,7 @@ sub new {
);
my $self = $class->db_new($dsn, $user, $pass, \%attrs);
$self->{dbd} = 'mysql';
# This makes sure that if the tables are encoded as UTF-8, we
# return their data correctly.

View File

@ -71,6 +71,7 @@ sub new {
|| 1000 ) * 1024,
};
my $self = $class->db_new($dsn, $user, $pass, $attrs);
$self->{dbd} = 'oracle';
# Needed by TheSchwartz
$self->{private_bz_dsn} = $dsn;

View File

@ -71,6 +71,7 @@ sub new {
my $attrs = { pg_enable_utf8 => Bugzilla->params->{'utf8'} };
my $self = $class->db_new($dsn, $user, $pass, $attrs);
$self->{dbd} = 'pg';
# all class local variables stored in DBI derived class needs to have
# a prefix 'private_'. See DBI documentation.

View File

@ -192,12 +192,12 @@ use constant DEFAULT_FIELDS => (
type => FIELD_TYPE_SINGLE_SELECT, buglist => 1},
{name => 'component', desc => 'Component', in_new_bugmail => 1,
buglist => 1},
{name => 'assigned_to', desc => 'AssignedTo', in_new_bugmail => 1,
{name => 'assigned_to', desc => 'Assignee', in_new_bugmail => 1,
buglist => 1},
{name => 'reporter', desc => 'ReportedBy', in_new_bugmail => 1,
{name => 'reporter', desc => 'Reporter', in_new_bugmail => 1,
buglist => 1},
{name => 'votes', desc => 'Votes', buglist => 1},
{name => 'qa_contact', desc => 'QAContact', in_new_bugmail => 1,
{name => 'qa_contact', desc => 'QA Contact', in_new_bugmail => 1,
buglist => 1},
{name => 'cc', desc => 'CC', in_new_bugmail => 1},
{name => 'dependson', desc => 'Depends on', in_new_bugmail => 1},
@ -230,7 +230,7 @@ use constant DEFAULT_FIELDS => (
{name => 'deadline', desc => 'Deadline',
in_new_bugmail => 1, buglist => 1},
{name => 'commenter', desc => 'Commenter'},
{name => 'flagtypes.name', desc => 'Flags', buglist => 1},
{name => 'flagtypes.name', desc => 'Flag Types', buglist => 1},
{name => 'requestees.login_name', desc => 'Flag Requestee'},
{name => 'setters.login_name', desc => 'Flag Setter'},
{name => 'work_time', desc => 'Hours Worked', buglist => 1},
@ -239,8 +239,8 @@ use constant DEFAULT_FIELDS => (
{name => 'content', desc => 'Content'},
{name => 'attach_data.thedata', desc => 'Attachment data'},
{name => 'attachments.isurl', desc => 'Attachment is a URL'},
{name => "owner_idle_time", desc => "Time Since Assignee Touched"},
{name => 'see_also', desc => "See Also",
{name => 'owner_idle_time', desc => 'Time Since Assignee Touched'},
{name => 'see_also', desc => 'See Also',
type => FIELD_TYPE_BUG_URLS},
);

View File

@ -53,16 +53,17 @@ use constant UPDATE_COLUMNS => qw(
#### Accessors ######
###############################
sub description { return $_[0]->{'description'}; }
sub description { $_[0]->{description} }
sub bug_count {
sub bug_count
{
my ($self) = @_;
return $self->{'bug_count'} if defined $self->{'bug_count'};
($self->{'bug_count'}) =
Bugzilla->dbh->selectrow_array(
'SELECT COUNT(*) FROM keywords WHERE keywordid = ?',
undef, $self->id);
return $self->{'bug_count'};
return $self->{bug_count} if defined $self->{bug_count};
($self->{bug_count}) = Bugzilla->dbh->selectrow_array(
'SELECT COUNT(*) FROM keywords WHERE keywordid = ?',
undef, $self->id
);
return $self->{bug_count};
}
###############################
@ -76,25 +77,20 @@ sub set_description { $_[0]->set('description', $_[1]); }
#### Subroutines ######
###############################
sub get_all_with_bug_count {
sub get_all_with_bug_count
{
my $class = shift;
my $dbh = Bugzilla->dbh;
my $keywords =
$dbh->selectall_arrayref('SELECT ' . join(', ', DB_COLUMNS) . ',
COUNT(keywords.bug_id) AS bug_count
FROM keyworddefs
LEFT JOIN keywords
ON keyworddefs.id = keywords.keywordid ' .
$dbh->sql_group_by('keyworddefs.id',
'keyworddefs.name,
keyworddefs.description') . '
ORDER BY keyworddefs.name', {'Slice' => {}});
if (!$keywords) {
return [];
}
my $keywords = $dbh->selectall_arrayref(
'SELECT ' . join(', ', DB_COLUMNS) . ', COUNT(keywords.bug_id) AS bug_count' .
' FROM keyworddefs LEFT JOIN keywords ON keyworddefs.id = keywords.keywordid ' .
$dbh->sql_group_by('keyworddefs.id', 'keyworddefs.name, keyworddefs.description') .
' ORDER BY keyworddefs.name', {Slice => {}}
);
return [] unless $keywords;
foreach my $keyword (@$keywords) {
bless($keyword, $class);
bless $keyword, $class;
}
return $keywords;
}

401
Bugzilla/Language/en.pm Normal file
View File

@ -0,0 +1,401 @@
#!/usr/bin/perl
# Internationalisation messages for English Bugzilla
package Bugzilla::Language::en;
use strict;
use Bugzilla::Constants;
my $terms = {
bug => 'bug',
Bug => 'Bug',
abug => 'a bug',
Abug => 'A bug',
aBug => 'a Bug',
ABug => 'A Bug',
bugs => 'bugs',
Bugs => 'Bugs',
zeroSearchResults => 'Zarro Boogs found',
Bugzilla => 'Bugzilla',
};
$Bugzilla::messages->{en} = {
terms => $terms,
operator_descs => {
not => 'NOT',
noop => '---',
equals => 'is equal to',
notequals => 'is not equal to',
anyexact => 'is equal to any of the strings',
substring => 'contains the string',
casesubstring => 'contains the string (exact case)',
notsubstring => 'does not contain the string',
anywordssubstr => 'contains any of the strings',
allwordssubstr => 'contains all of the strings',
nowordssubstr => 'contains none of the strings',
regexp => 'matches regular expression',
notregexp => 'does not match regular expression',
lessthan => 'is less than',
lessthaneq => 'is less than or equal to',
greaterthan => 'is greater than',
greaterthaneq => 'is greater than or equal to',
anywords => 'contains any of the words',
allwords => 'contains all of the words',
nowords => 'contains none of the words',
changedbefore => 'changed before',
changedafter => 'changed after',
changedfrom => 'changed from',
changedto => 'changed to',
changedby => 'changed by',
matches => 'matches',
notmatches => 'does not match',
insearch => 'matched by saved search',
notinsearch => 'not matched by saved search',
},
field_types => {
FIELD_TYPE_UNKNOWN() => 'Unknown Type',
FIELD_TYPE_FREETEXT() => 'Free Text',
FIELD_TYPE_SINGLE_SELECT() => 'Drop Down',
FIELD_TYPE_MULTI_SELECT() => 'Multiple-Selection Box',
FIELD_TYPE_TEXTAREA() => 'Large Text Box',
FIELD_TYPE_DATETIME() => 'Date/Time',
FIELD_TYPE_BUG_ID() => $terms->{Bug}.' ID',
FIELD_TYPE_NUMERIC() => 'Numeric',
},
field_descs => {
actual_time => 'Actual Hours',
alias => 'Alias',
assigned_to => 'Assignee',
blocked => 'Blocks',
bug_file_loc => 'URL',
bug_group => 'Group',
bug_id => $terms->{Bug}.' ID',
bug_severity => 'Severity',
bug_status => 'Status',
cc => 'CC',
classification => 'Classification',
cclist_accessible => 'CC list accessible',
commenter => 'Commenter',
component_id => 'Component ID',
component => 'Component',
content => 'Content',
'[Bug creation]' => 'Creation date',
opendate => 'Creation date',
creation_ts => 'Creation date',
deadline => 'Deadline',
changeddate => 'Changed',
delta_ts => 'Changed',
dependson => 'Depends on',
dup_id => 'Duplicate',
estimated_time => 'Orig. Est.',
everconfirmed => 'Ever confirmed',
keywords => 'Keywords',
longdesc => 'Comment',
newcc => 'CC',
op_sys => 'OS',
owner_idle_time => 'Time Since Assignee Touched',
percentage_complete => '%Complete',
priority => 'Priority',
product_id => 'Product ID',
product => 'Product',
qa_contact => 'QA Contact',
remaining_time => 'Hours Left',
rep_platform => 'Hardware',
reporter => 'Reporter',
reporter_accessible => 'Reporter accessible',
resolution => 'Resolution',
see_also => 'See Also',
setting => 'Setting',
settings => 'Settings',
short_desc => 'Summary',
status_whiteboard => 'Whiteboard',
target_milestone => 'Target Milestone',
version => 'Version',
votes => 'Votes',
work_time => 'Hours Worked',
interval_time => 'Period Worktime',
comment0 => 'First Comment',
'longdescs.isprivate' => 'Comment is private',
'attach_data.thedata' => 'Attachment data',
'attachments.description' => 'Attachment description',
'attachments.filename' => 'Attachment filename',
'attachments.mimetype' => 'Attachment mime type',
'attachments.ispatch' => 'Attachment is patch',
'attachments.isobsolete' => 'Attachment is obsolete',
'attachments.isprivate' => 'Attachment is private',
'attachments.isurl' => 'Attachment is a URL',
'attachments.submitter' => 'Attachment creator',
'flagtypes.name' => 'Flags',
'requestees.login_name' => 'Flag Requestee',
'setters.login_name' => 'Flag Setter',
},
};
__END__
#!/usr/bin/perl
package Bugzilla::Language::en;
use strict;
use Bugzilla::Constants;
my $terms = {
bug => 'bug',
Bug => 'Bug',
abug => 'a bug',
Abug => 'A bug',
aBug => 'a Bug',
ABug => 'A Bug',
bugs => 'bugs',
Bugs => 'Bugs',
zeroSearchResults => 'Zarro Boogs found',
Bugzilla => 'Bugzilla',
};
$Bugzilla::messages->{en} = {
terms => $terms,
operator_descs => {
not => 'NOT',
noop => '---',
equals => 'is equal to',
notequals => 'is not equal to',
anyexact => 'is equal to any of the strings',
substring => 'contains the string',
casesubstring => 'contains the string (exact case)',
notsubstring => 'does not contain the string',
anywordssubstr => 'contains any of the strings',
allwordssubstr => 'contains all of the strings',
nowordssubstr => 'contains none of the strings',
regexp => 'matches regular expression',
notregexp => 'does not match regular expression',
lessthan => 'is less than',
lessthaneq => 'is less than or equal to',
greaterthan => 'is greater than',
greaterthaneq => 'is greater than or equal to',
anywords => 'contains any of the words',
allwords => 'contains all of the words',
nowords => 'contains none of the words',
changedbefore => 'changed before',
changedafter => 'changed after',
changedfrom => 'changed from',
changedto => 'changed to',
changedby => 'changed by',
matches => 'matches',
notmatches => 'does not match',
insearch => 'matched by saved search',
notinsearch => 'not matched by saved search',
},
field_types => {
FIELD_TYPE_UNKNOWN => 'Unknown Type',
FIELD_TYPE_FREETEXT => 'Free Text',
FIELD_TYPE_SINGLE_SELECT => 'Drop Down',
FIELD_TYPE_MULTI_SELECT => 'Multiple-Selection Box',
FIELD_TYPE_TEXTAREA => 'Large Text Box',
FIELD_TYPE_DATETIME => 'Date/Time',
FIELD_TYPE_BUG_ID => $terms->{Bug}.' ID',
FIELD_TYPE_NUMERIC => 'Numeric',
},
field_descs => {
actual_time => 'Actual Hours',
alias => 'Alias',
assigned_to => 'Assignee',
blocked => 'Blocks',
bug_file_loc => 'URL',
bug_group => 'Group',
bug_id => $terms->{Bug}.' ID',
bug_severity => 'Severity',
bug_status => 'Status',
cc => 'CC',
classification => 'Classification',
cclist_accessible => 'CC list accessible',
commenter => 'Commenter',
component_id => 'Component ID',
component => 'Component',
content => 'Content',
'[Bug creation]' => 'Creation date',
opendate => 'Creation date',
creation_ts => 'Creation date',
deadline => 'Deadline',
changeddate => 'Changed',
delta_ts => 'Changed',
dependson => 'Depends on',
dup_id => 'Duplicate',
estimated_time => 'Orig. Est.',
everconfirmed => 'Ever confirmed',
keywords => 'Keywords',
longdesc => 'Comment',
newcc => 'CC',
op_sys => 'OS',
owner_idle_time => 'Time Since Assignee Touched',
percentage_complete => '%Complete',
priority => 'Priority',
product_id => 'Product ID',
product => 'Product',
qa_contact => 'QA Contact',
remaining_time => 'Hours Left',
rep_platform => 'Hardware',
reporter => 'Reporter',
reporter_accessible => 'Reporter accessible',
resolution => 'Resolution',
see_also => 'See Also',
setting => 'Setting',
settings => 'Settings',
short_desc => 'Summary',
status_whiteboard => 'Whiteboard',
target_milestone => 'Target Milestone',
version => 'Version',
votes => 'Votes',
work_time => 'Hours Worked',
interval_time => 'Period Worktime',
comment0 => 'First Comment',
'longdescs.isprivate' => 'Comment is private',
'attach_data.thedata' => 'Attachment data',
'attachments.description' => 'Attachment description',
'attachments.filename' => 'Attachment filename',
'attachments.mimetype' => 'Attachment mime type',
'attachments.ispatch' => 'Attachment is patch',
'attachments.isobsolete' => 'Attachment is obsolete',
'attachments.isprivate' => 'Attachment is private',
'attachments.isurl' => 'Attachment is a URL',
'attachments.submitter' => 'Attachment creator',
'flagtypes.name' => 'Flags',
'requestees.login_name' => 'Flag Requestee',
'setters.login_name' => 'Flag Setter',
},
};
__END__
#!/usr/bin/perl
# Internationalisation messages for English Bugzilla
package Bugzilla::Language::en;
use strict;
use Bugzilla::Constants;
my $terms = {
bug => 'bug',
Bug => 'Bug',
abug => 'a bug',
Abug => 'A bug',
aBug => 'a Bug',
ABug => 'A Bug',
bugs => 'bugs',
Bugs => 'Bugs',
zeroSearchResults => 'Zarro Boogs found',
Bugzilla => 'Bugzilla',
};
$Bugzilla::messages->{en} = {
terms => $terms,
operator_descs => {
not => 'NOT',
noop => '---',
equals => 'is equal to',
notequals => 'is not equal to',
anyexact => 'is equal to any of the strings',
substring => 'contains the string',
casesubstring => 'contains the string (exact case)',
notsubstring => 'does not contain the string',
anywordssubstr => 'contains any of the strings',
allwordssubstr => 'contains all of the strings',
nowordssubstr => 'contains none of the strings',
regexp => 'matches regular expression',
notregexp => 'does not match regular expression',
lessthan => 'is less than',
lessthaneq => 'is less than or equal to',
greaterthan => 'is greater than',
greaterthaneq => 'is greater than or equal to',
anywords => 'contains any of the words',
allwords => 'contains all of the words',
nowords => 'contains none of the words',
changedbefore => 'changed before',
changedafter => 'changed after',
changedfrom => 'changed from',
changedto => 'changed to',
changedby => 'changed by',
matches => 'matches',
notmatches => 'does not match',
insearch => 'matched by saved search',
notinsearch => 'not matched by saved search',
},
field_types => {
FIELD_TYPE_UNKNOWN() => 'Unknown Type',
FIELD_TYPE_FREETEXT() => 'Free Text',
FIELD_TYPE_SINGLE_SELECT() => 'Drop Down',
FIELD_TYPE_MULTI_SELECT() => 'Multiple-Selection Box',
FIELD_TYPE_TEXTAREA() => 'Large Text Box',
FIELD_TYPE_DATETIME() => 'Date/Time',
FIELD_TYPE_BUG_ID() => $terms->{Bug}.' ID',
FIELD_TYPE_NUMERIC() => 'Numeric',
},
field_descs => {
actual_time => 'Actual Hours',
alias => 'Alias',
assigned_to => 'Assignee',
blocked => 'Blocks',
bug_file_loc => 'URL',
bug_group => 'Group',
bug_id => $terms->{Bug}.' ID',
bug_severity => 'Severity',
bug_status => 'Status',
cc => 'CC',
classification => 'Classification',
cclist_accessible => 'CC list accessible',
commenter => 'Commenter',
component_id => 'Component ID',
component => 'Component',
content => 'Content',
'[Bug creation]' => 'Creation date',
opendate => 'Creation date',
creation_ts => 'Creation date',
deadline => 'Deadline',
changeddate => 'Changed',
delta_ts => 'Changed',
dependson => 'Depends on',
dup_id => 'Duplicate',
estimated_time => 'Orig. Est.',
everconfirmed => 'Ever confirmed',
keywords => 'Keywords',
longdesc => 'Comment',
newcc => 'CC',
op_sys => 'OS',
owner_idle_time => 'Time Since Assignee Touched',
percentage_complete => '%Complete',
priority => 'Priority',
product_id => 'Product ID',
product => 'Product',
qa_contact => 'QA Contact',
remaining_time => 'Hours Left',
rep_platform => 'Hardware',
reporter => 'Reporter',
reporter_accessible => 'Reporter accessible',
resolution => 'Resolution',
see_also => 'See Also',
setting => 'Setting',
settings => 'Settings',
short_desc => 'Summary',
status_whiteboard => 'Whiteboard',
target_milestone => 'Target Milestone',
version => 'Version',
votes => 'Votes',
work_time => 'Hours Worked',
interval_time => 'Period Worktime',
comment0 => 'First Comment',
'longdescs.isprivate' => 'Comment is private',
'attach_data.thedata' => 'Attachment data',
'attachments.description' => 'Attachment description',
'attachments.filename' => 'Attachment filename',
'attachments.mimetype' => 'Attachment mime type',
'attachments.ispatch' => 'Attachment is patch',
'attachments.isobsolete' => 'Attachment is obsolete',
'attachments.isprivate' => 'Attachment is private',
'attachments.isurl' => 'Attachment is a URL',
'attachments.submitter' => 'Attachment creator',
'flagtypes.name' => 'Flags',
'requestees.login_name' => 'Flag Requestee',
'setters.login_name' => 'Flag Setter',
},
};
__END__

View File

@ -88,8 +88,8 @@ sub _init {
$sql = "$id_field = ?";
@values = ($id);
} else {
unless (defined $param->{name} || (defined $param->{'condition'}
&& defined $param->{'values'}))
unless (defined $param->{name} || (defined $param->{condition}
&& defined $param->{values}))
{
ThrowCodeError('bad_arg', { argument => 'param',
function => $class . '::new',
@ -100,14 +100,14 @@ sub _init {
$sql = $dbh->sql_istrcmp($name_field, '?');
push(@values, $param->{name});
}
elsif (defined $param->{'condition'} && defined $param->{'values'}) {
elsif (defined $param->{condition} && defined $param->{values}) {
caller->isa('Bugzilla::Object')
|| ThrowCodeError('protection_violation',
{ caller => caller,
function => $class . '::new',
argument => 'condition/values' });
$sql = $param->{'condition'};
push(@values, @{$param->{'values'}});
$sql = $param->{condition};
push(@values, @{$param->{values}});
}
map { trick_taint($_) } @values;

File diff suppressed because it is too large Load Diff

View File

@ -526,7 +526,7 @@ sub _special_field_syntax {
return 1;
}
return 0;
return 0;
}
sub _default_quicksearch_word {

View File

@ -306,7 +306,7 @@ sub quoteUrls {
# we have to do this in one pattern, and so this is semi-messy.
# Also, we can't use $bug_re?$comment_re? because that will match the
# empty string
my $bug_word = template_var('terms')->{bug};
my $bug_word = Bugzilla->messages->{terms}->{bug};
my $bug_re = qr/\Q$bug_word\E\s*\#?\s*(\d+)/i;
my $comment_re = qr/comment\s*\#?\s*(\d+)/i;
$text =~ s~\b($bug_re(?:\s*,?\s*$comment_re)?|$comment_re)
@ -802,6 +802,35 @@ sub create {
# Default variables for all templates
VARIABLES => {
terms => Bugzilla->messages->{terms},
field_descs => Bugzilla->messages->{terms},
lc_messages => Bugzilla->messages,
# HTML <select>
html_select => sub
{
my ($name, $values, $valuenames, $selected, $args) = @_;
$name = html_quote($name);
my $html = '<select name="'.$name.'" id="'.$name.'">';
if (ref $valuenames eq 'ARRAY')
{
$values = [ map { $_->{name} } @$valuenames ];
$valuenames = { map { $_->{name} => $_->{title} } @$valuenames };
}
else
{
$values ||= [ keys %$valuenames ];
}
for (@$values)
{
$html .= '<option value="'.html_quote($_).'"';
$html .= ' selected="selected"' if $selected eq $_;
$html .= '>'.html_quote($valuenames->{$_}).'</option>';
}
$html .= '</select>';
return $html;
},
# Function for retrieving global parameters.
'Param' => sub { return Bugzilla->params->{$_[0]}; },
@ -891,11 +920,6 @@ sub create {
'feature_enabled' => sub { return Bugzilla->feature(@_); },
# field_descs can be somewhat slow to generate, so we generate
# it only once per-language no matter how many times
# $template->process() is called.
'field_descs' => sub { return template_var('field_descs') },
'install_string' => \&Bugzilla::Install::Util::install_string,
# These don't work as normal constants.

View File

@ -1534,6 +1534,7 @@ sub wants_bug_mail {
# You role is new if the bug itself is.
# Only makes sense for the assignee, QA contact and the CC list.
# FIXME Это неудобно, потому что неочевидно для пользователя!
if ($relationship == REL_ASSIGNEE
|| $relationship == REL_QA
|| $relationship == REL_CC)

View File

@ -32,24 +32,21 @@ use utf8;
use strict;
use base qw(Exporter);
@Bugzilla::Util::EXPORT = qw(trick_taint detaint_natural
trick_taint_copy
detaint_signed
html_quote url_quote xml_quote
css_class_quote html_light_quote url_decode
i_am_cgi correct_urlbase remote_ip
lsearch do_ssl_redirect_if_required use_attachbase
diff_arrays
trim wrap_hard wrap_comment find_wrap_point
format_time format_time_decimal validate_date
validate_time datetime_from
file_mod_time is_7bit_clean
bz_crypt generate_random_password
validate_email_syntax clean_text
stem_text
intersect
get_text template_var disable_utf8 bz_encode_json
xml_element xml_element_quote xml_dump_simple);
@Bugzilla::Util::EXPORT = qw(
trick_taint detaint_natural trick_taint_copy detaint_signed
html_quote url_quote xml_quote css_class_quote html_light_quote url_decode
i_am_cgi correct_urlbase remote_ip lsearch
do_ssl_redirect_if_required use_attachbase
diff_arrays list
trim wrap_hard wrap_comment find_wrap_point
format_time format_time_decimal validate_date validate_time datetime_from
file_mod_time is_7bit_clean
bz_crypt generate_random_password
validate_email_syntax clean_text
stem_text intersect
get_text disable_utf8 bz_encode_json
xml_element xml_element_quote xml_dump_simple
);
use Bugzilla::Constants;
@ -707,21 +704,21 @@ sub clean_text {
return trim($dtext);
}
# Довольно некрасивый хак для бага см.ниже - на багах с длинным числом комментов
# quoteUrls вызывает на каждый коммент get_text('term', { term => 'bug' }),
# что приводит к ужасной производительности. например, на баге с 703
# комментами в 10-15 раз ухудшение по сравнению с Bugzilla 2.x.
# Избавляемся от этого.
# CustIS Bug 40933 ФАКМОЙМОЗГ! ВРОТМНЕНОГИ! КТО ТАК ПИШЕТ?!!!!
# ВОТ он, антипаттерн разработки на TT, ведущий к тормозам...
# ALSO CustIS Bug 52322
sub get_text {
# FUCKMYBRAIN! CustIS Bugs 40933, 52322.
# Here is the Template Toolkit development anti-pattern!
# Originally, Bugzilla used to call get_text('term', { term => 'bug' })
# from quoteUrls() for each comment. This leaded to TERRIBLE performance
# on "long" bugs compared to Bugzilla 2.x!
sub get_text
{
my ($name, $vars) = @_;
my $template = Bugzilla->template_inner;
$vars ||= {};
$vars->{'message'} = $name;
$vars->{message} = $name;
my $message;
if (!$template->process('global/message.txt.tmpl', $vars, \$message)) {
if (!$template->process('global/message.txt.tmpl', $vars, \$message))
{
require Bugzilla::Error;
Bugzilla::Error::ThrowTemplateError($template->error());
}
@ -730,27 +727,6 @@ sub get_text {
return $message;
}
sub template_var {
my $name = shift;
my $cache = Bugzilla->request_cache->{util_template_var} ||= {};
my $template = Bugzilla->template_inner;
my $lang = Bugzilla->request_cache->{language};
return $cache->{$lang}->{$name} if defined $cache->{$lang};
my %vars;
# Note: If we suddenly start needing a lot of template_var variables,
# they should move into their own template, not field-descs.
my $output;
my $result = $template->process('global/field-descs.none.tmpl',
{ vars => \%vars, in_template_var => 1 }, \$output);
# Bugzilla::Error can't be "use"d in Bugzilla::Util.
if (!$result) {
require Bugzilla::Error;
Bugzilla::Error::ThrowTemplateError($template->error);
}
$cache->{$lang} = \%vars;
return $vars{$name};
}
sub disable_utf8 {
if (Bugzilla->params->{'utf8'}) {
binmode STDOUT, ':bytes'; # Turn off UTF8 encoding.
@ -872,8 +848,15 @@ sub bz_encode_json
return $var;
}
1;
sub list($)
{
my ($array) = @_;
return () unless defined $array;
return ($array) if ref $array ne 'ARRAY';
return @$array;
}
1;
__END__
=head1 NAME
@ -1147,14 +1130,6 @@ A string.
=back
=item C<template_var>
This is a method of getting the value of a variable from a template in
Perl code. The available variables are in the C<global/field-descs.none.tmpl>
template. Just pass in the name of the variable that you want the value of.
=back
=head2 Formatting Time

View File

@ -584,7 +584,7 @@ sub insert {
# Operation result to save into session (CustIS Bug 64562)
my $session_data = {
title => "Attachment ".$attachment->id." added to ".template_var('terms')->{Bug}." ".$attachment->bug_id,
title => "Attachment ".$attachment->id." added to ".Bugzilla->messages->{terms}->{Bug}." ".$attachment->bug_id,
sent => [$send_results],
sent_attrs => {
added_attachments => [ {

View File

@ -801,70 +801,68 @@ if (!$order || $order =~ /^reuse/i) {
}
}
if ($order) {
# FIXME переместить в Bugzilla::Search
my $old_orders = {
'' => 'bug_status,priority,assigned_to,bug_id', # Default
'bug number' => 'bug_id',
'importance' => 'priority,bug_severity,bug_id',
'assignee' => 'assigned_to,bug_status,priority,bug_id',
'last changed' => 'delta_ts,bug_status,priority,assigned_to,bug_id',
};
if ($order)
{
# Convert the value of the "order" form field into a list of columns
# by which to sort the results.
ORDER: for ($order) {
/^Bug Number$/ && do {
$order = "bug_id";
last ORDER;
};
/^Importance$/ && do {
$order = "priority,bug_severity";
last ORDER;
};
/^Assignee$/ && do {
$order = "assigned_to,bug_status,priority,bug_id";
last ORDER;
};
/^Last Changed$/ && do {
$order = "delta_ts,bug_status,priority,assigned_to,bug_id";
last ORDER;
};
do {
my (@order, @invalid_fragments);
if ($old_orders->{lc $order})
{
$order = $old_orders->{lc $order};
}
else
{
my (@order, @invalid_fragments);
# A custom list of columns. Make sure each column is valid.
foreach my $fragment (split(/,/, $order)) {
$fragment = trim($fragment);
next unless $fragment;
my ($column_name, $direction) = split_order_term($fragment);
$column_name = translate_old_column($column_name);
# A custom list of columns. Make sure each column is valid.
foreach my $fragment (split(/,/, $order))
{
$fragment = trim($fragment);
next unless $fragment;
my ($column_name, $direction) = split_order_term($fragment);
$column_name = translate_old_column($column_name);
# Special handlings for certain columns
next if $column_name eq 'relevance' && !$fulltext;
# Special handlings for certain columns
next if $column_name eq 'relevance' && !$fulltext;
# If we are sorting by votes, sort in descending order if
# no explicit sort order was given.
if ($column_name eq 'votes' && !$direction) {
$direction = "DESC";
}
if (exists $columns->{$column_name}) {
$direction = " $direction" if $direction;
push(@order, "$column_name$direction");
}
else {
push(@invalid_fragments, $fragment);
}
}
if (scalar @invalid_fragments) {
$vars->{'message'} = 'invalid_column_name';
$vars->{'invalid_fragments'} = \@invalid_fragments;
# If we are sorting by votes, sort in descending order if
# no explicit sort order was given.
if ($column_name eq 'votes' && !$direction)
{
$direction = "DESC";
}
$order = join(",", @order);
# Now that we have checked that all columns in the order are valid,
# detaint the order string.
trick_taint($order) if $order;
};
if (exists $columns->{$column_name})
{
$direction = " $direction" if $direction;
push @order, "$column_name$direction";
}
else
{
push @invalid_fragments, $fragment;
}
}
if (scalar @invalid_fragments)
{
$vars->{message} = 'invalid_column_name';
$vars->{invalid_fragments} = \@invalid_fragments;
}
$order = join(",", @order);
# Now that we have checked that all columns in the order are valid,
# detaint the order string.
trick_taint($order) if $order;
}
}
if (!$order) {
# DEFAULT
$order = "bug_status,priority,assigned_to,bug_id";
}
$order = $old_orders->{''} if !$order;
my @orderstrings = split(/,\s*/, $order);
@ -882,7 +880,7 @@ my $search = new Bugzilla::Search('fields' => \@selectcolumns,
'params' => $params,
'order' => \@orderstrings);
my $query = $search->getSQL();
$vars->{'search_description'} = $search->search_description;
$vars->{search_description} = $search->search_description_html;
if (defined $cgi->param('limit')) {
my $limit = $cgi->param('limit');
@ -1131,7 +1129,7 @@ $vars->{'order_dir'} = [ map { s/ DESC$// ? 1 : 0 } @{$vars->{'order_columns'}}
$vars->{'caneditbugs'} = 1;
$vars->{'time_info'} = $time_info;
$vars->{query_params} = $params->Vars; # now used only in superworktime
$vars->{query_params} = { %{ $params->Vars } }; # now used only in superworktime
$vars->{query_params}->{chfieldfrom} = $Bugzilla::Search::interval_from;
$vars->{query_params}->{chfieldto} = $Bugzilla::Search::interval_to;
@ -1203,9 +1201,7 @@ if ($dotweak && scalar @bugs) {
# Convert bug statuses to their ID.
my @bug_statuses = map {$dbh->quote($_)} keys %$bugstatuses;
my $bug_status_ids =
$dbh->selectcol_arrayref('SELECT id FROM bug_status
WHERE ' . $dbh->sql_in('value', \@bug_statuses));
my $bug_status_ids = $dbh->selectcol_arrayref('SELECT id FROM bug_status WHERE ' . $dbh->sql_in('value', \@bug_statuses));
# This query collects new statuses which are common to all current bug statuses.
# It also accepts transitions where the bug status doesn't change.
@ -1244,11 +1240,29 @@ if ($dotweak && scalar @bugs) {
# If we're editing a stored query, use the existing query name as default for
# the "Remember search as" field.
$vars->{'defaultsavename'} = $cgi->param('query_based_on');
$vars->{'query_sql_time'} = sprintf("%.2f", $query_sql_time);
$vars->{defaultsavename} = $cgi->param('query_based_on');
$vars->{query_sql_time} = sprintf("%.2f", $query_sql_time);
Bugzilla::Hook::process('after-buglist', { vars => $vars });
$vars->{abbrev} = {
bug_severity => { maxlength => 3, title => "Sev" },
priority => { maxlength => 3, title => "Pri" },
rep_platform => { maxlength => 3, title => "Plt" },
bug_status => { maxlength => 4 },
assigned_to => { maxlength => 30, ellipsis => "..." },
reporter => { maxlength => 30, ellipsis => "..." },
qa_contact => { maxlength => 30, ellipsis => "..." },
resolution => { maxlength => 4 },
short_short_desc => { maxlength => 60, ellipsis => "..." },
status_whiteboard => { title => "Whiteboard" },
component => { maxlength => 8, title => "Comp" },
product => { maxlength => 8 },
op_sys => { maxlength => 4 },
target_milestone => { title => "Milestone" },
percentage_complete => { format_value => "%d %%" },
};
################################################################################
# HTTP Header Generation
################################################################################

View File

@ -16,7 +16,7 @@ use Bugzilla::Token;
my $template = Bugzilla->template;
my $user = Bugzilla->login(LOGIN_REQUIRED);
my $cgi = Bugzilla->cgi;
my $params = $cgi->Vars;
my $params = { %{ $cgi->Vars } };
my $vars = {};
$user->in_group('bz_editcheckers')

View File

@ -41,22 +41,25 @@ my $token = $cgi->param('token');
$cgi->send_header();
$vars->{field_types} = Bugzilla->messages->{field_types};
# List all existing custom fields if no action is given.
if (!$action) {
if (!$action)
{
$template->process('admin/custom_fields/list.html.tmpl', $vars)
|| ThrowTemplateError($template->error());
}
# Interface to add a new custom field.
elsif ($action eq 'add') {
$vars->{'token'} = issue_session_token('add_field');
elsif ($action eq 'add')
{
$vars->{token} = issue_session_token('add_field');
$template->process('admin/custom_fields/create.html.tmpl', $vars)
|| ThrowTemplateError($template->error());
}
elsif ($action eq 'new') {
elsif ($action eq 'new')
{
check_token_data($token, 'add_field');
my $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'),
@ -80,7 +83,8 @@ elsif ($action eq 'new') {
$template->process('admin/custom_fields/list.html.tmpl', $vars)
|| ThrowTemplateError($template->error());
}
elsif ($action eq 'edit') {
elsif ($action eq 'edit')
{
my $name = $cgi->param('name') || ThrowUserError('field_missing_name');
my $field = Bugzilla->get_field($name);
$field || ThrowUserError('customfield_nonexistent', {'name' => $name});
@ -91,7 +95,8 @@ elsif ($action eq 'edit') {
$template->process('admin/custom_fields/edit.html.tmpl', $vars)
|| ThrowTemplateError($template->error());
}
elsif ($action eq 'update') {
elsif ($action eq 'update')
{
check_token_data($token, 'edit_field');
my $name = $cgi->param('name');
@ -125,7 +130,8 @@ elsif ($action eq 'update') {
$template->process('admin/custom_fields/list.html.tmpl', $vars)
|| ThrowTemplateError($template->error());
}
elsif ($action eq 'del') {
elsif ($action eq 'del')
{
my $name = $cgi->param('name');
# Validate field.
@ -144,7 +150,8 @@ elsif ($action eq 'del') {
$template->process('admin/custom_fields/confirm-delete.html.tmpl', $vars)
|| ThrowTemplateError($template->error());
}
elsif ($action eq 'delete') {
elsif ($action eq 'delete')
{
check_token_data($token, 'delete_field');
my $name = $cgi->param('name');
@ -161,15 +168,16 @@ elsif ($action eq 'delete') {
# Calling remove_from_db will check if field can be deleted.
# If the field cannot be deleted, it will throw an error.
$field->remove_from_db();
$vars->{'field'} = $field;
$vars->{'message'} = 'custom_field_deleted';
delete_token($token);
$template->process('admin/custom_fields/list.html.tmpl', $vars)
|| ThrowTemplateError($template->error());
}
else {
else
{
ThrowUserError('no_valid_action', {'field' => 'custom_field'});
}

View File

@ -76,7 +76,7 @@ if (@categoryActions = grep(/^categoryAction-.+/, $cgi->param())) {
exit;
}
if ($action eq 'list') { list(); }
if ($action eq 'list') { ft_list(); }
elsif ($action eq 'enter') { edit($action); }
elsif ($action eq 'copy') { edit($action); }
elsif ($action eq 'edit') { edit($action); }
@ -95,7 +95,7 @@ exit;
# Functions
################################################################################
sub list {
sub ft_list {
my $product = validateProduct(scalar $cgi->param('product'));
my $component = validateComponent($product, scalar $cgi->param('component'));
my $product_id = $product ? $product->id : 0;

View File

@ -398,19 +398,6 @@ CardDropTarget.prototype.onMove = function(pos)
else
this.element.style.borderRight = '5px solid red';
};
// Универсальное добавление обработчика события
var addListener = function() {
if (window.addEventListener) {
return function(el, type, fn) { el.addEventListener(type, fn, false); };
} else if (window.attachEvent) {
return function(el, type, fn) {
var f = function() { return fn.call(el, window.event); };
el.attachEvent('on'+type, f);
};
} else {
return function(el, type, fn) { element['on'+type] = fn; }
}
}();
// 2 если hash пуст
// 1 если в нём один ключ key
// 0 если в нём есть ключ, не равный key

View File

@ -6,6 +6,7 @@ use strict;
use base qw(Bugzilla::Object Exporter);
use JSON;
use Bugzilla::Search;
use Bugzilla::Search::Saved;
use Bugzilla::Error;
@ -77,9 +78,12 @@ sub refresh_sql
fields => [ 'bug_id' ],
user => Bugzilla::User->super_user,
);
my $sql = $search->getSQL();
$sql =~ s/ORDER\s+BY.*?$//iso;
$sql =~ s/^\s*SELECT.*?FROM//iso;
my $terms = Bugzilla::Search::simplify_expression([
'AND_MANY', { term => 'bugs.bug_id=?' },
$search->{terms_without_security}
]);
my $sql = $search->get_expression_sql($terms);
$sql =~ s/^\s*SELECT.*?FROM/SELECT $self->{id} FROM/;
$self->set_sql_code($sql);
}

View File

@ -1,7 +1,7 @@
#!/usr/bin/perl
# CustIS Bug 68921 - "Предикаты проверки корректности"
# - Задаётся сохранённый запрос поиска.
# - Принимается что баги, соответствующие (или НЕ соответствующие) этому запросу
# - Принимается, что баги, соответствующие (или НЕ соответствующие) этому запросу
# до (или после) любых изменений - некорректные, и надо выдать предупреждение или ошибку.
# - Выставляется флажок, можно ли всё-таки оставлять комментарии без рабочего времени.
@ -56,8 +56,6 @@ sub check
if (($_->flags & $mask) == $flags)
{
$s = $_->sql_code;
$i = $_->id;
$s =~ s/^(.*)(GROUP\s+BY)/SELECT $i id FROM $1 AND bugs.bug_id=? $2/iso;
push @$sql, $s;
push @bind, $bug_id;
}
@ -256,7 +254,14 @@ sub savedsearch_post_update
sub install_before_final_checks
{
Bugzilla->request_cache->{user} = Bugzilla::User->super_user;
eval { $_->update } for Bugzilla::Checker->get_all;
for (Bugzilla::Checker->get_all)
{
eval { $_->update };
if ($@)
{
warn $@;
}
}
return 1;
}

View File

@ -13,48 +13,13 @@ sub buglist_static_columns
my $columns = $args->{columns};
my $dbh = Bugzilla->dbh;
$columns->{dependson} = {
name => "(SELECT ".$dbh->sql_group_concat('bugblockers.dependson', "','")." FROM dependencies bugblockers WHERE bugblockers.blocked=bugs.bug_id)",
title => "Bug dependencies",
};
$columns->{blocked} = {
name => "(SELECT ".$dbh->sql_group_concat('bugblocked.blocked', "','")." FROM dependencies bugblocked WHERE bugblocked.dependson=bugs.bug_id)",
title => "Bugs blocked",
};
$columns->{flags} = {
name =>
"(SELECT ".$dbh->sql_group_concat($dbh->sql_string_concat('col_ft.name', 'col_f.status'), "', '")."
FROM flags col_f JOIN flagtypes col_ft ON col_f.type_id=col_ft.id
WHERE col_f.bug_id=bugs.bug_id AND (col_ft.is_requesteeble=0 OR col_ft.is_requestable=0))",
title => "Flags",
};
$columns->{requests} = {
name =>
"(SELECT ".
$dbh->sql_group_concat(
$dbh->sql_string_concat(
'col_ft.name', 'col_f.status',
'CASE WHEN col_p.login_name IS NULL THEN \'\' ELSE '.
$dbh->sql_string_concat("' '", 'col_p.login_name').' END'
), "', '"
)."
FROM flags col_f JOIN flagtypes col_ft ON col_f.type_id=col_ft.id
LEFT JOIN profiles col_p ON col_f.requestee_id=col_p.userid
WHERE col_f.bug_id=bugs.bug_id AND col_ft.is_requesteeble=1 AND col_ft.is_requestable=1)",
title => "Requests",
};
# CustIS Bug 68921 (see also Bugzilla::Search)
$columns->{interval_time} = { %{$columns->{work_time}} };
$columns->{interval_time}->{title} = 'Period worktime';
# CustIS Bug 71955 - first comment to the bug
$columns->{comment0} = {
title => "First Comment",
};
$columns->{lastcommenter} = {
title => "Last Commenter",
};
### Testopia ###
$columns->{test_cases} = {
@ -83,9 +48,28 @@ sub buglist_columns
my $columns = $args->{columns};
# CustIS Bug 71955 - first comment to the bug
# FIXME можно сделать JOIN'ом по bug_when=creation_ts
# но тогда дополнительно надо COALESCE на подзапрос с isprivate
# в случае isprivate.
my $hint = '';
my $dbh = Bugzilla->dbh;
if ($dbh->isa('Bugzilla::DB::Mysql'))
{
$hint = ' FORCE INDEX (longdescs_bug_id_idx)';
}
my $priv = (Bugzilla->user->is_insider ? "" : "AND ldc0.isprivate=0 ");
$columns->{comment0}->{name} =
"(SELECT thetext FROM longdescs ldc0 WHERE ldc0.bug_id = bugs.bug_id ".
(Bugzilla->user->is_insider ? "" : "AND ldc0.isprivate=0 ")." ORDER BY ldc0.bug_when LIMIT 1)";
"(SELECT thetext FROM longdescs ldc0$hint WHERE ldc0.bug_id = bugs.bug_id $priv".
" ORDER BY ldc0.bug_when LIMIT 1)";
my $login = 'ldp0.login_name';
if (!Bugzilla->user->id)
{
$login = $dbh->sql_string_until($login, $dbh->quote('@'));
}
$columns->{lastcommenter}->{name} =
"(SELECT $login FROM longdescs ldc0$hint".
" INNER JOIN profiles ldp0 ON ldp0.userid=ldc0.who WHERE ldc0.bug_id = bugs.bug_id $priv".
" ORDER BY ldc0.bug_when DESC LIMIT 1)";
return 1;
}

View File

@ -1,5 +1,3 @@
[% PROCESS "global/field-descs.none.tmpl" %]
[% PROCESS global/header.html.tmpl
title = 'Изменения не удовлетворяют проверкам' %]

View File

@ -54,7 +54,7 @@ package Testopia::Table;
use strict;
use Bugzilla;
use Bugzilla::Util;
use Bugzilla::Util qw(!list);
use Bugzilla::Error;
use Testopia::Util;
use Testopia::TestCase;

View File

@ -27,8 +27,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[% PROCESS global/variables.none.tmpl %]
[% title = "Admin Settings for Testopia" %]
[%############################################################################%]

View File

@ -20,8 +20,6 @@
# Greg Hendricks <ghendricks@novell.com>
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS global/header.html.tmpl
title = "Search by Attachment Number"

View File

@ -30,7 +30,6 @@
#
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/style.none.tmpl %]

View File

@ -20,8 +20,6 @@
# Greg Hendricks <ghendricks@novell.com>
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS global/header.html.tmpl
title = "Search by Test Case Number"

View File

@ -21,8 +21,6 @@
[%# Testopia Test Case list CSV export template #%]
[% PROCESS global/variables.none.tmpl %]
[% colsepchar = user.settings.csv_colsepchar.value %]
[% PROCESS testopia/export/csv.caseheader.tmpl %]

View File

@ -23,7 +23,6 @@
# ...
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/style.none.tmpl %]

View File

@ -21,8 +21,6 @@
[%# Testopia Test Case CSV export template #%]
[% PROCESS global/variables.none.tmpl %]
[% USE date %]
[% colsepchar = user.settings.csv_colsepchar.value %]

View File

@ -24,7 +24,6 @@
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/style.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]

View File

@ -21,7 +21,6 @@
[%# Testopia Show Test Case XML export template #%]
[% IF NOT header_done %]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/export/xml.header.tmpl %]
[% END %]

View File

@ -18,8 +18,6 @@
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
#%]
[% PROCESS global/variables.none.tmpl %]
[% colsepchar = user.settings.csv_colsepchar.value %]
[% FOREACH column = displaycolumns %]

View File

@ -23,7 +23,6 @@
# ...
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/style.none.tmpl %]

View File

@ -25,8 +25,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[% PROCESS global/variables.none.tmpl %]
[% title = "Create New Test Run Environment" %]
[%############################################################################%]

View File

@ -20,8 +20,6 @@
# Greg Hendricks <ghendricks@novell.com>
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS global/header.html.tmpl
title = "Search by Test Run Environment Number"

View File

@ -25,8 +25,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[% PROCESS global/variables.none.tmpl %]
[% title = "Delete Environment $environment.name" %]
[%############################################################################%]

View File

@ -25,8 +25,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[% PROCESS global/variables.none.tmpl %]
[% title = "Export Environment XML" %]
[%############################################################################%]

View File

@ -25,8 +25,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[% PROCESS global/variables.none.tmpl %]
[% title = "Import XML Environment" %]
[%############################################################################%]

View File

@ -26,8 +26,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[% PROCESS global/variables.none.tmpl %]
[% title = "Test Environments" %]
[%############################################################################%]

View File

@ -24,7 +24,6 @@
# ...
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/style.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]

View File

@ -21,8 +21,6 @@
[%# Testopia Test Case CSV row export template #%]
[% PROCESS global/variables.none.tmpl %]
[% colsepchar = user.settings.csv_colsepchar.value %]
[% FOREACH column = displaycolumns %]

View File

@ -21,8 +21,6 @@
[%# Testopia Test Case CSV column header export template #%]
[% PROCESS global/variables.none.tmpl %]
[% colsepchar = user.settings.csv_colsepchar.value %]
[% FOREACH column = displaycolumns %]

View File

@ -20,8 +20,6 @@
[%# Testopia Test Case XML export template #%]
[% PROCESS global/variables.none.tmpl %]
<testcase author="[% case.author.email FILTER xml %]" priority="[% case.priority FILTER xml %]" automated="[% case.isautomated ? "Automatic" : "Manual" FILTER xml %]" status="[% case.status FILTER xml %]">
[% IF case.text.action %]
<action>[% case.text.action FILTER replace('<','&testopia_lt;') FILTER replace('>','&testopia_gt;') %]</action>

View File

@ -18,7 +18,6 @@
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/style.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]

View File

@ -19,7 +19,6 @@
# Greg Hendricks <ghendricks@novell.com>
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/style.none.tmpl %]

View File

@ -20,7 +20,6 @@
# Greg Hendricks <ghendricks@novell.com>
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/style.none.tmpl %]

View File

@ -27,8 +27,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[%# PROCESS testopia/style.none.tmpl %]
[%# PROCESS global/variables.none.tmpl %]
[%# title = "Test Plan History for Plan $plan.id: $plan.name" %]
[%############################################################################%]

View File

@ -23,7 +23,6 @@
# ...
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/style.none.tmpl %]

View File

@ -18,7 +18,6 @@
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/export/xml.header.tmpl %]
[% SET header_done = 1 %]

View File

@ -21,8 +21,6 @@
[%# Testopia Test Case list CSV export template #%]
[% PROCESS global/variables.none.tmpl %]
[% colsepchar = user.settings.csv_colsepchar.value %]
[% PROCESS testopia/export/csv.caseheader.tmpl %]

View File

@ -23,7 +23,6 @@
# ...
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/style.none.tmpl %]

View File

@ -20,7 +20,6 @@
[%# Testopia Test Case list XML export template #%]
[% IF NOT header_done %]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/export/xml.header.tmpl %]
[% SET header_done = 1 %]
[% END %]

View File

@ -18,7 +18,6 @@
# Contributor(s): Greg Hendricks <ghendricks@novell.com>
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/style.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/search/variables.none.tmpl %]

View File

@ -26,8 +26,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[% PROCESS global/variables.none.tmpl %]
[% title = "Test run report - Bugs severity status" %]
[%############################################################################%]

View File

@ -26,8 +26,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[% PROCESS global/variables.none.tmpl %]
[% title = "Test run report - Bugs detected" %]
[%############################################################################%]

View File

@ -26,8 +26,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[% PROCESS global/variables.none.tmpl %]
[% title = "Build Coverage Report for Plan $plan.id: $plan.name" %]
[%############################################################################%]

View File

@ -19,12 +19,8 @@
# Contributor(s): Gervase Markham <gerv@gerv.net>
#%]
[% PROCESS global/variables.none.tmpl %]
[% y_label = report.type %]
[% PROCESS "global/field-descs.none.tmpl" %]
[% col_field_disp = field_descs.$col_field || col_field %]

View File

@ -31,8 +31,6 @@
# tbl: Name of a hash in data which is the table to be plotted.
#%]
[% PROCESS "global/field-descs.none.tmpl" %]
[% col_field_disp = field_descs.$col_field || report.col_field %]
[% row_field_disp = field_descs.$row_field || report.row_field %]

View File

@ -21,8 +21,6 @@
[%# INTERFACE:
# See report-table.html.tmpl.
#%]
[% PROCESS global/variables.none.tmpl %]
[% colsepchar = user.settings.csv_colsepchar.value %]
[% num_bugs = BLOCK %]Number of [% terms.bugs %][% END %]
[% tbl_field_disp = field_descs.$tbl_field || report.tbl_field %]

View File

@ -46,8 +46,6 @@
[% report.row_field = "" %]
[% END %]
[% PROCESS "global/field-descs.none.tmpl" %]
[% tbl_field_disp = field_descs.$report.tbl_field || report.tbl_field %]
[% col_field_disp = field_descs.$report.col_field || report.col_field %]
[% row_field_disp = field_descs.$report.row_field || report.row_field %]

View File

@ -26,8 +26,6 @@
[%# Template Initialization #%]
[%############################################################################%]
[% PROCESS global/variables.none.tmpl %]
[% title = "Test run report - Test burnout chart" %]
[%############################################################################%]

View File

@ -24,7 +24,6 @@
# ...
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/style.none.tmpl %]
[% title = "Create a New Test Run" %]

View File

@ -20,8 +20,6 @@
# Greg Hendricks <ghendricks@novell.com>
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS global/header.html.tmpl
title = "Search by Test Run Number"

View File

@ -23,7 +23,6 @@
# ...
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/style.none.tmpl %]

View File

@ -23,7 +23,6 @@
# ...
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]
[% PROCESS testopia/style.none.tmpl %]

View File

@ -22,7 +22,6 @@
# ...
#%]
[% PROCESS global/variables.none.tmpl %]
[% PROCESS testopia/style.none.tmpl %]
[% PROCESS testopia/blocks.html.tmpl %]

View File

@ -18,24 +18,24 @@
# Contributor(s): Ed Fuentetaja <efuentetaja@acm.org>
#%]
[%
debug_ext = Param('testopia-debug') == 'ON'
? "extensions/testopia/extjs/ext-all-debug.js"
debug_ext = Param('testopia-debug') == 'ON'
? "extensions/testopia/extjs/ext-all-debug.js"
: "extensions/testopia/extjs/ext-all.js"
debug_ext_base = Param('testopia-debug') == 'ON'
? "extensions/testopia/extjs/adapter/ext/ext-base-debug.js"
: "extensions/testopia/extjs/adapter/ext/ext-base.js"
debug_testopia = Param('testopia-debug') == 'ON'
debug_testopia = Param('testopia-debug') == 'ON'
? "extensions/testopia/testopia.all.js" : "extensions/testopia/testopia.all.ycomp.js"
style_urls = ["extensions/testopia/extjs/resources/css/ext-all.css",
"extensions/testopia/extjs/examples/ux/css/xtheme-gray-extend.css",
"extensions/testopia/extjs/examples/grid/grid-examples.css"]
%]
[% IF Param('testopia-debug') == 'Developer' %]
[% IF Param('testopia-debug') == 'Developer' %]
[% javascript_urls = [
"extensions/testopia/extjs/adapter/ext/ext-base-debug.js",
"extensions/testopia/extjs/ext-all-debug.js",
"extensions/testopia/extjs/examples/ux/RowEditor.js",

View File

@ -11,7 +11,7 @@ use Bugzilla;
use Bugzilla::Util;
use Bugzilla::Constants;
my $args = Bugzilla->cgi->Vars;
my $args = { %{ Bugzilla->cgi->Vars } };
my $user = Bugzilla->login(~LOGIN_REQUIRED);
my $ctype = 'text/javascript'.(Bugzilla->params->{utf8} ? '; charset=utf-8' : '');

View File

@ -41,7 +41,7 @@ sub add_wt
# Read buglist from query params
my @idlist;
my $args = $cgi->Vars;
my $args = { %{ $cgi->Vars } };
foreach (keys %$args)
{
if (/^wtime_(\d+)/)

View File

@ -20,7 +20,7 @@ use JSON;
my $gc_prob = 0.01;
my $cgi = Bugzilla->cgi;
my $args = $cgi->Vars;
my $args = { %{ $cgi->Vars } };
my $check = $args->{ga_check} ? 1 : 0; # если 1 и пользователь не вошёл, входа не требовать
# требуем входа, если пришёл пользователь (в запросе нет ключа) и в запросе не сказано "не требовать входа"

BIN
images/neg.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 B

View File

@ -88,10 +88,8 @@ for (keys %$args)
$vars->{bug_tpl} = $bug_tpl;
$vars->{name_tr} = $name_tr;
# FIXME переделать на стандарт
# нужно всосать из шаблонов field_descs...
# и несколько поменять... ;-/ поганый хак, конечно, а чё делать-то.
my $field_descs = { %{ template_var('field_descs') } };
# FIXME переделать на стандартные описания полей, берущиеся из базы
my $field_descs = { %{ Bugzilla->messages->{field_descs} } };
$field_descs->{platform} = $field_descs->{rep_platform};
$field_descs->{comment} = $field_descs->{longdesc};
for ((grep { /\./ } keys %$field_descs),

129
js/TUI.js
View File

@ -1,26 +1,5 @@
/**
* FIXME: Kill this and YUI, and replace with jQuery completely
*/
/* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Bugzilla Bug Tracking System.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): Dennis Melentyev <dennis.melentyev@infopulse.com.ua>
* Max Kanat-Alexander <mkanat@bugzilla.org>
/* License: Dual-license GPL 3.0+ or MPL 1.1+
* Contributor(s): Vitaliy Filippov <vitalif@mail.ru>
*/
/* This file provides JavaScript functions to be included when one wishes
@ -29,14 +8,13 @@
*
* TUI stands for Tweak UI.
*
* Requires js/util.js and the YUI Dom and Cookie libraries.
* Rewritten without YAHOO UI, requires just js/util.js.
*
* See template/en/default/bug/create/create.html.tmpl for a usage example.
*/
var TUI_HIDDEN_CLASS = 'bz_tui_hidden';
var TUI_COOKIE_NAME = 'TUI';
var TUI_COOKIE_NAME = 'TUI';
var TUI_alternates = new Array();
/**
@ -46,67 +24,92 @@ var TUI_alternates = new Array();
*
* @param className The name of the CSS class to hide.
*/
function TUI_toggle_class(className) {
var elements = YAHOO.util.Dom.getElementsByClassName(className);
for (var i = 0; i < elements.length; i++) {
bz_toggleClass(elements[i], TUI_HIDDEN_CLASS);
}
_TUI_save_class_state(elements, className);
_TUI_toggle_control_link(className);
function TUI_toggle_class(className)
{
var hidden = toggleRule('tui_css', '.'+className, 'display: none !important');
TUI_store(className, hidden ? '' : '1');
TUI_toggle_control_link(className);
}
/**
* Specifies that a certain class of items should be hidden by default,
* if the user doesn't have a TUI cookie.
*
*
* @param className The class to hide by default.
*/
function TUI_hide_default(className) {
YAHOO.util.Event.onDOMReady(function () {
if (!YAHOO.util.Cookie.getSub('TUI', className)) {
function TUI_hide_default(className)
{
addListener(window, 'load', function() {
if (!getCookieHash(TUI_COOKIE_NAME)[className])
TUI_toggle_class(className);
}
});
}
function _TUI_toggle_control_link(className) {
function TUI_toggle_control_link(className)
{
var link = document.getElementById(className + "_controller");
var original_text = link.innerHTML;
link.innerHTML = TUI_alternates[className];
TUI_alternates[className] = original_text;
}
function _TUI_save_class_state(elements, aClass) {
// We just check the first element to see if it's hidden or not, and
// consider that all elements are the same.
if (YAHOO.util.Dom.hasClass(elements[0], TUI_HIDDEN_CLASS)) {
_TUI_store(aClass, 0);
}
else {
_TUI_store(aClass, 1);
function getCookieHash(name)
{
var c = getCookie(name)||'';
c = c.split('&');
var h = {};
var t;
for (var i = 0; i < c.length; i++)
{
t = c[i].split('=', 2);
if (t[0].length)
h[t[0]] = t[1];
}
return h;
}
function _TUI_store(aClass, state) {
YAHOO.util.Cookie.setSub(TUI_COOKIE_NAME, aClass, state,
{
function TUI_store(aClass, state)
{
var h = getCookieHash(TUI_COOKIE_NAME);
h[aClass] = state;
var c = [];
for (var i in h)
c.push(i+'='+h[i]);
c = c.join('&');
setCookie(TUI_COOKIE_NAME, c, {
expires: new Date('January 1, 2038'),
path: BUGZILLA.param.cookie_path
path: BUGZILLA.param.cookiepath
});
}
function _TUI_restore() {
var classes = YAHOO.util.Cookie.getSubs(TUI_COOKIE_NAME);
for (item in classes) {
if (classes[item] == 0) {
var elements = YAHOO.util.Dom.getElementsByClassName(item);
for (var i = 0; i < elements.length; i++) {
YAHOO.util.Dom.addClass(elements[i], 'bz_tui_hidden');
}
_TUI_toggle_control_link(item);
function toggleRule(css_id, target, rule)
{
var s;
if (!(s = document.getElementById(css_id)))
{
s = document.createElement('style');
document.getElementsByTagName('head')[0].appendChild(s);
s.setAttribute('id', css_id);
}
ss = s.sheet||s;
var f = false;
var r = ss.rules||ss.cssRules;
for (var i = r.length-1; i >= 0; i--)
{
if (r[i].selectorText == target)
{
if (ss.removeRule)
ss.removeRule(i);
else
ss.deleteRule(i);
f = true;
}
}
if (f)
return false;
if (ss.addRule)
ss.addRule(target, rule);
else
s.appendChild(document.createTextNode(target+' { '+rule+' }'));
return true;
}
YAHOO.util.Event.onDOMReady(_TUI_restore);

View File

@ -23,210 +23,211 @@
function switch_aft(n)
{
var f = document.getElementById('form_type_file'+n);
var u = document.getElementById('form_type_url'+n);
var t = document.getElementById('form_type_text'+n);
document.getElementById('tr_file'+n).style.display = f && f.checked ? '' : 'none';
document.getElementById('tr_text'+n).style.display = t && t.checked ? '' : 'none';
if (u)
document.getElementById('tr_url'+n).style.display = u.checked ? '' : 'none';
var f = document.getElementById('form_type_file'+n);
var u = document.getElementById('form_type_url'+n);
var t = document.getElementById('form_type_text'+n);
document.getElementById('tr_file'+n).style.display = f && f.checked ? '' : 'none';
document.getElementById('tr_text'+n).style.display = t && t.checked ? '' : 'none';
if (u)
document.getElementById('tr_url'+n).style.display = u.checked ? '' : 'none';
}
function validateAttachmentForm(theform) {
var desc_value = YAHOO.lang.trim(theform.description.value);
if (desc_value == '') {
alert(BUGZILLA.string.attach_desc_required);
return false;
}
return true;
function validateAttachmentForm(theform)
{
var desc = theform.description.value.replace(/^\s+|\s+$/, '');
if (desc == '')
{
alert(BUGZILLA.string.attach_desc_required);
return false;
}
return true;
}
function updateCommentPrivacy(checkbox)
{
var text_elem = document.getElementById('comment');
if (checkbox.checked) {
text_elem.className='bz_private';
} else {
text_elem.className='';
}
var text_elem = document.getElementById('comment');
if (checkbox.checked)
text_elem.className = 'bz_private';
else
text_elem.className = '';
}
function URLFieldHandler()
{
var field_attachurl = document.getElementById("attachurl");
var greyfields = [
"data", "ispatch", "autodetect",
"list", "manual", "bigfile",
"contenttypeselection",
"contenttypeentry"
];
var i, thisfield;
if (field_attachurl.value.match(/^\s*$/)) {
for (i = 0; i < greyfields.length; i++) {
thisfield = document.getElementById(greyfields[i]);
if (thisfield)
thisfield.removeAttribute("disabled");
var field_attachurl = document.getElementById("attachurl");
var greyfields = [
"data", "ispatch", "autodetect",
"list", "manual", "bigfile",
"contenttypeselection",
"contenttypeentry"
];
var i, thisfield;
if (field_attachurl.value.match(/^\s*$/)) {
for (i = 0; i < greyfields.length; i++) {
thisfield = document.getElementById(greyfields[i]);
if (thisfield)
thisfield.removeAttribute("disabled");
}
} else {
for (i = 0; i < greyfields.length; i++) {
thisfield = document.getElementById(greyfields[i]);
if (thisfield)
thisfield.setAttribute("disabled", "disabled");
}
}
} else {
for (i = 0; i < greyfields.length; i++) {
thisfield = document.getElementById(greyfields[i]);
if (thisfield)
thisfield.setAttribute("disabled", "disabled");
}
}
}
function DataFieldHandler(AllowAttachUrl)
{
var field_data = document.getElementById("data");
var fd_empty = field_data.value.match(/^\s*$/);
var field_description = document.getElementById("description");
if (!field_description._changed && !fd_empty)
{
l = field_data.value.lastIndexOf('/')+1;
lw = field_data.value.lastIndexOf('\\')+1;
if (lw > l)
l = lw;
field_description.value = field_data.value.substr(l);
}
if (!AllowAttachUrl)
return;
var greyfields = new Array("attachurl");
var i, thisfield;
if (fd_empty) {
for (i = 0; i < greyfields.length; i++) {
thisfield = document.getElementById(greyfields[i]);
if (thisfield)
thisfield.removeAttribute("disabled");
var field_data = document.getElementById("data");
var fd_empty = field_data.value.match(/^\s*$/);
var field_description = document.getElementById("description");
if (!field_description._changed && !fd_empty)
{
l = field_data.value.lastIndexOf('/')+1;
lw = field_data.value.lastIndexOf('\\')+1;
if (lw > l)
l = lw;
field_description.value = field_data.value.substr(l);
}
} else {
for (i = 0; i < greyfields.length; i++) {
thisfield = document.getElementById(greyfields[i]);
if (thisfield)
thisfield.setAttribute("disabled", "disabled");
if (!AllowAttachUrl)
return;
var greyfields = new Array("attachurl");
var i, thisfield;
if (fd_empty) {
for (i = 0; i < greyfields.length; i++) {
thisfield = document.getElementById(greyfields[i]);
if (thisfield)
thisfield.removeAttribute("disabled");
}
} else {
for (i = 0; i < greyfields.length; i++) {
thisfield = document.getElementById(greyfields[i]);
if (thisfield)
thisfield.setAttribute("disabled", "disabled");
}
}
}
}
function clearAttachmentFields() {
var element;
var element;
document.getElementById('data').value = '';
DataFieldHandler();
if ((element = document.getElementById('bigfile')))
element.checked = '';
if ((element = document.getElementById('attachurl'))) {
element.value = '';
URLFieldHandler();
}
document.getElementById('description').value = '';
/* Fire onchange so that the disabled state of the content-type
* radio buttons are also reset
*/
element = document.getElementById('ispatch');
element.checked = '';
bz_fireEvent(element, 'change');
if ((element = document.getElementById('isprivate')))
document.getElementById('data').value = '';
DataFieldHandler();
if ((element = document.getElementById('bigfile')))
element.checked = '';
if ((element = document.getElementById('attachurl'))) {
element.value = '';
URLFieldHandler();
}
document.getElementById('description').value = '';
/* Fire onchange so that the disabled state of the content-type
* radio buttons are also reset
*/
element = document.getElementById('ispatch');
element.checked = '';
bz_fireEvent(element, 'change');
if ((element = document.getElementById('isprivate')))
element.checked = '';
}
/* Functions used when viewing patches in Diff mode. */
function collapse_all() {
var elem = document.checkboxform.firstChild;
while (elem != null) {
if (elem.firstChild != null) {
var tbody = elem.firstChild.nextSibling;
if (tbody.className == 'file') {
tbody.className = 'file_collapse';
twisty = get_twisty_from_tbody(tbody);
twisty.firstChild.nodeValue = '(+)';
twisty.nextSibling.checked = false;
}
var elem = document.checkboxform.firstChild;
while (elem != null) {
if (elem.firstChild != null) {
var tbody = elem.firstChild.nextSibling;
if (tbody.className == 'file') {
tbody.className = 'file_collapse';
twisty = get_twisty_from_tbody(tbody);
twisty.firstChild.nodeValue = '(+)';
twisty.nextSibling.checked = false;
}
}
elem = elem.nextSibling;
}
elem = elem.nextSibling;
}
return false;
return false;
}
function expand_all() {
var elem = document.checkboxform.firstChild;
while (elem != null) {
if (elem.firstChild != null) {
var tbody = elem.firstChild.nextSibling;
if (tbody.className == 'file_collapse') {
tbody.className = 'file';
twisty = get_twisty_from_tbody(tbody);
twisty.firstChild.nodeValue = '(-)';
twisty.nextSibling.checked = true;
}
var elem = document.checkboxform.firstChild;
while (elem != null) {
if (elem.firstChild != null) {
var tbody = elem.firstChild.nextSibling;
if (tbody.className == 'file_collapse') {
tbody.className = 'file';
twisty = get_twisty_from_tbody(tbody);
twisty.firstChild.nodeValue = '(-)';
twisty.nextSibling.checked = true;
}
}
elem = elem.nextSibling;
}
elem = elem.nextSibling;
}
return false;
return false;
}
var current_restore_elem;
function restore_all() {
current_restore_elem = null;
incremental_restore();
current_restore_elem = null;
incremental_restore();
}
function incremental_restore() {
if (!document.checkboxform.restore_indicator.checked) {
return;
}
var next_restore_elem;
if (current_restore_elem) {
next_restore_elem = current_restore_elem.nextSibling;
} else {
next_restore_elem = document.checkboxform.firstChild;
}
while (next_restore_elem != null) {
current_restore_elem = next_restore_elem;
if (current_restore_elem.firstChild != null) {
restore_elem(current_restore_elem.firstChild.nextSibling);
if (!document.checkboxform.restore_indicator.checked) {
return;
}
var next_restore_elem;
if (current_restore_elem) {
next_restore_elem = current_restore_elem.nextSibling;
} else {
next_restore_elem = document.checkboxform.firstChild;
}
while (next_restore_elem != null) {
current_restore_elem = next_restore_elem;
if (current_restore_elem.firstChild != null) {
restore_elem(current_restore_elem.firstChild.nextSibling);
}
next_restore_elem = current_restore_elem.nextSibling;
}
next_restore_elem = current_restore_elem.nextSibling;
}
}
function restore_elem(elem, alertme) {
if (elem.className == 'file_collapse') {
twisty = get_twisty_from_tbody(elem);
if (twisty.nextSibling.checked) {
elem.className = 'file';
twisty.firstChild.nodeValue = '(-)';
if (elem.className == 'file_collapse') {
twisty = get_twisty_from_tbody(elem);
if (twisty.nextSibling.checked) {
elem.className = 'file';
twisty.firstChild.nodeValue = '(-)';
}
} else if (elem.className == 'file') {
twisty = get_twisty_from_tbody(elem);
if (!twisty.nextSibling.checked) {
elem.className = 'file_collapse';
twisty.firstChild.nodeValue = '(+)';
}
}
} else if (elem.className == 'file') {
twisty = get_twisty_from_tbody(elem);
if (!twisty.nextSibling.checked) {
elem.className = 'file_collapse';
twisty.firstChild.nodeValue = '(+)';
}
}
}
function twisty_click(twisty) {
tbody = get_tbody_from_twisty(twisty);
if (tbody.className == 'file') {
tbody.className = 'file_collapse';
twisty.firstChild.nodeValue = '(+)';
twisty.nextSibling.checked = false;
} else {
tbody.className = 'file';
twisty.firstChild.nodeValue = '(-)';
twisty.nextSibling.checked = true;
}
return false;
tbody = get_tbody_from_twisty(twisty);
if (tbody.className == 'file') {
tbody.className = 'file_collapse';
twisty.firstChild.nodeValue = '(+)';
twisty.nextSibling.checked = false;
} else {
tbody.className = 'file';
twisty.firstChild.nodeValue = '(-)';
twisty.nextSibling.checked = true;
}
return false;
}
function get_tbody_from_twisty(twisty) {
return twisty.parentNode.parentNode.parentNode.nextSibling;
return twisty.parentNode.parentNode.parentNode.nextSibling;
}
function get_twisty_from_tbody(tbody) {
return tbody.previousSibling.firstChild.nextSibling.firstChild.firstChild;
return tbody.previousSibling.firstChild.nextSibling.firstChild.firstChild;
}
var prev_mode = 'raw';
@ -235,115 +236,116 @@ var has_edited = 0;
var has_viewed_as_diff = 0;
function editAsComment(patchviewerinstalled)
{
switchToMode('edit', patchviewerinstalled);
has_edited = 1;
switchToMode('edit', patchviewerinstalled);
has_edited = 1;
}
function undoEditAsComment(patchviewerinstalled)
{
switchToMode(prev_mode, patchviewerinstalled);
switchToMode(prev_mode, patchviewerinstalled);
}
function redoEditAsComment(patchviewerinstalled)
{
switchToMode('edit', patchviewerinstalled);
switchToMode('edit', patchviewerinstalled);
}
function viewDiff(attachment_id, patchviewerinstalled)
{
switchToMode('diff', patchviewerinstalled);
switchToMode('diff', patchviewerinstalled);
// If we have not viewed as diff before, set the view diff frame URL
if (!has_viewed_as_diff) {
var viewDiffFrame = document.getElementById('viewDiffFrame');
viewDiffFrame.src =
'attachment.cgi?id=' + attachment_id + '&action=diff&headers=0';
has_viewed_as_diff = 1;
}
// If we have not viewed as diff before, set the view diff frame URL
if (!has_viewed_as_diff) {
var viewDiffFrame = document.getElementById('viewDiffFrame');
viewDiffFrame.src =
'attachment.cgi?id=' + attachment_id + '&action=diff&headers=0';
has_viewed_as_diff = 1;
}
}
function viewRaw(patchviewerinstalled)
{
switchToMode('raw', patchviewerinstalled);
switchToMode('raw', patchviewerinstalled);
}
function switchToMode(mode, patchviewerinstalled)
{
if (mode == current_mode) {
alert('switched to same mode! This should not happen.');
return;
}
if (mode == current_mode)
{
alert('switched to same mode! This should not happen.');
return;
}
// Switch out of current mode
if (current_mode == 'edit') {
hideElementById('editFrame');
hideElementById('undoEditButton');
} else if (current_mode == 'raw') {
hideElementById('viewFrame');
if (patchviewerinstalled)
hideElementById('viewDiffButton');
hideElementById(has_edited ? 'redoEditButton' : 'editButton');
hideElementById('smallCommentFrame');
} else if (current_mode == 'diff') {
if (patchviewerinstalled)
hideElementById('viewDiffFrame');
hideElementById('viewRawButton');
hideElementById(has_edited ? 'redoEditButton' : 'editButton');
hideElementById('smallCommentFrame');
}
// Switch out of current mode
if (current_mode == 'edit') {
hideElementById('editFrame');
hideElementById('undoEditButton');
} else if (current_mode == 'raw') {
hideElementById('viewFrame');
if (patchviewerinstalled)
hideElementById('viewDiffButton');
hideElementById(has_edited ? 'redoEditButton' : 'editButton');
hideElementById('smallCommentFrame');
} else if (current_mode == 'diff') {
if (patchviewerinstalled)
hideElementById('viewDiffFrame');
hideElementById('viewRawButton');
hideElementById(has_edited ? 'redoEditButton' : 'editButton');
hideElementById('smallCommentFrame');
}
// Switch into new mode
if (mode == 'edit') {
showElementById('editFrame');
showElementById('undoEditButton');
} else if (mode == 'raw') {
showElementById('viewFrame');
if (patchviewerinstalled)
showElementById('viewDiffButton');
// Switch into new mode
if (mode == 'edit') {
showElementById('editFrame');
showElementById('undoEditButton');
} else if (mode == 'raw') {
showElementById('viewFrame');
if (patchviewerinstalled)
showElementById('viewDiffButton');
showElementById(has_edited ? 'redoEditButton' : 'editButton');
showElementById('smallCommentFrame');
} else if (mode == 'diff') {
if (patchviewerinstalled)
showElementById('viewDiffFrame');
showElementById(has_edited ? 'redoEditButton' : 'editButton');
showElementById('smallCommentFrame');
} else if (mode == 'diff') {
if (patchviewerinstalled)
showElementById('viewDiffFrame');
showElementById('viewRawButton');
showElementById(has_edited ? 'redoEditButton' : 'editButton');
showElementById('smallCommentFrame');
}
showElementById('viewRawButton');
showElementById(has_edited ? 'redoEditButton' : 'editButton');
showElementById('smallCommentFrame');
}
prev_mode = current_mode;
current_mode = mode;
prev_mode = current_mode;
current_mode = mode;
}
function hideElementById(id)
{
var elm = document.getElementById(id);
if (elm) {
elm.style.display = 'none';
}
var elm = document.getElementById(id);
if (elm) {
elm.style.display = 'none';
}
}
function showElementById(id, val)
{
var elm = document.getElementById(id);
if (elm) {
if (!val) val = 'inline';
elm.style.display = val;
}
var elm = document.getElementById(id);
if (elm) {
if (!val) val = 'inline';
elm.style.display = val;
}
}
function normalizeComments()
{
// Remove the unused comment field from the document so its contents
// do not get transmitted back to the server.
// Remove the unused comment field from the document so its contents
// do not get transmitted back to the server.
var small = document.getElementById('smallCommentFrame');
var big = document.getElementById('editFrame');
if ( (small) && (small.style.display == 'none') )
{
small.parentNode.removeChild(small);
}
if ( (big) && (big.style.display == 'none') )
{
big.parentNode.removeChild(big);
}
var small = document.getElementById('smallCommentFrame');
var big = document.getElementById('editFrame');
if ( (small) && (small.style.display == 'none') )
{
small.parentNode.removeChild(small);
}
if ( (big) && (big.style.display == 'none') )
{
big.parentNode.removeChild(big);
}
}

View File

@ -1,4 +1,9 @@
YAHOO.util.Event.addListener(window, 'load', initControlledFields);
/* Functions used to show/hide dependent bug fields and change their select options
* License: Dual-license GPL 3.0+ or MPL 1.1+
* Contributor(s): Vitaliy Filippov <vitalif@mail.ru>
*/
addListener(window, 'load', initControlledFields);
function initControlledFields()
{
@ -9,7 +14,8 @@ function initControlledFields()
function initControlledField(i)
{
var f = document.getElementById(i);
YAHOO.util.Event.addListener(f, 'change', handleControllerField, f);
if (f)
addListener(f, 'change', handleControllerField_this);
}
function getSelectedIds(sel)
@ -27,6 +33,11 @@ function getSelectedIds(sel)
return opt;
}
function handleControllerField_this(e)
{
return handleControllerField(e, this);
}
function handleControllerField(e, controller)
{
var vis, label_container, field_container, id;
@ -46,13 +57,13 @@ function handleControllerField(e, controller)
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');
removeClass(label_container, 'bz_hidden_field');
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');
addClass(label_container, 'bz_hidden_field');
addClass(field_container, 'bz_hidden_field');
}
}
var item, controlled, copt, controlled_value;
@ -89,4 +100,3 @@ function handleControllerField(e, controller)
}
}
}

415
js/bug.js
View File

@ -1,260 +1,273 @@
function updateCommentPrivacy(checkbox, id) {
var comment_elem = document.getElementById('comment_text_'+id).parentNode;
if (checkbox.checked) {
if (!comment_elem.className.match('bz_private')) {
comment_elem.className = comment_elem.className.concat(' bz_private');
/* JS functions used on bug edit page
* License: Dual-license GPL 3.0+ or MPL 1.1+
* Contributor(s): Vitaliy Filippov <vitalif@mail.ru>
*/
function updateCommentPrivacy(checkbox, id)
{
var comment_elem = document.getElementById('comment_text_'+id).parentNode;
if (checkbox.checked)
{
if (!comment_elem.className.match('bz_private'))
comment_elem.className = comment_elem.className.concat(' bz_private');
}
}
else {
comment_elem.className =
comment_elem.className.replace(/(\s*|^)bz_private(\s*|$)/, '$2');
}
else
comment_elem.className =
comment_elem.className.replace(/(\s*|^)bz_private(\s*|$)/, '$2');
}
/* The functions below expand and collapse comments */
function toggle_comment_display(link, comment_id) {
var comment = document.getElementById('comment_text_' + comment_id);
var re = new RegExp(/\bcollapsed\b/);
if (comment.className.match(re))
expand_comment(link, comment);
else
collapse_comment(link, comment);
}
function toggle_all_comments(action, num_comments) {
// If for some given ID the comment doesn't exist, this doesn't mean
// there are no more comments, but that the comment is private and
// the user is not allowed to view it.
for (var id = 0; id < num_comments; id++) {
var comment = document.getElementById('comment_text_' + id);
if (!comment)
continue;
var link = document.getElementById('comment_link_' + id);
if (action == 'collapse')
collapse_comment(link, comment);
function toggle_comment_display(link, comment_id)
{
var comment = document.getElementById('comment_text_' + comment_id);
var re = new RegExp(/\bcollapsed\b/);
if (comment.className.match(re))
expand_comment(link, comment);
else
expand_comment(link, comment);
}
collapse_comment(link, comment);
}
function collapse_comment(link, comment) {
link.innerHTML = "[+]";
link.title = "Expand the comment.";
YAHOO.util.Dom.addClass(comment, 'collapsed');
function toggle_all_comments(action, num_comments)
{
// If for some given ID the comment doesn't exist, this doesn't mean
// there are no more comments, but that the comment is private and
// the user is not allowed to view it.
for (var id = 0; id < num_comments; id++)
{
var comment = document.getElementById('comment_text_' + id);
if (!comment)
continue;
var link = document.getElementById('comment_link_' + id);
if (action == 'collapse')
collapse_comment(link, comment);
else
expand_comment(link, comment);
}
}
function expand_comment(link, comment) {
link.innerHTML = "[-]";
link.title = "Collapse the comment";
YAHOO.util.Dom.removeClass(comment, 'collapsed');
function collapse_comment(link, comment)
{
link.innerHTML = "[+]";
link.title = "Expand the comment.";
addClass(comment, 'collapsed');
}
function expand_comment(link, comment)
{
link.innerHTML = "[-]";
link.title = "Collapse the comment";
removeClass(comment, 'collapsed');
}
/* This way, we are sure that browsers which do not support JS
* won't display this link */
function addCollapseLink(count) {
var e = document.getElementById('comment_act_'+count);
if (!e)
return;
e.innerHTML +=
' <a href="#" class="bz_collapse_comment"' +
' id="comment_link_' + count +
'" onclick="toggle_comment_display(this, ' + count +
'); return false;" title="Collapse the comment.">[-]<\/a> ';
function addCollapseLink(count)
{
var e = document.getElementById('comment_act_'+count);
if (!e)
return;
e.innerHTML +=
' <a href="#" class="bz_collapse_comment"' +
' id="comment_link_' + count +
'" onclick="toggle_comment_display(this, ' + count +
'); return false;" title="Collapse the comment.">[-]<\/a> ';
}
/* Outputs a link to call replyToComment(); used to reduce HTML output */
function addReplyLink(id, real_id) {
var e = document.getElementById('comment_act_'+id);
if (!e)
return;
var s = '[';
if (user_settings.quote_replies != 'off')
{
s += '<a href="#add_comment" onclick="replyToComment(' +
id + ',' + real_id + '); return false;">reply<' + '/a>';
}
s += ', clone to <a href="enter_bug.cgi?cloned_bug_id='+bug_info.id+'&amp;cloned_comment='+id+'">other</a>';
s += '/<a href="enter_bug.cgi?cloned_bug_id='+bug_info.id+'&amp;product='+encodeURI(bug_info.product)+'&amp;cloned_comment='+id+'">same</a>';
/* CustIS Bug 69514 */
if (bug_info.extprod)
s += '/<a href="enter_bug.cgi?cloned_bug_id='+bug_info.id+'&amp;product='+encodeURI(bug_info.extprod)+'&amp;cloned_comment='+id+'">ext</a>';
else if (bug_info.intprod)
s += '/<a href="enter_bug.cgi?cloned_bug_id='+bug_info.id+'&amp;product='+encodeURI(bug_info.intprod)+'&amp;cloned_comment='+id+'">int</a>';
s += ' product]';
e.innerHTML += s;
function addReplyLink(id, real_id)
{
var e = document.getElementById('comment_act_'+id);
if (!e)
return;
var s = '[';
if (user_settings.quote_replies != 'off')
{
s += '<a href="#add_comment" onclick="replyToComment(' +
id + ',' + real_id + '); return false;">reply<' + '/a>';
}
s += ', clone to <a href="enter_bug.cgi?cloned_bug_id='+bug_info.id+'&amp;cloned_comment='+id+'">other</a>';
s += '/<a href="enter_bug.cgi?cloned_bug_id='+bug_info.id+'&amp;product='+encodeURI(bug_info.product)+'&amp;cloned_comment='+id+'">same</a>';
/* CustIS Bug 69514 */
if (bug_info.extprod)
s += '/<a href="enter_bug.cgi?cloned_bug_id='+bug_info.id+'&amp;product='+encodeURI(bug_info.extprod)+'&amp;cloned_comment='+id+'">ext</a>';
else if (bug_info.intprod)
s += '/<a href="enter_bug.cgi?cloned_bug_id='+bug_info.id+'&amp;product='+encodeURI(bug_info.intprod)+'&amp;cloned_comment='+id+'">int</a>';
s += ' product]';
e.innerHTML += s;
}
function addActionLinks(indexes)
{
for (var i in indexes)
{
addReplyLink(indexes[i][0], indexes[i][1]);
addCollapseLink(indexes[i][0]);
}
for (var i in indexes)
{
addReplyLink(indexes[i][0], indexes[i][1]);
addCollapseLink(indexes[i][0]);
}
}
/* Adds the reply text to the `comment' textarea */
function replyToComment(id, real_id)
{
var prefix = "(In reply to comment #" + id + ")\n";
var replytext = "";
if (user_settings.quote_replies == 'quoted_reply')
{
/* pre id="comment_name_N" */
var text_elem = document.getElementById('comment_text_'+id);
var text = getText(text_elem);
/* make sure we split on all newlines -- IE or Moz use \r and \n
* respectively.
*/
text = text.split(/\r|\n/);
var prev_ist = false, ist = false;
for (var i = 0; i < text.length; i++)
var prefix = "(In reply to comment #" + id + ")\n";
var replytext = "";
if (user_settings.quote_replies == 'quoted_reply')
{
/* CustIS Bug 55876 - ASCII pseudographic tables */
ist = text[i].match('^(┌|│|└).*(┐|│|┘)$') ? true : false;
if (!ist)
{
replytext += "> ";
replytext += text[i];
replytext += "\n";
}
else if (!prev_ist)
replytext += "> (table cut off)\n";
prev_ist = ist;
/* pre id="comment_name_N" */
var text_elem = document.getElementById('comment_text_'+id);
var text = getText(text_elem);
/* make sure we split on all newlines -- IE or Moz use \r and \n
* respectively.
*/
text = text.split(/\r|\n/);
var prev_ist = false, ist = false;
for (var i = 0; i < text.length; i++)
{
/* CustIS Bug 55876 - ASCII pseudographic tables */
ist = text[i].match('^(┌|│|└).*(┐|│|┘)$') ? true : false;
if (!ist)
{
replytext += "> ";
replytext += text[i];
replytext += "\n";
}
else if (!prev_ist)
replytext += "> (table cut off)\n";
prev_ist = ist;
}
replytext = prefix + replytext + "\n";
}
else if (user_settings.quote_replies == 'simple_reply')
replytext = prefix;
replytext = prefix + replytext + "\n";
}
else if (user_settings.quote_replies == 'simple_reply')
replytext = prefix;
if (user_settings.is_insider && document.getElementById('isprivate_' + real_id).checked)
document.getElementById('newcommentprivacy').checked = 'checked';
if (user_settings.is_insider && document.getElementById('isprivate_' + real_id).checked)
document.getElementById('newcommentprivacy').checked = 'checked';
var textarea = document.getElementById('comment_textarea');
textarea.value += replytext;
var textarea = document.getElementById('comment_textarea');
textarea.value += replytext;
textarea.focus();
textarea.focus();
}
function adjustRemainingTime()
{
// subtracts time spent from remaining time
var new_time;
var wt = bzParseTime(document.changeform.work_time.value);
if (wt === null || wt === undefined || wt != wt)
{
document.changeform.work_time.style.backgroundColor = '#FFC0C0';
document.changeform.remaining_time.style.backgroundColor = '#FFC0C0';
wt = 0;
}
else
{
document.changeform.work_time.style.backgroundColor = null;
document.changeform.remaining_time.style.backgroundColor = null;
}
if (notimetracking)
document.changeform.work_time.parentNode.style.backgroundColor = wt != 0 ? '#FFC0C0' : null;
// subtracts time spent from remaining time
var new_time;
var wt = bzParseTime(document.changeform.work_time.value);
if (wt === null || wt === undefined || wt != wt)
{
document.changeform.work_time.style.backgroundColor = '#FFC0C0';
document.changeform.remaining_time.style.backgroundColor = '#FFC0C0';
wt = 0;
}
else
{
document.changeform.work_time.style.backgroundColor = null;
document.changeform.remaining_time.style.backgroundColor = null;
}
if (notimetracking)
document.changeform.work_time.parentNode.style.backgroundColor = wt != 0 ? '#FFC0C0' : null;
// prevent negative values if work_time > fRemainingTime
new_time = Math.max(fRemainingTime - wt, 0.0);
// get upto 2 decimal places
document.changeform.remaining_time.value =
Math.round(new_time * 100)/100;
// prevent negative values if work_time > fRemainingTime
new_time = Math.max(fRemainingTime - wt, 0.0);
// get upto 2 decimal places
document.changeform.remaining_time.value =
Math.round(new_time * 100)/100;
}
function updateRemainingTime() {
// if the remaining time is changed manually, update fRemainingTime
fRemainingTime = bzParseTime(document.changeform.remaining_time.value);
function updateRemainingTime()
{
// if the remaining time is changed manually, update fRemainingTime
fRemainingTime = bzParseTime(document.changeform.remaining_time.value);
}
function changeform_onsubmit()
{
var wt = bzParseTime(document.changeform.work_time.value);
var awt = wt;
if (wt != wt)
awt = 0;
else if (user_settings.wants_worktime_reminder &&
(wt === null || wt === undefined || wt != wt ||
notimetracking && wt != 0 || !notimetracking && wt == 0))
{
awt = prompt("Please, verify working time:", !wt || wt != wt ? "0" : wt);
if (awt === null || awt === undefined || (""+awt).length <= 0)
var wt = bzParseTime(document.changeform.work_time.value);
var awt = wt;
if (wt != wt)
awt = 0;
else if (user_settings.wants_worktime_reminder &&
(wt === null || wt === undefined || wt != wt ||
notimetracking && wt != 0 || !notimetracking && wt == 0))
{
document.changeform.work_time.focus();
return false;
awt = prompt("Please, verify working time:", !wt || wt != wt ? "0" : wt);
if (awt === null || awt === undefined || (""+awt).length <= 0)
{
document.changeform.work_time.focus();
return false;
}
}
}
document.changeform.work_time.value = awt;
adjustRemainingTime();
return true;
document.changeform.work_time.value = awt;
adjustRemainingTime();
return true;
}
// This function clears a row from multi-attachment upload form
function att_file_clear(e)
{
e = document.getElementById(e);
var ci = e.id.substr(5);
e.parentNode.innerHTML = e.parentNode.innerHTML;
document.getElementById('del_'+ci).style.display = 'none';
document.getElementById('description_'+ci).value = '';
document.getElementById('contenttypeselection_'+ci).selectedIndex = 0;
e = document.getElementById(e);
var ci = e.id.substr(5);
e.parentNode.innerHTML = e.parentNode.innerHTML;
document.getElementById('del_'+ci).style.display = 'none';
document.getElementById('description_'+ci).value = '';
document.getElementById('contenttypeselection_'+ci).selectedIndex = 0;
}
// This function handles change events of upload inputs on multi-attachment upload form
function att_file_onchange(e)
{
var ci = e.id.substr(5);
document.getElementById('del_'+ci).style.display = e.value ? '' : 'none';
if (e.value)
{
// Fill description from file name if it wasn't changed by user
var e1 = document.getElementById('description_'+ci);
if (!e1._changed)
var ci = e.id.substr(5);
document.getElementById('del_'+ci).style.display = e.value ? '' : 'none';
if (e.value)
{
var p = e.value;
var slash = p.lastIndexOf('/');
var backslash = p.lastIndexOf('\\');
var fname;
if (slash == -1 && backslash == -1)
fname = p;
else if (slash > backslash)
fname = p.substr(slash+1);
else
fname = p.substr(backslash+1);
e1.value = fname;
// Fill description from file name if it wasn't changed by user
var e1 = document.getElementById('description_'+ci);
if (!e1._changed)
{
var p = e.value;
var slash = p.lastIndexOf('/');
var backslash = p.lastIndexOf('\\');
var fname;
if (slash == -1 && backslash == -1)
fname = p;
else if (slash > backslash)
fname = p.substr(slash+1);
else
fname = p.substr(backslash+1);
e1.value = fname;
}
// Add a new empty field if there are no empty fields
var i = 0;
var f;
while (f = document.getElementById('data_'+i))
{
if (!f.value)
{
i = -1;
break;
}
i++;
}
if (i > 0)
{
// Copy innerHTML of fileX
// IE does not like setting innerHTML of regular elements, so create
// a div with table and then copy its row
var tmp = document.createElement('div');
tmp.innerHTML =
'<table id="file'+i+'table"><tbody><tr id="file'+i+'">'+
document.getElementById('fileX').innerHTML.replace(/_XXX/g, '_'+i)+
'</tr></tbody></table>';
// div.table.tbody.tr
document.getElementById('files').appendChild(tmp.childNodes[0].childNodes[0].childNodes[0]);
}
}
// Add a new empty field if there are no empty fields
var i = 0;
var f;
while (f = document.getElementById('data_'+i))
{
if (!f.value)
{
i = -1;
break;
}
i++;
}
if (i > 0)
{
// Copy innerHTML of fileX
// IE does not like setting innerHTML of regular elements, so create
// a div with table and then copy its row
var tmp = document.createElement('div');
tmp.innerHTML =
'<table id="file'+i+'table"><tbody><tr id="file'+i+'">'+
document.getElementById('fileX').innerHTML.replace(/_XXX/g, '_'+i)+
'</tr></tbody></table>';
// div.table.tbody.tr
document.getElementById('files').appendChild(tmp.childNodes[0].childNodes[0].childNodes[0]);
}
}
}

220
js/calendar.js Normal file
View File

@ -0,0 +1,220 @@
/**
* Calendar Script, slightly modified
* Creates a calendar widget which can be used to select the date more easily than using just a text box
* http://www.openjs.com/scripts/ui/calendar/
* License: MIT-like, http://www.openjs.com/license.php
*
* Example:
* <input type="text" name="date" id="date" />
* <script type="text/javascript">
* Calendar.set("date");
* </script>
*/
var Calendar = {
month_names: ["January","February","March","April","May","June","July","Augest","September","October","November","December"],
weekdays: ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],
sunday: 0,
month_days: [31,28,31,30,31,30,31,31,30,31,30,31],
//Get today's date - year, month, day and date
today : new Date(),
opt : {},
data: [],
//Functions
/// Used to create HTML in a optimized way.
wrt:function(txt) {
this.data.push(txt);
},
getPosition:function(ele) {
var x = 0;
var y = 0;
while (ele) {
x += ele.offsetLeft;
y += ele.offsetTop;
ele = ele.offsetParent;
}
if (navigator.userAgent.indexOf("Mac") != -1 && typeof document.body.leftMargin != "undefined") {
x += document.body.leftMargin;
offsetTop += document.body.topMargin;
}
var xy = new Array(x,y);
return xy;
},
/// Called when the user clicks on a date in the calendar.
selectDate:function(year,month,day) {
var ths = _calendar_active_instance;
var i = document.getElementById(ths.opt["input"]);
var t = i.value.split(/\s+/, 2)[1]||'';
if (t)
t = ' '+t;
i.value = year + "-" + month + "-" + day + t; // Date format is :HARDCODE:
ths.hideCalendar();
},
/// Creates a calendar with the date given in the argument as the selected date.
makeCalendar:function(year, month, day) {
year = parseInt(year);
month= parseInt(month);
day = parseInt(day);
//Display the table
var next_month = month+1;
var next_month_year = year;
if(next_month>=12) {
next_month = 0;
next_month_year++;
}
var previous_month = month-1;
var previous_month_year = year;
if(previous_month<0) {
previous_month = 11;
previous_month_year--;
}
this.wrt("<table>");
this.wrt("<tr><th><a href='javascript:Calendar.makeCalendar("+(previous_month_year)+","+(previous_month)+");' title='"+this.month_names[previous_month]+" "+(previous_month_year)+"'>&lt;</a></th>");
this.wrt("<th colspan='5' class='calendar-title'><select name='calendar-month' class='calendar-month' onChange='Calendar.makeCalendar("+year+",this.value);'>");
for(var i in this.month_names) {
this.wrt("<option value='"+i+"'");
if(i == month) this.wrt(" selected='selected'");
this.wrt(">"+this.month_names[i]+"</option>");
}
this.wrt("</select>");
this.wrt("<select name='calendar-year' class='calendar-year' onChange='Calendar.makeCalendar(this.value, "+month+");'>");
var current_year = this.today.getYear();
if(current_year < 1900) current_year += 1900;
for(var i=current_year-70; i<current_year+10; i++) {
this.wrt("<option value='"+i+"'")
if(i == year) this.wrt(" selected='selected'");
this.wrt(">"+i+"</option>");
}
this.wrt("</select></th>");
this.wrt("<th><a href='javascript:Calendar.makeCalendar("+(next_month_year)+","+(next_month)+");' title='"+this.month_names[next_month]+" "+(next_month_year)+"'>&gt;</a></th></tr>");
this.wrt("<tr class='header'>");
for(var weekday=0; weekday<7; weekday++) this.wrt("<td>"+this.weekdays[weekday]+"</td>");
this.wrt("</tr>");
//Get the first day of this month
var first_day = new Date(year,month,1);
var start_day = (first_day.getDay()+Calendar.sunday)%7;
var d = 1;
var flag = 0;
//Leap year support
if(year % 4 == 0) this.month_days[1] = 29;
else this.month_days[1] = 28;
var days_in_this_month = this.month_days[month];
//Create the calender
for(var i=0;i<=5;i++) {
if(w >= days_in_this_month) break;
this.wrt("<tr>");
for(var j=0;j<7;j++) {
if(d > days_in_this_month) flag=0; //If the days has overshooted the number of days in this month, stop writing
else if(j >= start_day && !flag) flag=1;//If the first day of this month has come, start the date writing
if(flag) {
var w = d, mon = month+1;
if(w < 10) w = "0" + w;
if(mon < 10)mon = "0" + mon;
//Is it today?
var class_name = '';
var yea = this.today.getYear();
if(yea < 1900) yea += 1900;
if(yea == year && this.today.getMonth() == month && this.today.getDate() == d) class_name = " today";
if(day == d) class_name += " selected";
class_name += " " + this.weekdays[j].toLowerCase();
this.wrt("<td class='days"+class_name+"'><a href='javascript:Calendar.selectDate(\""+year+"\",\""+mon+"\",\""+w+"\")'>"+w+"</a></td>");
d++;
} else {
this.wrt("<td class='days'>&nbsp;</td>");
}
}
this.wrt("</tr>");
}
this.wrt("</table>");
this.wrt("<input type='button' value='Cancel' class='calendar-cancel' onclick='Calendar.hideCalendar();' />");
document.getElementById(this.opt['calendar']).innerHTML = this.data.join("");
this.data = [];
},
/// Display the calendar - if a date exists in the input box, that will be selected in the calendar.
showCalendar: function() {
var input = document.getElementById(this.opt['input']);
//Position the div in the correct location...
var div = document.getElementById(this.opt['calendar']);
var xy = this.getPosition(input);
var width = input.clientWidth||input.offsetWidth;
div.style.left=(xy[0]+width+10)+"px";
div.style.top=xy[1]+"px";
// Show the calendar with the date in the input as the selected date
var existing_date = new Date();
var date_in_input = input.value.replace(/\s+.*$/, ''); //Remove time
if(date_in_input) {
var selected_date = false;
var date_parts = date_in_input.split("-");
if(date_parts.length == 3) {
date_parts[1]--; //Month starts with 0
selected_date = new Date(date_parts[0], date_parts[1], date_parts[2]);
}
if(selected_date && !isNaN(selected_date.getYear())) { //Valid date.
existing_date = selected_date;
}
}
var the_year = existing_date.getYear();
if(the_year < 1900) the_year += 1900;
this.makeCalendar(the_year, existing_date.getMonth(), existing_date.getDate());
document.getElementById(this.opt['calendar']).style.display = "block";
_calendar_active_instance = this;
},
/// Hides the currently show calendar.
hideCalendar: function(instance) {
var active_calendar_id = "";
if(instance) active_calendar_id = instance.opt['calendar'];
else active_calendar_id = _calendar_active_instance.opt['calendar'];
if(active_calendar_id) document.getElementById(active_calendar_id).style.display = "none";
_calendar_active_instance = {};
},
/// Setup a text input box to be a calendar box.
set: function(input_id) {
var input = document.getElementById(input_id);
if(!input) return; //If the input field is not there, exit.
if(!this.opt['calendar']) this.init();
var ths = this;
input.onclick=function(){
ths.opt['input'] = this.id;
ths.showCalendar();
};
},
/// Will be called once when the first input is set.
init: function() {
if(!this.opt['calendar'] || !document.getElementById(this.opt['calendar'])) {
var div = document.createElement('div');
if(!this.opt['calendar']) this.opt['calendar'] = 'calender_div_'+ Math.round(Math.random() * 100);
div.setAttribute('id',this.opt['calendar']);
div.className="calendar-box";
document.getElementsByTagName("body")[0].insertBefore(div,document.getElementsByTagName("body")[0].firstChild);
}
}
}

View File

@ -1,28 +1,29 @@
/*# 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 Pascal Held.
#
# Contributor(s): Pascal Held <paheld@gmail.com>
#
*/
/* 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 Pascal Held.
*
* Contributor(s): Pascal Held <paheld@gmail.com>
*/
function initChangeColumns() {
function initChangeColumns()
{
window.onunload = unload;
var av_select = document.getElementById("available_columns");
var sel_select = document.getElementById("selected_columns");
YAHOO.util.Dom.removeClass(
['avail_header', av_select, 'select_button',
'deselect_button', 'up_button', 'down_button'], 'bz_default_hidden');
var l = ['avail_header', av_select, 'select_button',
'deselect_button', 'up_button', 'down_button'];
for (var i = 0; i < l.length; i++)
removeClass(l[i], 'bz_default_hidden');
switch_options(sel_select, av_select, false);
sel_select.selectedIndex = -1;
updateView();
@ -51,14 +52,16 @@ function switch_options(from_box, to_box, selected)
from_box.options[i].selected = sel[i];
}
function move_select() {
function move_select()
{
var av_select = document.getElementById("available_columns");
var sel_select = document.getElementById("selected_columns");
switch_options(av_select, sel_select, true);
updateView();
}
function move_deselect() {
function move_deselect()
{
var av_select = document.getElementById("available_columns");
var sel_select = document.getElementById("selected_columns");
switch_options(sel_select, av_select, true);
@ -117,7 +120,8 @@ function move_down()
updateView();
}
function updateView() {
function updateView()
{
var select_button = document.getElementById("select_button");
var deselect_button = document.getElementById("deselect_button");
var up_button = document.getElementById("up_button");
@ -128,41 +132,44 @@ function updateView() {
down_button.disabled = true;
var av_select = document.getElementById("available_columns");
var sel_select = document.getElementById("selected_columns");
for (var i = 0; i < av_select.options.length; i++) {
if (av_select.options[i].selected) {
for (var i = 0; i < av_select.options.length; i++)
{
if (av_select.options[i].selected)
{
select_button.disabled = false;
break;
}
}
for (var i = 0; i < sel_select.options.length; i++) {
if (sel_select.options[i].selected) {
for (var i = 0; i < sel_select.options.length; i++)
{
if (sel_select.options[i].selected)
{
deselect_button.disabled = false;
up_button.disabled = false;
down_button.disabled = false;
break;
}
}
if (sel_select.options.length > 0) {
if (sel_select.options[0].selected) {
if (sel_select.options.length > 0)
{
if (sel_select.options[0].selected)
up_button.disabled = true;
}
if (sel_select.options[sel_select.options.length - 1].selected) {
if (sel_select.options[sel_select.options.length - 1].selected)
down_button.disabled = true;
}
}
}
function change_submit() {
function change_submit()
{
var sel_select = document.getElementById("selected_columns");
for (var i = 0; i < sel_select.options.length; i++) {
for (var i = 0; i < sel_select.options.length; i++)
sel_select.options[i].selected = true;
}
return false;
}
function unload() {
function unload()
{
var sel_select = document.getElementById("selected_columns");
for (var i = 0; i < sel_select.options.length; i++) {
for (var i = 0; i < sel_select.options.length; i++)
sel_select.options[i].selected = true;
}
}

558
js/charts.js Normal file
View File

@ -0,0 +1,558 @@
/* Functions for dynamically adding Boolean Charts fields
* onto the Bugzilla Advanced Search Form.
* License: Dual-license GPL 3.0+ or MPL 1.1+
* Contributor(s): Vitaliy Filippov <vitalif@mail.ru>
*/
function chart_add_second(btn)
{
var n = btn.id.substr(5, btn.id.length-9);
// Transform <div> to <fieldset>
var d = document.getElementById('chart'+n);
d.id = 'divchart'+n; // prevent id collisions
btn.id = 'btnchart'+n; // prevent id collisions
var op = (n != 'R' && n.indexOf('-') < 0 ? 'and' : 'or');
// Create <fieldset>
var f = document.createElement('fieldset');
f.id = 'chart'+n;
f.className = 'chart _'+op;
var legend_html = op.toUpperCase()+' '+
'<input type="button" value="+" class="chart_add_button" id="chart'+n+'-btn" onclick="chart_add(this.id)" />';
if (op == 'and')
{
// Move [NOT] to the legend for 'AND' charts
var neg = document.getElementById('negate'+n);
legend_html +=
'<input type="button" value="NOT" class="chart_not_'+(neg.value ? 'c' : 'u')+'"'+
' style="font-size: 85%" id="negate'+n+'-btn" onclick="chart_neg(this)" />';
if (neg.value)
f.className += ' _neg';
neg = document.getElementById('negate'+n+'-btn');
neg.parentNode.removeChild(neg);
}
// Create <legend>
var l = document.createElement('legend');
l.className = '_'+op;
l.innerHTML = legend_html;
f.appendChild(l);
d.parentNode.insertBefore(f, d);
btn.parentNode.removeChild(btn);
d.parentNode.removeChild(d);
while (d.childNodes.length)
f.appendChild(d.childNodes[0]);
// Add an operand
chart_add('chart'+n+'-btn');
}
function chart_add_btn(d, s)
{
var i = document.createElement('input');
i.type = 'button';
i.id = d.id+'-btn';
i.onclick = chart_add_second_event;
i.value = s;
d.appendChild(document.createTextNode(' '));
d.appendChild(i);
}
// Find next available number for div with prefix 'n'
function chart_add_div(d, n)
{
var i, nd;
for (i = 0; document.getElementById(n+i); i++);
nd = document.createElement('div');
nd.id = n+i;
nd.className = 'chart';
d.appendChild(nd);
return nd;
}
// Copy 'fieldx-x-x' or 'typex-x-x' selectbox
function chart_copy_select(cp_id, new_id)
{
var s = document.createElement('select');
s.id = s.name = new_id;
s.innerHTML = document.getElementById(cp_id).innerHTML;
s.selectedIndex = 0;
return s;
}
// Add another term into chart when clicked on button with id=btnid
function chart_add(btnid)
{
var d, i, add_and, add_or, n;
d = document.getElementById(btnid.substr(0, btnid.length-4)); // chartN-btn
if (d.id == 'chartR')
add_and = d = chart_add_div(d, 'chart');
if (d.id.indexOf('-') < 0)
add_or = d = chart_add_div(d, d.id+'-');
var cn = d.id.substr(5);
for (i = 0; document.getElementById('field'+cn+'-'+i); i++);
cn = cn+'-'+i;
if (!add_or)
d.appendChild(document.createElement('br'));
// Append field-type-value inputs
d.appendChild(chart_copy_select('field0-0-0', 'field'+cn));
d.appendChild(chart_copy_select('type0-0-0', 'type'+cn));
s = document.createElement('input');
s.id = s.name = "value"+cn;
s.size = 40;
d.appendChild(s);
if (add_and)
{
chart_add_btn(add_and, 'AND');
// Add negate button
var n = add_and.id.substr(5);
var i = document.createElement('input');
i.type = 'button';
i.className = 'chart_not_u';
i.id = 'negate'+n+'-btn';
i.onclick = chart_neg_event;
i.value = 'NOT';
add_and.appendChild(i);
// Add hidden input for negate button
i = document.createElement('input');
i.type = 'hidden';
i.name = i.id = 'negate'+n;
document.getElementById('chartR').appendChild(i);
}
if (add_or)
chart_add_btn(add_or, 'OR');
}
function chart_neg(btn)
{
var n = btn.id.substr(6, btn.id.length-10); // negateN
var i = document.getElementById('negate'+n);
i.value = i.value ? '' : '1';
btn.className = 'chart_not_' + (i.value ? 'c' : 'u');
var c = document.getElementById('chart'+n);
if (i.value)
c.className += ' _neg';
else
c.className = c.className.replace(/ _neg/, '');
}
function chart_add_second_event()
{
chart_add_second(this);
}
function chart_neg_event()
{
chart_neg(this);
}
function chart_add_second(btn)
{
var n = btn.id.substr(5, btn.id.length-9);
// Transform <div> to <fieldset>
var d = document.getElementById('chart'+n);
d.id = 'divchart'+n; // prevent id collisions
btn.id = 'btnchart'+n; // prevent id collisions
var op = (n != 'R' && n.indexOf('-') < 0 ? 'and' : 'or');
// Create <fieldset>
var f = document.createElement('fieldset');
f.id = 'chart'+n;
f.className = 'chart _'+op;
var legend_html = op.toUpperCase()+' '+
'<input type="button" value="+" class="chart_add_button" id="chart'+n+'-btn" onclick="chart_add(this.id)" />';
if (op == 'and')
{
// Move [NOT] to the legend for 'AND' charts
var neg = document.getElementById('negate'+n);
legend_html +=
'<input type="button" value="NOT" class="chart_not_'+(neg.value ? 'c' : 'u')+'"'+
' style="font-size: 85%" id="negate'+n+'-btn" onclick="chart_neg(this)" />';
if (neg.value)
f.className += ' _neg';
neg = document.getElementById('negate'+n+'-btn');
neg.parentNode.removeChild(neg);
}
// Create <legend>
var l = document.createElement('legend');
l.className = '_'+op;
l.innerHTML = legend_html;
f.appendChild(l);
d.parentNode.insertBefore(f, d);
btn.parentNode.removeChild(btn);
d.parentNode.removeChild(d);
while (d.childNodes.length)
f.appendChild(d.childNodes[0]);
// Add an operand
chart_add('chart'+n+'-btn');
}
function chart_add_btn(d, s)
{
var i = document.createElement('input');
i.type = 'button';
i.id = d.id+'-btn';
i.onclick = chart_add_second_event;
i.value = s;
d.appendChild(document.createTextNode(' '));
d.appendChild(i);
}
// Find next available number for div with prefix 'n'
function chart_add_div(d, n)
{
var i, nd;
for (i = 0; document.getElementById(n+i); i++);
nd = document.createElement('div');
nd.id = n+i;
nd.className = 'chart';
d.appendChild(nd);
return nd;
}
// Copy 'fieldx-x-x' or 'typex-x-x' selectbox
function chart_copy_select(cp_id, new_id)
{
var s = document.createElement('select');
s.id = s.name = new_id;
s.innerHTML = document.getElementById(cp_id).innerHTML;
s.selectedIndex = 0;
return s;
}
// Add another term into chart when clicked on button with id=btnid
function chart_add(btnid)
{
var d, i, add_and, add_or, n;
d = document.getElementById(btnid.substr(0, btnid.length-4)); // chartN-btn
if (d.id == 'chartR')
add_and = d = chart_add_div(d, 'chart');
if (d.id.indexOf('-') < 0)
add_or = d = chart_add_div(d, d.id+'-');
var cn = d.id.substr(5);
for (i = 0; document.getElementById('field'+cn+'-'+i); i++);
cn = cn+'-'+i;
if (!add_or)
d.appendChild(document.createElement('br'));
// Append field-type-value inputs
d.appendChild(chart_copy_select('field0-0-0', 'field'+cn));
d.appendChild(chart_copy_select('type0-0-0', 'type'+cn));
s = document.createElement('input');
s.id = s.name = "value"+cn;
s.size = 40;
d.appendChild(s);
if (add_and)
{
chart_add_btn(add_and, 'AND');
// Add negate button
var n = add_and.id.substr(5);
var i = document.createElement('input');
i.type = 'button';
i.className = 'chart_not_u';
i.id = 'negate'+n+'-btn';
i.onclick = chart_neg_event;
i.value = 'NOT';
add_and.appendChild(i);
// Add hidden input for negate button
i = document.createElement('input');
i.type = 'hidden';
i.name = i.id = 'negate'+n;
document.getElementById('chartR').appendChild(i);
}
if (add_or)
chart_add_btn(add_or, 'OR');
}
function chart_neg(btn)
{
var n = btn.id.substr(6, btn.id.length-10); // negateN
var i = document.getElementById('negate'+n);
i.value = i.value ? '' : '1';
btn.className = 'chart_not_' + (i.value ? 'c' : 'u');
var c = document.getElementById('chart'+n);
if (i.value)
c.className += ' _neg';
else
c.className = c.className.replace(/ _neg/, '');
}
function chart_add_second_event()
{
chart_add_second(this);
}
function chart_neg_event()
{
chart_neg(this);
}
function chart_add_second(btn)
{
var n = btn.id.substr(5, btn.id.length-9);
// Transform <div> to <fieldset>
var d = document.getElementById('chart'+n);
d.id = 'divchart'+n; // prevent id collisions
btn.id = 'btnchart'+n; // prevent id collisions
var op = (n != 'R' && n.indexOf('-') < 0 ? 'and' : 'or');
// Create <fieldset>
var f = document.createElement('fieldset');
f.id = 'chart'+n;
f.className = 'chart _'+op;
var legend_html = op.toUpperCase()+' '+
'<input type="button" value="+" class="chart_add_button" id="chart'+n+'-btn" onclick="chart_add(this.id)" />';
if (op == 'and')
{
// Move [NOT] to the legend for 'AND' charts
var neg = document.getElementById('negate'+n);
legend_html +=
'<input type="button" value="NOT" class="chart_not_'+(neg.value ? 'c' : 'u')+'"'+
' style="font-size: 85%" id="negate'+n+'-btn" onclick="chart_neg(this)" />';
if (neg.value)
f.className += ' _neg';
neg = document.getElementById('negate'+n+'-btn');
neg.parentNode.removeChild(neg);
}
// Create <legend>
var l = document.createElement('legend');
l.className = '_'+op;
l.innerHTML = legend_html;
f.appendChild(l);
d.parentNode.insertBefore(f, d);
btn.parentNode.removeChild(btn);
d.parentNode.removeChild(d);
while (d.childNodes.length)
f.appendChild(d.childNodes[0]);
// Add an operand
chart_add('chart'+n+'-btn');
}
function chart_add_btn(d, s)
{
var i = document.createElement('input');
i.type = 'button';
i.id = d.id+'-btn';
i.onclick = chart_add_second_event;
i.value = s;
d.appendChild(document.createTextNode(' '));
d.appendChild(i);
}
// Find next available number for div with prefix 'n'
function chart_add_div(d, n)
{
var i, nd;
for (i = 0; document.getElementById(n+i); i++);
nd = document.createElement('div');
nd.id = n+i;
nd.className = 'chart';
d.appendChild(nd);
return nd;
}
// Copy 'fieldx-x-x' or 'typex-x-x' selectbox
function chart_copy_select(cp_id, new_id)
{
var s = document.createElement('select');
s.id = s.name = new_id;
s.innerHTML = document.getElementById(cp_id).innerHTML;
s.selectedIndex = 0;
return s;
}
// Add another term into chart when clicked on button with id=btnid
function chart_add(btnid)
{
var d, i, add_and, add_or, n;
d = document.getElementById(btnid.substr(0, btnid.length-4)); // chartN-btn
if (d.id == 'chartR')
add_and = d = chart_add_div(d, 'chart');
if (d.id.indexOf('-') < 0)
add_or = d = chart_add_div(d, d.id+'-');
var cn = d.id.substr(5);
for (i = 0; document.getElementById('field'+cn+'-'+i); i++);
cn = cn+'-'+i;
if (!add_or)
d.appendChild(document.createElement('br'));
// Append field-type-value inputs
d.appendChild(chart_copy_select('field0-0-0', 'field'+cn));
d.appendChild(chart_copy_select('type0-0-0', 'type'+cn));
s = document.createElement('input');
s.id = s.name = "value"+cn;
s.size = 40;
d.appendChild(s);
if (add_and)
{
chart_add_btn(add_and, 'AND');
// Add negate button
var n = add_and.id.substr(5);
var i = document.createElement('input');
i.type = 'button';
i.className = 'chart_not_u';
i.id = 'negate'+n+'-btn';
i.onclick = chart_neg_event;
i.value = 'NOT';
add_and.appendChild(i);
// Add hidden input for negate button
i = document.createElement('input');
i.type = 'hidden';
i.name = i.id = 'negate'+n;
document.getElementById('chartR').appendChild(i);
}
if (add_or)
chart_add_btn(add_or, 'OR');
}
function chart_neg(btn)
{
var n = btn.id.substr(6, btn.id.length-10); // negateN
var i = document.getElementById('negate'+n);
i.value = i.value ? '' : '1';
btn.className = 'chart_not_' + (i.value ? 'c' : 'u');
var c = document.getElementById('chart'+n);
if (i.value)
c.className += ' _neg';
else
c.className = c.className.replace(/ _neg/, '');
}
function chart_add_second_event()
{
chart_add_second(this);
}
function chart_neg_event()
{
chart_neg(this);
}
function chart_add_second(btn)
{
var n = btn.id.substr(5, btn.id.length-9);
// Transform <div> to <fieldset>
var d = document.getElementById('chart'+n);
d.id = 'divchart'+n; // prevent id collisions
btn.id = 'btnchart'+n; // prevent id collisions
var op = (n != 'R' && n.indexOf('-') < 0 ? 'and' : 'or');
// Create <fieldset>
var f = document.createElement('fieldset');
f.id = 'chart'+n;
f.className = 'chart _'+op;
var legend_html = op.toUpperCase()+' '+
'<input type="button" value="+" class="chart_add_button" id="chart'+n+'-btn" onclick="chart_add(this.id)" />';
if (op == 'and')
{
// Move [NOT] to the legend for 'AND' charts
var neg = document.getElementById('negate'+n);
legend_html +=
'<input type="button" value="NOT" class="chart_not_'+(neg.value ? 'c' : 'u')+'"'+
' style="font-size: 85%" id="negate'+n+'-btn" onclick="chart_neg(this)" />';
if (neg.value)
f.className += ' _neg';
neg = document.getElementById('negate'+n+'-btn');
neg.parentNode.removeChild(neg);
}
// Create <legend>
var l = document.createElement('legend');
l.className = '_'+op;
l.innerHTML = legend_html;
f.appendChild(l);
d.parentNode.insertBefore(f, d);
btn.parentNode.removeChild(btn);
d.parentNode.removeChild(d);
while (d.childNodes.length)
f.appendChild(d.childNodes[0]);
// Add an operand
chart_add('chart'+n+'-btn');
}
function chart_add_btn(d, s)
{
var i = document.createElement('input');
i.type = 'button';
i.id = d.id+'-btn';
i.onclick = chart_add_second_event;
i.value = s;
d.appendChild(document.createTextNode(' '));
d.appendChild(i);
}
// Find next available number for div with prefix 'n'
function chart_add_div(d, n)
{
var i, nd;
for (i = 0; document.getElementById(n+i); i++);
nd = document.createElement('div');
nd.id = n+i;
nd.className = 'chart';
d.appendChild(nd);
return nd;
}
// Copy 'fieldx-x-x' or 'typex-x-x' selectbox
function chart_copy_select(cp_id, new_id)
{
var s = document.createElement('select');
s.id = s.name = new_id;
s.innerHTML = document.getElementById(cp_id).innerHTML;
s.selectedIndex = 0;
return s;
}
// Add another term into chart when clicked on button with id=btnid
function chart_add(btnid)
{
var d, i, add_and, add_or, n;
d = document.getElementById(btnid.substr(0, btnid.length-4)); // chartN-btn
if (d.id == 'chartR')
add_and = d = chart_add_div(d, 'chart');
if (d.id.indexOf('-') < 0)
add_or = d = chart_add_div(d, d.id+'-');
var cn = d.id.substr(5);
for (i = 0; document.getElementById('field'+cn+'-'+i); i++);
cn = cn+'-'+i;
if (!add_or)
d.appendChild(document.createElement('br'));
// Append field-type-value inputs
d.appendChild(chart_copy_select('field0-0-0', 'field'+cn));
d.appendChild(chart_copy_select('type0-0-0', 'type'+cn));
s = document.createElement('input');
s.id = s.name = "value"+cn;
s.size = 40;
d.appendChild(s);
if (add_and)
{
chart_add_btn(add_and, 'AND');
// Add negate button
var n = add_and.id.substr(5);
var i = document.createElement('input');
i.type = 'button';
i.className = 'chart_not_u';
i.id = 'negate'+n+'-btn';
i.onclick = chart_neg_event;
i.value = 'NOT';
add_and.appendChild(i);
// Add hidden input for negate button
i = document.createElement('input');
i.type = 'hidden';
i.name = i.id = 'negate'+n;
document.getElementById('chartR').appendChild(i);
}
if (add_or)
chart_add_btn(add_or, 'OR');
}
function chart_neg(btn)
{
var n = btn.id.substr(6, btn.id.length-10); // negateN
var i = document.getElementById('negate'+n);
i.value = i.value ? '' : '1';
btn.className = 'chart_not_' + (i.value ? 'c' : 'u');
var c = document.getElementById('chart'+n);
if (i.value)
c.className += ' _neg';
else
c.className = c.className.replace(/ _neg/, '');
}
function chart_add_second_event()
{
chart_add_second(this);
}
function chart_neg_event()
{
chart_neg(this);
}

View File

@ -2,22 +2,22 @@
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
* The Original Code is the Bugzilla Bug Tracking System.
*
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
*
* Contributor(s): Mike Shaver <shaver@mozilla.org>
* Christian Reis <kiko@async.com.br>
* André Batosti <batosti@async.com.br>
* André Batosti <batosti@async.com.br>
*/
if (!Node) {
@ -130,7 +130,7 @@ function duplicated(element) {
highlighted = 0;
return;
}
}
}
highlighted = element;
var elem = document.getElementById(element);
highlightedclass = elem.className;

View File

@ -18,135 +18,16 @@
* Guy Pyrzak <guy.pyrzak@gmail.com>
*/
/* This library assumes that the needed YUI libraries have been loaded
already. */
function createCalendar(name) {
var cal = new YAHOO.widget.Calendar('calendar_' + name,
'con_calendar_' + name);
YAHOO.bugzilla['calendar_' + name] = cal;
var field = document.getElementById(name);
cal.selectEvent.subscribe(setFieldFromCalendar, field, false);
updateCalendarFromField(field);
cal.render();
}
/* The onclick handlers for the button that shows the calendar. */
function showCalendar(field_name) {
var calendar = YAHOO.bugzilla["calendar_" + field_name];
var field = document.getElementById(field_name);
var button = document.getElementById('button_calendar_' + field_name);
bz_overlayBelow(calendar.oDomContainer, field);
calendar.show();
button.onclick = function() { hideCalendar(field_name); };
// Because of the way removeListener works, this has to be a function
// attached directly to this calendar.
calendar.bz_myBodyCloser = function(event) {
var container = this.oDomContainer;
var target = YAHOO.util.Event.getTarget(event);
if (target != container && target != button
&& !YAHOO.util.Dom.isAncestor(container, target))
{
hideCalendar(field_name);
}
};
// If somebody clicks outside the calendar, hide it.
YAHOO.util.Event.addListener(document.body, 'click',
calendar.bz_myBodyCloser, calendar, true);
// Make Esc close the calendar.
calendar.bz_escCal = function (event) {
var key = YAHOO.util.Event.getCharCode(event);
if (key == 27) {
hideCalendar(field_name);
}
};
YAHOO.util.Event.addListener(document.body, 'keydown', calendar.bz_escCal);
}
function hideCalendar(field_name) {
var cal = YAHOO.bugzilla["calendar_" + field_name];
cal.hide();
var button = document.getElementById('button_calendar_' + field_name);
button.onclick = function() { showCalendar(field_name); };
YAHOO.util.Event.removeListener(document.body, 'click',
cal.bz_myBodyCloser);
YAHOO.util.Event.removeListener(document.body, 'keydown', cal.bz_escCal);
}
/* This is the selectEvent for our Calendar objects on our custom
* DateTime fields.
*/
function setFieldFromCalendar(type, args, date_field) {
var dates = args[0];
var setDate = dates[0];
// We can't just write the date straight into the field, because there
// might already be a time there.
var timeRe = /\b(\d{1,2}):(\d\d)(?::(\d\d))?/;
var currentTime = timeRe.exec(date_field.value);
var d = new Date(setDate[0], setDate[1] - 1, setDate[2]);
if (currentTime) {
d.setHours(currentTime[1], currentTime[2]);
if (currentTime[3]) {
d.setSeconds(currentTime[3]);
}
}
var year = d.getFullYear();
// JavaScript's "Date" represents January as 0 and December as 11.
var month = d.getMonth() + 1;
if (month < 10) month = '0' + String(month);
var day = d.getDate();
if (day < 10) day = '0' + String(day);
var dateStr = year + '-' + month + '-' + day;
if (currentTime) {
var minutes = d.getMinutes();
if (minutes < 10) minutes = '0' + String(minutes);
var seconds = d.getSeconds();
if (seconds > 0 && seconds < 10) {
seconds = '0' + String(seconds);
}
dateStr = dateStr + ' ' + d.getHours() + ':' + minutes;
if (seconds) dateStr = dateStr + ':' + seconds;
}
date_field.value = dateStr;
hideCalendar(date_field.id);
}
/* Sets the calendar based on the current field value.
*/
function updateCalendarFromField(date_field) {
var dateRe = /(\d\d\d\d)-(\d\d?)-(\d\d?)/;
var pieces = dateRe.exec(date_field.value);
if (pieces) {
var cal = YAHOO.bugzilla["calendar_" + date_field.id];
cal.select(new Date(pieces[1], pieces[2] - 1, pieces[3]));
var selectedArray = cal.getSelectedDates();
var selected = selectedArray[0];
cal.cfg.setProperty("pagedate", (selected.getMonth() + 1) + '/'
+ selected.getFullYear());
cal.render();
}
}
/* Hide input fields and show the text with (edit) next to it */
function hideEditableField( container, input, action, field_id, original_value ) {
YAHOO.util.Dom.removeClass(container, 'bz_default_hidden');
YAHOO.util.Dom.addClass(input, 'bz_default_hidden');
YAHOO.util.Event.addListener(action, 'click', showEditableField,
new Array(container, input));
if(field_id != ""){
YAHOO.util.Event.addListener(window, 'load', checkForChangedFieldValues,
new Array(container, input, field_id, original_value));
}
/* Hide input fields and show the text with (edit) next to it */
function hideEditableField( container, input, action, field_id, original_value )
{
removeClass(container, 'bz_default_hidden');
addClass(input, 'bz_default_hidden');
addListener(action, 'click', function(ev) { return showEditableField(ev, [ container, input ]); });
if (field_id != "")
addListener(window, 'load', function(ev) {
return checkForChangedFieldValues(ev, [ container, input, field_id, original_value ])
});
}
/* showEditableField (e, ContainerInputArray)
@ -158,29 +39,31 @@ function hideEditableField( container, input, action, field_id, original_value )
* var ContainerInputArray[1]: the input area and label that will be displayed
*
*/
function showEditableField (e, ContainerInputArray) {
function showEditableField(e, ContainerInputArray)
{
var inputs = new Array();
var inputArea = YAHOO.util.Dom.get(ContainerInputArray[1]);
if ( ! inputArea ){
YAHOO.util.Event.preventDefault(e);
return;
var inputArea = ContainerInputArray[1];
if (!inputArea)
{
if (e.preventDefault) e.preventDefault();
return false;
}
YAHOO.util.Dom.addClass(ContainerInputArray[0], 'bz_default_hidden');
YAHOO.util.Dom.removeClass(inputArea, 'bz_default_hidden');
if ( inputArea.tagName.toLowerCase() == "input" ) {
addClass(ContainerInputArray[0], 'bz_default_hidden');
removeClass(inputArea, 'bz_default_hidden');
if (inputArea.tagName.toLowerCase() == "input")
inputs.push(inputArea);
} else {
else
inputs = inputArea.getElementsByTagName('input');
}
if ( inputs.length > 0 ) {
if (inputs.length > 0)
{
// focus on the first field, this makes it easier to edit
inputs[0].focus();
inputs[0].select();
}
YAHOO.util.Event.preventDefault(e);
if (e.preventDefault) e.preventDefault();
return false;
}
/* checkForChangedFieldValues(e, array )
* Function checks if after the autocomplete by the browser if the values match the originals.
* If they don't match then hide the text and show the input so users don't get confused.
@ -189,10 +72,10 @@ function showEditableField (e, ContainerInputArray) {
* var ContainerInputArray: An array containing the (edit) and text area and the input being displayed
* var ContainerInputArray[0]: the conainer that will be hidden usually shows the (edit) text
* var ContainerInputArray[1]: the input area and label that will be displayed
* var ContainerInputArray[2]: the field that is on the page, might get changed by browser autocomplete
* var ContainerInputArray[2]: the field that is on the page, might get changed by browser autocomplete
* var ContainerInputArray[3]: the original value from the page loading.
*
*/
*/
function checkForChangedFieldValues(e, ContainerInputArray ) {
var el = document.getElementById(ContainerInputArray[2]);
var unhide = false;
@ -207,174 +90,177 @@ function checkForChangedFieldValues(e, ContainerInputArray ) {
if ( set_default ) {
if(set_default.checked){
unhide = true;
}
}
}
}
}
if(unhide){
YAHOO.util.Dom.addClass(ContainerInputArray[0], 'bz_default_hidden');
YAHOO.util.Dom.removeClass(ContainerInputArray[1], 'bz_default_hidden');
if(unhide)
{
addClass(ContainerInputArray[0], 'bz_default_hidden');
removeClass(ContainerInputArray[1], 'bz_default_hidden');
}
}
function hideAliasAndSummary(short_desc_value, alias_value) {
function hideAliasAndSummary(short_desc_value, alias_value)
{
// check the short desc field
hideEditableField( 'summary_alias_container','summary_alias_input',
'editme_action','short_desc', short_desc_value);
hideEditableField(
'summary_alias_container','summary_alias_input',
'editme_action','short_desc', short_desc_value
);
// check that the alias hasn't changed
var bz_alias_check_array = new Array('summary_alias_container',
'summary_alias_input', 'alias', alias_value);
YAHOO.util.Event.addListener( window, 'load', checkForChangedFieldValues,
bz_alias_check_array);
var bz_alias_check_array = [
'summary_alias_container', 'summary_alias_input', 'alias', alias_value
];
addListener(window, 'load',
function(ev) { return checkForChangedFieldValues(ev, bz_alias_check_array) }
);
}
function showPeopleOnChange( field_id_list ) {
for(var i = 0; i < field_id_list.length; i++) {
YAHOO.util.Event.addListener( field_id_list[i],'change', showEditableField,
new Array('bz_qa_contact_edit_container',
'bz_qa_contact_input'));
YAHOO.util.Event.addListener( field_id_list[i],'change',showEditableField,
new Array('bz_assignee_edit_container',
'bz_assignee_input'));
function showPeopleOnChange(field_id_list)
{
for (var i = 0; i < field_id_list.length; i++)
{
addListener(field_id_list[i], 'change',
function(ev) { return showEditableField(ev, [ 'bz_qa_contact_edit_container', 'bz_qa_contact_input' ]) });
addListener(field_id_list[i], 'change',
function(ev) { return showEditableField(ev, [ 'bz_assignee_edit_container', 'bz_assignee_input']) });
}
}
function assignToDefaultOnChange(field_id_list) {
showPeopleOnChange( field_id_list );
for(var i = 0; i < field_id_list.length; i++) {
YAHOO.util.Event.addListener( field_id_list[i],'change', setDefaultCheckbox,
'set_default_assignee');
YAHOO.util.Event.addListener( field_id_list[i],'change',setDefaultCheckbox,
'set_default_qa_contact');
function assignToDefaultOnChange(field_id_list)
{
showPeopleOnChange(field_id_list);
for (var i = 0; i < field_id_list.length; i++)
{
addListener(field_id_list[i], 'change',
function(ev) { return setDefaultCheckbox(ev, 'set_default_assignee') });
addListener(field_id_list[i], 'change',
function(ev) { return setDefaultCheckbox(ev, 'set_default_qa_contact') });
}
}
function initDefaultCheckbox(field_id){
YAHOO.util.Event.addListener( 'set_default_' + field_id,'change', boldOnChange,
'set_default_' + field_id);
YAHOO.util.Event.addListener( window,'load', checkForChangedFieldValues,
new Array( 'bz_' + field_id + '_edit_container',
'bz_' + field_id + '_input',
'set_default_' + field_id ,'1'));
YAHOO.util.Event.addListener( window, 'load', boldOnChange,
'set_default_' + field_id );
function initDefaultCheckbox(field_id)
{
addListener('set_default_'+field_id, 'change',
function(ev) { return boldOnChange(ev, 'set_default_'+field_id) });
addListener(window, 'load',
function(ev) { return checkForChangedFieldValues(ev, [
'bz_'+field_id+'_edit_container', 'bz_'+field_id+'_input',
'set_default_'+field_id, '1' ]) });
addListener(window, 'load',
function(ev) { return boldOnChange(ev, 'set_default_'+field_id) });
}
function showHideStatusItems(e, dupArrayInfo) {
function showHideStatusItems(is_duplicate, initial_status)
{
var el = document.getElementById('bug_status');
// finish doing stuff based on the selection.
if ( el ) {
if (el)
{
showDuplicateItem(el);
// Make sure that fields whose visibility or values are controlled
// by "resolution" behave properly when resolution is hidden.
var resolution = document.getElementById('resolution');
if (resolution && resolution.options[0].value != '') {
if (resolution && resolution.options[0].value != '')
{
resolution.bz_lastSelected = resolution.selectedIndex;
var emptyOption = new Option('', '');
resolution.insertBefore(emptyOption, resolution.options[0]);
emptyOption.selected = true;
}
YAHOO.util.Dom.addClass('resolution_settings', 'bz_default_hidden');
if (document.getElementById('resolution_settings_warning')) {
YAHOO.util.Dom.addClass('resolution_settings_warning',
'bz_default_hidden');
}
YAHOO.util.Dom.addClass('duplicate_display', 'bz_default_hidden');
if ( (el.value == dupArrayInfo[1] && dupArrayInfo[0] == "is_duplicate")
|| bz_isValueInArray(close_status_array, el.value) )
addClass('resolution_settings', 'bz_default_hidden');
if (document.getElementById('resolution_settings_warning'))
addClass('resolution_settings_warning', 'bz_default_hidden');
addClass('duplicate_display', 'bz_default_hidden');
if (el.value == initial_status && is_duplicate == "is_duplicate" ||
bz_isValueInArray(close_status_array, el.value))
{
YAHOO.util.Dom.removeClass('resolution_settings',
'bz_default_hidden');
YAHOO.util.Dom.removeClass('resolution_settings_warning',
'bz_default_hidden');
removeClass('resolution_settings', 'bz_default_hidden');
removeClass('resolution_settings_warning', 'bz_default_hidden');
// Remove the blank option we inserted.
if (resolution && resolution.options[0].value == '') {
if (resolution && resolution.options[0].value == '')
{
resolution.removeChild(resolution.options[0]);
resolution.selectedIndex = resolution.bz_lastSelected;
}
}
if (resolution) {
if (resolution)
bz_fireEvent(resolution, 'change');
}
}
}
function showDuplicateItem(e) {
function showDuplicateItem(e)
{
var resolution = document.getElementById('resolution');
var bug_status = document.getElementById('bug_status');
var dup_id = document.getElementById('dup_id');
if (resolution) {
if (resolution.value == 'DUPLICATE' && bz_isValueInArray( close_status_array, bug_status.value) ) {
if (resolution && dup_id)
{
if (resolution.value == 'DUPLICATE' && bz_isValueInArray(close_status_array, bug_status.value))
{
// hide resolution show duplicate
YAHOO.util.Dom.removeClass('duplicate_settings',
'bz_default_hidden');
YAHOO.util.Dom.addClass('dup_id_discoverable', 'bz_default_hidden');
removeClass('duplicate_settings', 'bz_default_hidden');
addClass('dup_id_discoverable', 'bz_default_hidden');
// check to make sure the field is visible or IE throws errors
if( ! YAHOO.util.Dom.hasClass( dup_id, 'bz_default_hidden' ) ){
if (!hasClass(dup_id, 'bz_default_hidden'))
{
dup_id.focus();
dup_id.select();
}
}
else {
YAHOO.util.Dom.addClass('duplicate_settings', 'bz_default_hidden');
YAHOO.util.Dom.removeClass('dup_id_discoverable',
'bz_default_hidden');
else
{
addClass('duplicate_settings', 'bz_default_hidden');
removeClass('dup_id_discoverable', 'bz_default_hidden');
dup_id.blur();
}
}
YAHOO.util.Event.preventDefault(e); //prevents the hyperlink from going to the url in the href.
// Prevent the hyperlink from going to the url in the href:
if (e.preventDefault) e.preventDefault();
return false;
}
function setResolutionToDuplicate(e, duplicate_or_move_bug_status) {
function setResolutionToDuplicate(duplicate_or_move_bug_status)
{
var status = document.getElementById('bug_status');
var resolution = document.getElementById('resolution');
YAHOO.util.Dom.addClass('dup_id_discoverable', 'bz_default_hidden');
addClass('dup_id_discoverable', 'bz_default_hidden');
status.value = duplicate_or_move_bug_status;
bz_fireEvent(status, 'change');
resolution.value = "DUPLICATE";
bz_fireEvent(resolution, 'change');
YAHOO.util.Event.preventDefault(e);
if (e.preventDefault) e.preventDefault();
return false;
}
function setDefaultCheckbox(e, field_id ) {
function setDefaultCheckbox(e, field_id)
{
var el = document.getElementById(field_id);
var elLabel = document.getElementById(field_id + "_label");
if( el && elLabel ) {
if (el && elLabel)
{
el.checked = "true";
YAHOO.util.Dom.setStyle(elLabel, 'font-weight', 'bold');
elLabel.style.fontWeight = bold;
}
}
function boldOnChange(e, field_id){
function boldOnChange(e, field_id)
{
var el = document.getElementById(field_id);
var elLabel = document.getElementById(field_id + "_label");
if( el && elLabel ) {
if( el.checked ){
YAHOO.util.Dom.setStyle(elLabel, 'font-weight', 'bold');
}
else{
YAHOO.util.Dom.setStyle(elLabel, 'font-weight', 'normal');
}
}
if (el && elLabel)
elLabel.style.fontWeight = el.checked ? 'bold' : 'normal';
}
function updateCommentTagControl(checkbox, form) {
if (checkbox.checked) {
form.comment.className='bz_private';
} else {
form.comment.className='';
}
function updateCommentTagControl(checkbox, form)
{
form.comment.className = checkbox.checked ? 'bz_private' : '';
}
// 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) {
function _value_id(field_name, id)
{
return 'v' + id + '_' + field_name;
}

View File

@ -28,59 +28,61 @@
// the user is requesting the corresponding flag.
function toggleRequesteeField(flagField, no_focus)
{
// Convert the ID of the flag field into the ID of its corresponding
// requestee field and then use the ID to get the field.
var id = flagField.name.replace(/flag(_type)?-(\d+)/, "requestee$1-$2");
var requesteeField = document.getElementById(id);
if (!requesteeField) return;
// Convert the ID of the flag field into the ID of its corresponding
// requestee field and then use the ID to get the field.
var id = flagField.name.replace(/flag(_type)?-(\d+)/, "requestee$1-$2");
var requesteeField = document.getElementById(id);
if (!requesteeField) return;
// Enable or disable the requestee field based on the value
// of the flag field.
if (flagField.value == "?") {
requesteeField.disabled = false;
if (!no_focus) requesteeField.focus();
} else {
requesteeField.disabled = true;
}
// For combo-boxes
var rcombosel = document.getElementById(id+'_s');
if (rcombosel && (rcombosel.disabled = requesteeField.disabled))
menuforusers_showmulti(id);
// Enable or disable the requestee field based on the value
// of the flag field.
if (flagField.value == "?")
{
requesteeField.disabled = false;
if (!no_focus)
requesteeField.focus();
}
else
requesteeField.disabled = true;
// For combo-boxes
var rcombosel = document.getElementById(id+'_s');
if (rcombosel && (rcombosel.disabled = requesteeField.disabled))
menuforusers_showmulti(id);
}
// Disables requestee fields when the window is loaded since they shouldn't
// be enabled until the user requests that flag type.
function disableRequesteeFields()
{
var inputElements = document.getElementsByTagName("input");
var selectElements = document.getElementsByTagName("select");
//You cannot update Node lists, so you must create an array to combine the NodeLists
var allElements = [];
for( var i=0; i < inputElements.length; i++ ) {
allElements[allElements.length] = inputElements.item(i);
}
for( var i=0; i < selectElements.length; i++ ) { //Combine inputs with selects
allElements[allElements.length] = selectElements.item(i);
}
var inputElement, id, flagField;
for ( var i=0 ; i<allElements.length ; i++ )
{
inputElement = allElements[i];
if (inputElement.name.search(/^requestee(_type)?-(\d+)$/) != -1)
var inputElements = document.getElementsByTagName("input");
var selectElements = document.getElementsByTagName("select");
// You cannot update Node lists, so you must create an array to combine the NodeLists
var allElements = [];
for (var i = 0; i < inputElements.length; i++)
allElements.push(inputElements.item(i));
// Combine inputs with selects
for (var i = 0; i < selectElements.length; i++)
allElements.push(selectElements.item(i));
var inputElement, id, flagField;
for (var i = 0; i < allElements.length; i++)
{
// Convert the ID of the requestee field into the ID of its corresponding
// flag field and then use the ID to get the field.
id = inputElement.name.replace(/requestee(_type)?-(\d+)/, "flag$1-$2");
flagField = document.getElementById(id);
if (flagField && flagField.value != "?")
{
inputElement.disabled = true;
// For combo-boxes
inputElement = document.getElementById(inputElement.id+'_s');
if (inputElement)
inputElement.disabled = true;
}
inputElement = allElements[i];
if (inputElement.name.search(/^requestee(_type)?-(\d+)$/) != -1)
{
// Convert the ID of the requestee field into the ID of its corresponding
// flag field and then use the ID to get the field.
id = inputElement.name.replace(/requestee(_type)?-(\d+)/, "flag$1-$2");
flagField = document.getElementById(id);
if (flagField && flagField.value != "?")
{
inputElement.disabled = true;
// For combo-boxes
inputElement = document.getElementById(inputElement.id+'_s');
if (inputElement)
inputElement.disabled = true;
}
}
}
}
}
YAHOO.util.Event.addListener(window, "load", disableRequesteeFields);
addListener(window, "load", disableRequesteeFields);

View File

@ -17,254 +17,191 @@
var mini_login_constants;
function show_mini_login_form( suffix ) {
function show_mini_login_form( suffix )
{
var login_link = document.getElementById('login_link' + suffix);
var login_form = document.getElementById('mini_login' + suffix);
var account_container = document.getElementById('new_account_container'
+ suffix);
YAHOO.util.Dom.addClass(login_link, 'bz_default_hidden');
YAHOO.util.Dom.removeClass(login_form, 'bz_default_hidden');
YAHOO.util.Dom.addClass(account_container, 'bz_default_hidden');
var account_container = document.getElementById('new_account_container' + suffix);
addClass(login_link, 'bz_default_hidden');
removeClass(login_form, 'bz_default_hidden');
addClass(account_container, 'bz_default_hidden');
login_form._shown = true;
return false;
}
function hide_mini_login_form( suffix ) {
function hide_mini_login_form( suffix )
{
var login_link = document.getElementById('login_link' + suffix);
var login_form = document.getElementById('mini_login' + suffix);
var account_container = document.getElementById('new_account_container'
+ suffix);
YAHOO.util.Dom.removeClass(login_link, 'bz_default_hidden');
YAHOO.util.Dom.addClass(login_form, 'bz_default_hidden');
YAHOO.util.Dom.removeClass(account_container, 'bz_default_hidden');
var account_container = document.getElementById('new_account_container' + suffix);
removeClass(login_link, 'bz_default_hidden');
addClass(login_form, 'bz_default_hidden');
removeClass(account_container, 'bz_default_hidden');
return false;
}
function show_forgot_form( suffix ) {
function show_forgot_form( suffix )
{
var forgot_link = document.getElementById('forgot_link' + suffix);
var forgot_form = document.getElementById('forgot_form' + suffix);
var login_container = document.getElementById('mini_login_container'
+ suffix);
YAHOO.util.Dom.addClass(forgot_link, 'bz_default_hidden');
YAHOO.util.Dom.removeClass(forgot_form, 'bz_default_hidden');
YAHOO.util.Dom.addClass(login_container, 'bz_default_hidden');
var login_container = document.getElementById('mini_login_container' + suffix);
addClass(forgot_link, 'bz_default_hidden');
removeClass(forgot_form, 'bz_default_hidden');
addClass(login_container, 'bz_default_hidden');
return false;
}
function hide_forgot_form( suffix ) {
function hide_forgot_form( suffix )
{
var forgot_link = document.getElementById('forgot_link' + suffix);
var forgot_form = document.getElementById('forgot_form' + suffix);
var login_container = document.getElementById('mini_login_container'
+ suffix);
YAHOO.util.Dom.removeClass(forgot_link, 'bz_default_hidden');
YAHOO.util.Dom.addClass(forgot_form, 'bz_default_hidden');
YAHOO.util.Dom.removeClass(login_container, 'bz_default_hidden');
var login_container = document.getElementById('mini_login_container' + suffix);
removeClass(forgot_link, 'bz_default_hidden');
addClass(forgot_form, 'bz_default_hidden');
removeClass(login_container, 'bz_default_hidden');
return false;
}
function init_mini_login_form( suffix ) {
function init_mini_login_form( suffix )
{
var mini_login = document.getElementById('Bugzilla_login' + suffix );
var mini_password = document.getElementById('Bugzilla_password' + suffix );
var mini_dummy = document.getElementById(
'Bugzilla_password_dummy' + suffix);
// If the login and password are blank when the page loads, we display
// "login" and "password" in the boxes by default.
if (mini_login.value == "" && mini_password.value == "") {
if (mini_login.value == "" && mini_password.value == "")
{
mini_login.value = mini_login_constants.login;
YAHOO.util.Dom.addClass(mini_login, "bz_mini_login_help");
YAHOO.util.Dom.addClass(mini_password, 'bz_default_hidden');
YAHOO.util.Dom.removeClass(mini_dummy, 'bz_default_hidden');
addClass(mini_login, "bz_mini_login_help");
addClass(mini_password, 'bz_default_hidden');
removeClass(mini_dummy, 'bz_default_hidden');
}
else {
else
show_mini_login_form(suffix);
}
}
// Clear the words "login" and "password" from the form when you click
// in one of the boxes. We clear them both when you click in either box
// so that the browser's password-autocomplete can work.
function mini_login_on_focus( suffix ) {
var mini_login = document.getElementById('Bugzilla_login' + suffix );
var mini_password = document.getElementById('Bugzilla_password' + suffix );
var mini_dummy = document.getElementById(
'Bugzilla_password_dummy' + suffix);
function mini_login_on_focus(suffix)
{
var mini_login = document.getElementById('Bugzilla_login' + suffix);
var mini_password = document.getElementById('Bugzilla_password' + suffix);
var mini_dummy = document.getElementById('Bugzilla_password_dummy' + suffix);
YAHOO.util.Dom.removeClass(mini_login, "bz_mini_login_help");
if (mini_login.value == mini_login_constants.login) {
removeClass(mini_login, "bz_mini_login_help");
if (mini_login.value == mini_login_constants.login)
mini_login.value = '';
}
YAHOO.util.Dom.removeClass(mini_password, 'bz_default_hidden');
YAHOO.util.Dom.addClass(mini_dummy, 'bz_default_hidden');
removeClass(mini_password, 'bz_default_hidden');
addClass(mini_dummy, 'bz_default_hidden');
}
function check_mini_login_fields( suffix ) {
var mini_login = document.getElementById('Bugzilla_login' + suffix );
var mini_password = document.getElementById('Bugzilla_password' + suffix );
if( (mini_login.value != "" && mini_password.value != "")
&& mini_login.value != mini_login_constants.login )
{
return true;
}
window.alert( mini_login_constants.warning );
function check_mini_login_fields(suffix)
{
var mini_login = document.getElementById('Bugzilla_login' + suffix);
var mini_password = document.getElementById('Bugzilla_password' + suffix);
if (mini_login.value != "" && mini_password.value != "" &&
mini_login.value != mini_login_constants.login)
return true;
window.alert(mini_login_constants.warning);
return false;
}
function set_language( value ) {
YAHOO.util.Cookie.set('LANG', value,
{
function set_language(value)
{
setCookie('LANG', value, {
expires: new Date('January 1, 2038'),
path: BUGZILLA.param.cookie_path
});
window.location.reload()
window.location.reload();
}
/* template/en/global/menuforusers.html.tmpl */
function dump(arr,level)
{
var dumped_text = "";
if(!level) level = 0;
var level_padding = "";
for(var j=0;j<level+1;j++)
level_padding += " ";
if(typeof(arr) == 'object') {
for(var item in arr) {
var value = arr[item];
if(typeof(value) == 'object') {
dumped_text += level_padding + "'" + item + "' ...\n";
dumped_text += dump(value,level+1);
} else {
dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
}
}
} else {
dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
}
return dumped_text;
}
function menuforusers_initcombo(id, multi)
{
var sel = document.getElementById(id+"_s");
var ed = document.getElementById(id);
if (!sel || !ed)
return;
var p = sel.parentNode;
/* We must move <select> out of its parent element temporarily,
because it can be invisible in some cases (i.e. New Bug form),
and have offsetWidth=offsetHeight=0 */
document.body.appendChild(sel);
var w = (sel.offsetWidth-sel.offsetHeight+2);
if (w > 400)
{
w = 400;
sel.style.width = (w+sel.offsetHeight-2)+'px';
}
ed.style.width = w+'px';
p.appendChild(sel);
ed.style.borderWidth = 0;
menuforusers_tocombo(id);
if (multi)
{
YAHOO.util.Event.addListener(document.body, "click", function(ev) {
if (!ev) var ev = window.event;
var t = ev.target;
if (!t) t = ev.srcElement;
if (t.nodeType == 3) t = t.parentNode; // Safari bug
if (t.id != id && t.id != id+'_b' && t.id != id+'_s' && t.parentNode.id != id+'_s')
menuforusers_showmulti(id, false)
});
YAHOO.util.Event.addListener(document.getElementById(id+'_b'), "click", function(ev) { menuforusers_showmulti(id); });
}
}
RegExp.escape = function(text) {
if (!arguments.callee.sRE) {
var specials = [
'/', '.', '*', '+', '?', '|',
'(', ')', '[', ']', '{', '}', '\\'
];
arguments.callee.sRE = new RegExp(
'(\\' + specials.join('|\\') + ')', 'g'
);
}
return text.replace(arguments.callee.sRE, '\\$1');
var sel = document.getElementById(id+"_s");
var ed = document.getElementById(id);
if (!sel || !ed)
return;
var p = sel.parentNode;
/* We must move <select> out of its parent element temporarily,
because it can be invisible in some cases (i.e. New Bug form),
and have offsetWidth=offsetHeight=0 */
document.body.appendChild(sel);
var w = (sel.offsetWidth-sel.offsetHeight+2);
if (w > 400)
{
w = 400;
sel.style.width = (w+sel.offsetHeight-2)+'px';
}
ed.style.width = w+'px';
p.appendChild(sel);
ed.style.borderWidth = 0;
menuforusers_tocombo(id);
if (multi)
{
addListener(document.body, "click", function(ev) {
t = eventTarget(ev);
if (t.id != id && t.id != id+'_b' && t.id != id+'_s' && t.parentNode.id != id+'_s')
menuforusers_showmulti(id, false)
});
addListener(document.getElementById(id+'_b'), "click", function(ev) { menuforusers_showmulti(id); });
}
}
function menuforusers_tocombo(id, multi)
{
var sel = document.getElementById(id+"_s");
var ed = document.getElementById(id);
if (!sel || !ed)
return;
var nv = [];
var v = ed.value.split(/[\s,]+/);
var i, j;
for (i = 0; i < v.length; i++)
{
for (j = 0; j < sel.options.length; j++)
var sel = document.getElementById(id+"_s");
var ed = document.getElementById(id);
if (!sel || !ed)
return;
var nv = [];
var v = ed.value.split(/[\s,]+/);
var i, j;
for (i = 0; i < v.length; i++)
{
if (sel.options[j].value.toLowerCase().indexOf(v[i].toLowerCase()) >= 0 ||
sel.options[j].text.toLowerCase().indexOf(v[i].toLowerCase()) >= 0)
{
sel.options[j].selected = true;
nv.push(sel.options[j].value);
break;
}
for (j = 0; j < sel.options.length; j++)
{
if (sel.options[j].value.toLowerCase().indexOf(v[i].toLowerCase()) >= 0 ||
sel.options[j].text.toLowerCase().indexOf(v[i].toLowerCase()) >= 0)
{
sel.options[j].selected = true;
nv.push(sel.options[j].value);
break;
}
}
if (j >= sel.options.length)
nv.push(v[i]);
if (!multi)
break;
}
if (j >= sel.options.length)
nv.push(v[i]);
if (!multi)
break;
}
ed.value = nv.join(', ');
ed.value = nv.join(', ');
}
function menuforusers_fromcombo(id, multi)
{
var sel = document.getElementById(id+"_s");
var ed = document.getElementById(id);
if (!sel || !ed)
return;
v = [];
for (var i = 0; i < sel.options.length; i++)
if (sel.options[i].selected)
v.push(sel.options[i].value);
ed.value = v.join(', ');
var sel = document.getElementById(id+"_s");
var ed = document.getElementById(id);
if (!sel || !ed)
return;
v = [];
for (var i = 0; i < sel.options.length; i++)
if (sel.options[i].selected)
v.push(sel.options[i].value);
ed.value = v.join(', ');
}
function menuforusers_showmulti(id, wha)
{
var sel = document.getElementById(id+"_s");
var btn = document.getElementById(id+"_b");
if (!sel || !btn)
return;
var show = sel.style.visibility == 'hidden' && !sel.disabled;
if (typeof(wha) != 'undefined')
show = wha;
sel.style.visibility = show ? '' : 'hidden';
btn.src = 'images/dn' + (show ? 'push' : '') + '.gif';
}
/* work time parser: "1,5" or "1:30" (HH:MM) = 1.5, "1.5d" (days) = 12 */
function bzParseTime(time)
{
time = time+"";
time = time.replace(',','.');
if (m = time.match(/^\s*(-?)(\d+):(\d+)\s*$/))
{
for (var i = 2; i < 5; i++)
{
if (!m[i]) m[i] = 0;
else m[i] = parseInt(m[i]);
}
if (!m[1]) m[1] = '';
time = Math.floor(parseFloat(m[1] + (m[2] + m[3]/60))*100+0.5)/100;
}
else if (m = time.match(/^\s*(-?\d+(?:\.\d+)?)d\s*$/))
time = parseFloat(m[1])*8;
else
time = parseFloat(time);
return time;
var sel = document.getElementById(id+"_s");
var btn = document.getElementById(id+"_b");
if (!sel || !btn)
return;
var show = sel.style.visibility == 'hidden' && !sel.disabled;
if (typeof(wha) != 'undefined')
show = wha;
sel.style.visibility = show ? '' : 'hidden';
btn.src = 'images/dn' + (show ? 'push' : '') + '.gif';
}

View File

@ -81,8 +81,9 @@ function showHelp() {
return;
// Get the position and size of the form element in the document
var elemY = bz_findPosY(this);
var elemX = bz_findPosX(this);
var elemPos = findPos(this);
var elemX = elemPos[0];
var elemY = elemPos[1];
var elemH = this.offsetHeight;
// Update help text displayed in the div

View File

@ -2,19 +2,19 @@
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
*
* The Original Code is the Bugzilla Bug Tracking System.
*
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
*
* Contributor(s): Christian Reis <kiko@async.com.br>
*/
@ -52,7 +52,7 @@ function selectClassification(classfield, product, component, version, milestone
first_load = false;
return;
}
// Don't reset first_load as done in selectProduct. That's because we
// want selectProduct to handle the first_load attribute.
@ -69,7 +69,7 @@ function selectClassification(classfield, product, component, version, milestone
if (!findall) {
// Save sel for the next invocation of selectClassification().
var tmp = sel;
// This is an optimization: if we have just added classifications to an
// existing selection, no need to clear the form elements and add
// everything again; just merge the new ones with the existing

View File

@ -1,20 +1,4 @@
/* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Bugzilla Bug Tracking System.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
/* License: Dual-license GPL 3.0+ or MPL 1.1+
* Contributor(s): Vitaliy Filippov <vitalif@mail.ru>
*/
@ -66,64 +50,65 @@ respecting this "list of active IDs".
*/
var qfHandling = {};
YAHOO.util.Event.addListener(window, 'load', initQueryformFields);
addListener(window, 'load', initQueryformFields);
function initQueryformFields()
{
for (var i in qfVisibility)
{
if (!qfHandling[i])
handleQueryformField(null, document.getElementById(i));
initQueryformField(i);
}
for (var i in qfVisibility)
{
if (!qfHandling[i])
handleQueryformField(null, document.getElementById(i));
initQueryformField(i);
}
}
function initQueryformField(i)
{
var f = document.getElementById(i);
YAHOO.util.Event.addListener(f, 'change', handleQueryformField, f);
var f = document.getElementById(i);
if (f)
addListener(f, 'change', handleQueryformField_this);
}
// Get selected IDs of names selected in selectbox sel
function getQueryformSelectedIds(sel)
{
var opt = {};
var a;
var has_selected;
var l2 = sel.id.length+4;
// No selection is equivalent to full selection
for (var i = 0; i < sel.options.length; i++)
{
if (sel.options[i].selected)
var opt = {};
var a;
var has_selected;
var l2 = sel.id.length+4;
// No selection is equivalent to full selection
for (var i = 0; i < sel.options.length; i++)
{
has_selected = true;
break;
if (sel.options[i].selected)
{
has_selected = true;
break;
}
}
}
// Iterate over all options
for (var i = 0; i < sel.options.length; i++)
{
if (sel.options[i].selected || !has_selected)
// Iterate over all options
for (var i = 0; i < sel.options.length; i++)
{
// IDs of options are qf_<SELECTBOX_ID>_1_2_3_...
// where 1_2_3 is the list of IDs mapped to this option name
// which are currently visible.
a = sel.options[i].id.substr(l2).split('_');
for (var j in a)
opt[a[j]] = true;
if (sel.options[i].selected || !has_selected)
{
// IDs of options are qf_<SELECTBOX_ID>_1_2_3_...
// where 1_2_3 is the list of IDs mapped to this option name
// which are currently visible.
a = sel.options[i].id.substr(l2).split('_');
for (var j in a)
opt[a[j]] = true;
}
}
}
return opt;
return opt;
}
// Get the array with values of options selected in sel selectbox
function getPlainSelectedIds(sel)
{
var o = {};
for (var i = 0; i < sel.options.length; i++)
if (sel.options[i].selected)
o[sel.options[i].value] = true;
return o;
var o = {};
for (var i = 0; i < sel.options.length; i++)
if (sel.options[i].selected)
o[sel.options[i].value] = true;
return o;
}
// Check visibility of some field or value when it's visible only for ids
@ -134,105 +119,111 @@ function getPlainSelectedIds(sel)
// f({ 2: 1 }, { 1: 1 }) = false
function qfCheckVisibility(visible_for_ids, selected_ids)
{
vis = true;
// Visible also if visible_for_ids is an empty hash
if (visible_for_ids)
{
for (var cid in visible_for_ids)
vis = true;
// Visible also if visible_for_ids is an empty hash
if (visible_for_ids)
{
vis = false;
if (selected_ids[cid])
{
vis = true;
break;
}
for (var cid in visible_for_ids)
{
vis = false;
if (selected_ids[cid])
{
vis = true;
break;
}
}
}
}
return vis;
return vis;
}
// handleQueryformField on 'this' change
function handleQueryformField_this(event)
{
return handleQueryformField(event, this);
}
// Handle change of selection inside a selectbox 'controller'
// Update all dependent fields
function handleQueryformField(event, controller)
{
var controlled, controlled_selected;
var vis, item, legal, name2id, name2id_order, valueVD;
qfHandling[controller.id] = true; // prevent double-action during init
var VD = qfVisibility[controller.id];
var visibility_selected = getQueryformSelectedIds(controller);
var ids = {};
for (var i in VD.fields)
ids[i] = true;
for (var i in VD.values)
ids[i] = true;
for (var controlled_id in ids)
{
controlled = document.getElementById(controlled_id);
if (!controlled)
continue;
if (controlled.nodeName != 'SELECT')
var controlled, controlled_selected;
var vis, item, legal, name2id, name2id_order, valueVD;
qfHandling[controller.id] = true; // prevent double-action during init
var VD = qfVisibility[controller.id];
var visibility_selected = getQueryformSelectedIds(controller);
var ids = {};
for (var i in VD.fields)
ids[i] = true;
for (var i in VD.values)
ids[i] = true;
for (var controlled_id in ids)
{
// Just show/hide non-select fields
item = document.getElementById(controlled_id+'_cont');
if (item)
{
item.style.display = qfCheckVisibility(
VD.fields[controlled_id], visibility_selected
) ? '' : 'none';
}
continue;
}
// Save and clear old selection for dependent field:
controlled_selected = getPlainSelectedIds(controlled);
bz_clearOptions(controlled);
// Loop over all legal values and remember currently
// visible IDs inside name2id preserving their original
// order using name2id_order
legal = qfVisibility[controlled_id]['legal'];
name2id = {};
name2id_order = [];
if (qfCheckVisibility(VD.fields[controlled_id], visibility_selected))
{
var vis_val = VD.values[controlled_id];
// Field is visible
for (var i in legal)
{
if (!vis_val || qfCheckVisibility(vis_val[legal[i][0]], visibility_selected))
controlled = document.getElementById(controlled_id);
if (!controlled)
continue;
if (controlled.nodeName != 'SELECT')
{
// Value is visible
if (!name2id[legal[i][1]])
{
name2id[legal[i][1]] = [];
name2id_order.push(legal[i][1]);
}
name2id[legal[i][1]].push(legal[i][0]);
// Just show/hide non-select fields
item = document.getElementById(controlled_id+'_cont');
if (item)
{
item.style.display = qfCheckVisibility(
VD.fields[controlled_id], visibility_selected
) ? '' : 'none';
}
continue;
}
// Save and clear old selection for dependent field:
controlled_selected = getPlainSelectedIds(controlled);
bz_clearOptions(controlled);
// Loop over all legal values and remember currently
// visible IDs inside name2id preserving their original
// order using name2id_order
legal = qfVisibility[controlled_id]['legal'];
name2id = {};
name2id_order = [];
if (qfCheckVisibility(VD.fields[controlled_id], visibility_selected))
{
var vis_val = VD.values[controlled_id];
// Field is visible
for (var i in legal)
{
if (!vis_val || qfCheckVisibility(vis_val[legal[i][0]], visibility_selected))
{
// Value is visible
if (!name2id[legal[i][1]])
{
name2id[legal[i][1]] = [];
name2id_order.push(legal[i][1]);
}
name2id[legal[i][1]].push(legal[i][0]);
}
}
}
// Create options
for (var i in name2id_order)
{
i = name2id_order[i];
item = bz_createOptionInSelect(controlled, i, i);
/* Save particular selected IDs for the same name
for cascade selection of such fields.
At the moment, only component, version and target_milestone fields
can have many values with the same name, and they do not affect the
case of cascade selection when there are no custom fields depending
on them. */
item.id = 'qf_'+controlled_id+'_'+name2id[i].join('_');
if (controlled_selected[i])
{
// Restore selection
item.selected = true;
}
}
handleQueryformField(event, controlled);
item = document.getElementById(controlled_id+'_cont');
if (item)
{
// Hide fields with no options
item.style.display = controlled.options.length ? '' : 'none';
}
}
}
// Create options
for (var i in name2id_order)
{
i = name2id_order[i];
item = bz_createOptionInSelect(controlled, i, i);
/* Save particular selected IDs for the same name
for cascade selection of such fields.
At the moment, only component, version and target_milestone fields
can have many values with the same name, and they do not affect the
case of cascade selection when there are no custom fields depending
on them. */
item.id = 'qf_'+controlled_id+'_'+name2id[i].join('_');
if (controlled_selected[i])
{
// Restore selection
item.selected = true;
}
}
handleQueryformField(event, controlled);
item = document.getElementById(controlled_id+'_cont');
if (item)
{
// Hide fields with no options
item.style.display = controlled.options.length ? '' : 'none';
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,158 +1,35 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* 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 Cross Platform JavaScript Utility Library.
*
* The Initial Developer of the Original Code is
* Everything Solved.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Max Kanat-Alexander <mkanat@bugzilla.org>
* Christopher A. Aillon <christopher@aillon.com>
*
* ***** END LICENSE BLOCK ***** */
/**
* Locate where an element is on the page, x-wise.
*
* @param obj Element of which location to return.
* @return Current position of the element relative to the left of the
* page window. Measured in pixels.
/* Utility functions for Bugzilla scripts
* Rewritten without YAHOO UI
* License: Dual-license GPL 3.0+ or MPL 1.1+
* Contributor(s): Vitaliy Filippov <vitalif@mail.ru>
*/
function bz_findPosX(obj)
{
var curleft = 0;
if (obj.offsetParent) {
while (obj) {
curleft += obj.offsetLeft;
// Get the position of 'obj' from the page top
// Returns [x, y], in pixels
function findPos(obj)
{
if (obj.offsetParent)
{
var r = [ 0, 0 ];
while (obj)
{
r[0] += obj.offsetLeft;
r[1] += obj.offsetTop;
obj = obj.offsetParent;
}
return r;
}
else if (obj.x) {
curleft += obj.x;
}
return curleft;
else if (obj.y)
return [ obj.x, obj.y ];
}
/**
* Locate where an element is on the page, y-wise.
*
* @param obj Element of which location to return.
* @return Current position of the element relative to the top of the
* page window. Measured in pixels.
*/
function bz_findPosY(obj)
// Checks if a specified value 'val' is in the specified array 'arr'
function bz_isValueInArray(arr, val)
{
var curtop = 0;
if (obj.offsetParent) {
while (obj) {
curtop += obj.offsetTop;
obj = obj.offsetParent;
}
}
else if (obj.y) {
curtop += obj.y;
}
return curtop;
}
/**
* Get the full height of an element, even if it's larger than the browser
* window.
*
* @param fromObj Element of which height to return.
* @return Current height of the element. Measured in pixels.
*/
function bz_getFullHeight(fromObj)
{
var scrollY;
// All but Mac IE
if (fromObj.scrollHeight > fromObj.offsetHeight) {
scrollY = fromObj.scrollHeight;
// Mac IE
} else {
scrollY = fromObj.offsetHeight;
}
return scrollY;
}
/**
* Get the full width of an element, even if it's larger than the browser
* window.
*
* @param fromObj Element of which width to return.
* @return Current width of the element. Measured in pixels.
*/
function bz_getFullWidth(fromObj)
{
var scrollX;
// All but Mac IE
if (fromObj.scrollWidth > fromObj.offsetWidth) {
scrollX = fromObj.scrollWidth;
// Mac IE
} else {
scrollX = fromObj.offsetWidth;
}
return scrollX;
}
/**
* Causes a block to appear directly underneath another block,
* overlaying anything below it.
*
* @param item The block that you want to move.
* @param parent The block that it goes on top of.
* @return nothing
*/
function bz_overlayBelow(item, parent) {
var elemY = bz_findPosY(parent);
var elemX = bz_findPosX(parent);
var elemH = parent.offsetHeight;
item.style.position = 'absolute';
item.style.left = elemX + "px";
item.style.top = elemY + elemH + 1 + "px";
}
/**
* Checks if a specified value is in the specified array.
*
* @param aArray Array to search for the value.
* @param aValue Value to search from the array.
* @return Boolean; true if value is found in the array and false if not.
*/
function bz_isValueInArray(aArray, aValue)
{
var run = 0;
var len = aArray.length;
for ( ; run < len; run++) {
if (aArray[run] == aValue) {
return true;
}
}
return false;
for (var i = arr.length-1; i >= 0; i--)
if (arr[i] == val)
return true;
return false;
}
/**
@ -164,10 +41,11 @@ function bz_isValueInArray(aArray, aValue)
* element.
* @return Created option element.
*/
function bz_createOptionInSelect(aSelect, aTextValue, aValue) {
var myOption = new Option(aTextValue, aValue);
aSelect.options[aSelect.length] = myOption;
return myOption;
function bz_createOptionInSelect(aSelect, aTextValue, aValue)
{
var myOption = new Option(aTextValue, aValue);
aSelect.options[aSelect.length] = myOption;
return myOption;
}
/**
@ -175,13 +53,11 @@ function bz_createOptionInSelect(aSelect, aTextValue, aValue) {
*
* @param aSelect Select form control of which options to clear.
*/
function bz_clearOptions(aSelect) {
var length = aSelect.options.length;
for (var i = 0; i < length; i++) {
aSelect.removeChild(aSelect.options[0]);
}
function bz_clearOptions(aSelect)
{
var length = aSelect.options.length;
for (var i = 0; i < length; i++)
aSelect.removeChild(aSelect.options[0]);
}
/**
@ -191,14 +67,15 @@ function bz_clearOptions(aSelect) {
* before array values are created in it.
* @param aArray Array with values to populate select with.
*/
function bz_populateSelectFromArray(aSelect, aArray) {
// Clear the field
bz_clearOptions(aSelect);
for (var i = 0; i < aArray.length; i++) {
var item = aArray[i];
bz_createOptionInSelect(aSelect, item[1], item[0]);
}
function bz_populateSelectFromArray(aSelect, aArray)
{
// Clear the field
bz_clearOptions(aSelect);
for (var i = 0; i < aArray.length; i++)
{
var item = aArray[i];
bz_createOptionInSelect(aSelect, item[1], item[0]);
}
}
/**
@ -209,13 +86,12 @@ function bz_populateSelectFromArray(aSelect, aArray) {
* @param aSelect The select you're checking.
* @param aValue The value that you want to know about.
*/
function bz_valueSelected(aSelect, aValue) {
function bz_valueSelected(aSelect, aValue)
{
var options = aSelect.options;
for (var i = 0; i < options.length; i++) {
if (options[i].selected && options[i].value == aValue) {
for (var i = 0; i < options.length; i++)
if (options[i].selected && options[i].value == aValue)
return true;
}
}
return false;
}
@ -226,25 +102,26 @@ function bz_valueSelected(aSelect, aValue) {
* @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) {
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) {
function bz_fireEvent(anElement, anEvent)
{
// IE
if (document.createEventObject) {
if (document.createEventObject)
{
var evt = document.createEventObject();
return anElement.fireEvent('on' + anEvent, evt);
}
@ -254,75 +131,61 @@ function bz_fireEvent(anElement, anEvent) {
return !anElement.dispatchEvent(evt);
}
/**
* Adds a CSS class to an element if it doesn't have it. Removes the
* CSS class from the element if the element does have the class.
*
* Requires YUI's Dom library.
*
* @param anElement The element to toggle the class on
* @param aClass The name of the CSS class to toggle.
*/
function bz_toggleClass(anElement, aClass) {
if (YAHOO.util.Dom.hasClass(anElement, aClass)) {
YAHOO.util.Dom.removeClass(anElement, aClass);
}
else {
YAHOO.util.Dom.addClass(anElement, aClass);
}
}
/* map { $_ => 1 } %h */
function array_hash(ar)
{
var h = {};
if (ar.length == 1 && ar[0].length == 0)
var h = {};
if (ar.length == 1 && ar[0].length == 0)
return h;
for (i in ar)
h[ar[i]] = 1;
return h;
for (i in ar)
h[ar[i]] = 1;
return h;
}
/* [a,b,c], [d,b] ---> {d:1},{a:1,c:1} */
/* Calculates the difference between two arrays.
from, to ---> added, removed
[a,b,c], [d,b] ---> {d:1},{a:1,c:1} */
function diff_arrays(a1, a2)
{
var h1 = array_hash(a1);
var h2 = array_hash(a2);
var add = {}, rem = {};
for (i in a1)
if (!h2[a1[i]])
rem[a1[i]] = 1;
for (i in a2)
if (!h1[a2[i]])
add[a2[i]] = 1;
return [ add, rem ];
var h1 = array_hash(a1);
var h2 = array_hash(a2);
var add = {}, rem = {};
for (i in a1)
if (!h2[a1[i]])
rem[a1[i]] = 1;
for (i in a2)
if (!h1[a2[i]])
add[a2[i]] = 1;
return [ add, rem ];
}
/* join ",", grep { $h{$_} } keys %h */
function hash_join(h)
{
var a = [];
for (i in h)
if (h[i])
a.push(i);
return a.join(", ");
var a = [];
for (i in h)
if (h[i])
a.push(i);
return a.join(", ");
}
/* CustIS Bug 64559 - Submit form on Ctrl-Enter */
function ctrlEnter(event, formElem) {
if((event.ctrlKey) && ((event.keyCode == 0xA)||(event.keyCode == 0xD))) {
formElem.commit.click();
return false;
}
return true;
function ctrlEnter(event, formElem)
{
if (event.ctrlKey && (event.keyCode == 0xA || event.keyCode == 0xD))
{
formElem.commit.click();
return false;
}
return true;
}
if (typeof Node == 'undefined') {
/* MSIE doesn't define Node, so provide a compatibility object */
window.Node = {
TEXT_NODE: 3,
ENTITY_REFERENCE_NODE: 5
};
/* MSIE doesn't define Node, so provide a compatibility object */
window.Node = {
TEXT_NODE: 3,
ENTITY_REFERENCE_NODE: 5
};
}
/* Concatenates all text from element's childNodes. This is used
@ -330,20 +193,20 @@ if (typeof Node == 'undefined') {
* innerText is non-standard).
*/
function getText(element) {
var child, text = "";
for (var i=0; i < element.childNodes.length; i++) {
child = element.childNodes[i];
var type = child.nodeType;
if (type == Node.TEXT_NODE || type == Node.ENTITY_REFERENCE_NODE) {
text += child.nodeValue;
} else if (child.nodeName.toLowerCase() == 'br') {
text += "\n";
} else {
/* recurse into nodes of other types */
text += getText(child);
var child, text = "";
for (var i=0; i < element.childNodes.length; i++) {
child = element.childNodes[i];
var type = child.nodeType;
if (type == Node.TEXT_NODE || type == Node.ENTITY_REFERENCE_NODE) {
text += child.nodeValue;
} else if (child.nodeName.toLowerCase() == 'br') {
text += "\n";
} else {
/* recurse into nodes of other types */
text += getText(child);
}
}
}
return text;
return text;
}
/* Functions for comment preview */
@ -354,47 +217,264 @@ function getText(element) {
window.iframeajax_call = 0;
window.iframeajax = function(url, data)
{
var f = document.createElement('form');
var i = document.createElement('iframe');
f.target = i.name = i.id = 'iframeajax_'+(window.iframeajax_call++);
f.method = 'POST';
f.action = url;
var d = document.createElement('div');
d.id = 'div_'+i.id;
data['iframeajaxid'] = i.id.substr(11);
for (var k in data)
{
var n = document.createElement('input');
n.type = 'hidden';
n.name = k;
n.value = data[k];
f.appendChild(n);
}
d.style.display = 'none';
d.appendChild(f);
d.appendChild(i);
document.body.appendChild(d);
window.frames[i.id].name = i.id;
pushEvent(i, 'load', function() {
i.contentWindow.loaded();
i.parentNode.removeChild(i);
});
f.submit();
var f = document.createElement('form');
var i = document.createElement('iframe');
f.target = i.name = i.id = 'iframeajax_'+(window.iframeajax_call++);
f.method = 'POST';
f.action = url;
var d = document.createElement('div');
d.id = 'div_'+i.id;
data['iframeajaxid'] = i.id.substr(11);
for (var k in data)
{
var n = document.createElement('input');
n.type = 'hidden';
n.name = k;
n.value = data[k];
f.appendChild(n);
}
d.style.display = 'none';
d.appendChild(f);
d.appendChild(i);
document.body.appendChild(d);
window.frames[i.id].name = i.id;
addListener(i, 'load', function() {
i.contentWindow.loaded();
i.parentNode.removeChild(i);
});
f.submit();
};
window.pushEvent = function(obj, event, handler) {
if (obj.addEventListener)
obj.addEventListener(event, handler, false);
else if (obj.attachEvent)
obj.attachEvent('on'+event, handler);
};
window.findPos = function(obj) { var curtop = 0; if (obj.offsetParent) { do { curtop += obj.offsetTop; } while (obj = obj.offsetParent); return [curtop]; } }
window.scrollDocTo = function(obj) { window.scroll(0,findPos(obj)); }
window.scrTo = function(id) { scrollDocTo(document.getElementById(id)); }
window.hidepreview = function() { document.getElementById('wrapcommentpreview').style.display='none'; }
window.addListener = function(obj, event, handler)
{
if (typeof(obj) == 'string')
obj = document.getElementById(obj);
if (!obj)
return;
if (obj.addEventListener)
obj.addEventListener(event, handler, false);
else if (obj.attachEvent)
obj.attachEvent('on'+event, handler);
};
window.removeListener = function(obj, event, handler)
{
if (typeof(obj) == 'string')
obj = document.getElementById(obj);
if (!obj)
return;
if (obj.addEventListener)
obj.removeEventListener(event, handler, false);
else if (obj.attachEvent)
obj.detachEvent('on'+event, handler);
};
window.eventTarget = function(ev)
{
if (!ev) var ev = window.event;
var t = ev.target;
if (!t) t = ev.srcElement;
if (t && t.nodeType == 3) t = t.parentNode;
return t;
};
window.getElementsByClassName = function(c, nodeName, parent)
{
if (typeof(parent) == 'string')
parent = document.getElementById(parent);
parent = parent||document;
if (nodeName)
nodeName = nodeName.toLowerCase();
if (parent.getElementsByClassName)
{
var l = parent.getElementsByClassName(c);
if (!nodeName)
return l;
else
{
var l1 = [];
for (var i = 0; i < l.length; i++)
if (l[i].nodeName.toLowerCase() == nodeName)
l1.push(l[i]);
return l1;
}
}
var s = [ parent ];
var l = [];
if (nodeName)
{
while (s.length)
{
if (hasClass(s[0], c) && s[0].nodeName.toLowerCase() == nodeName)
l.push(s[0]);
else
for (var i = 0; i < s[0].children.length; i++)
s.push(s[0].children[i]);
s.shift();
}
}
else
{
while (s.length)
{
if (hasClass(s[0], c))
l.push(s[0]);
else
for (var i = 0; i < s[0].children.length; i++)
s.push(s[0].children[i]);
s.shift();
}
}
return l;
};
/**
* addClass : add CSS class to an element
* returns (void)
* removeClass : remove CSS class from element
* returns (modified => true)
* hasClass : check if element has the specified CSS class
* returns (has class => true)
* toggleClass : add / remove CSS class if object doesn't have it / has it.
* returns (has class after toggle => true)
* FIXME all have jQuery alternatives
*
* @param anElement/obj The element to toggle the class on
* @param aClass/c The name of the CSS class to toggle.
*/
window.addClass = function(obj, c)
{
if (typeof(obj) == 'string')
obj = document.getElementById(obj);
if (obj)
obj.className = obj.className+' '+c;
};
window.removeClass = function(obj, c)
{
if (typeof(obj) == 'string')
obj = document.getElementById(obj);
if (!obj)
return false;
var l = obj.className.split(/\s+/);
var l1 = [];
for (var i = l.length-1; i >= 0; i--)
if (l[i] != c)
l1.push(l[i]);
obj.className = l1.length ? l1.join(' ') : '';
return l1.length != l.length;
};
window.hasClass = function(obj, c)
{
if (typeof(obj) == 'string')
obj = document.getElementById(obj);
var l = obj.className.split(/\s+/);
for (var i = l.length-1; i >= 0; i--)
if (l[i] == c)
return true;
return false;
};
window.toggleClass = function(anElement, aClass)
{
if (typeof(anElement) == 'string')
anElement = document.getElementById(anElement);
if (hasClass(anElement, aClass))
{
removeClass(anElement, aClass);
return false;
}
else
{
addClass(anElement, aClass);
return true;
}
};
window.scrollDocTo = function(obj) { window.scroll(0, findPos(obj)[1]); }
window.scrTo = function(id) { scrollDocTo(document.getElementById(id)); }
window.hidepreview = function()
{
document.getElementById('wrapcommentpreview').style.display = 'none';
};
window.showcommentpreview = function(textarea_id)
{
document.getElementById('wrapcommentpreview').style.display = '';
iframeajax('page.cgi?id=previewcomment.html', { 'comment': document.getElementById(textarea_id || 'comment_textarea').value });
scrTo('wrapcommentpreview');
document.getElementById('wrapcommentpreview').style.display = '';
iframeajax('page.cgi?id=previewcomment.html', { 'comment': document.getElementById(textarea_id || 'comment_textarea').value });
scrTo('wrapcommentpreview');
};
RegExp.escape = function(text) {
if (!arguments.callee.sRE) {
var specials = [
'/', '.', '*', '+', '?', '|',
'(', ')', '[', ']', '{', '}', '\\'
];
arguments.callee.sRE = new RegExp(
'(\\' + specials.join('|\\') + ')', 'g'
);
}
return text.replace(arguments.callee.sRE, '\\$1');
};
/* Parse time in hours:
"1,5" or "1:30" (HH:MM) = 1.5,
"1.5d" (days) = 12 */
function bzParseTime(time)
{
time = time+"";
time = time.replace(',','.');
if (m = time.match(/^\s*(-?)(\d+):(\d+)\s*$/))
{
for (var i = 2; i < 5; i++)
{
if (!m[i]) m[i] = 0;
else m[i] = parseInt(m[i]);
}
if (!m[1]) m[1] = '';
time = Math.floor(parseFloat(m[1] + (m[2] + m[3]/60))*100+0.5)/100;
}
else if (m = time.match(/^\s*(-?\d+(?:\.\d+)?)d\s*$/))
time = parseFloat(m[1])*8;
else
time = parseFloat(time);
return time;
};
/* Gets named cookie */
window.getCookie = function(name)
{
var matches = document.cookie.match(new RegExp(
"(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
));
return matches ? decodeURIComponent(matches[1]) : undefined;
};
/* Sets a new cookie name=value
props: {expires:, path:, domain:, secure:, httponly:} */
window.setCookie = function(name, value, props)
{
props = props || {};
var exp = props.expires;
if (typeof exp == "number" && exp)
{
var d = new Date();
d.setTime(d.getTime() + exp*1000);
exp = props.expires = d;
}
if (exp && exp.toUTCString)
props.expires = exp.toUTCString();
value = encodeURIComponent(value);
var updatedCookie = name + "=" + value;
for (var propName in props)
{
updatedCookie += "; " + propName;
var propValue = props[propName];
if (propValue !== true)
updatedCookie += "=" + propValue;
}
document.cookie = updatedCookie;
};
/* Removes named cookie */
window.deleteCookie = function(name)
{
setCookie(name, null, { expires: -1 });
};

18
js/yui/calendar.js vendored

File diff suppressed because one or more lines are too long

7
js/yui/cookie.js vendored
View File

@ -1,7 +0,0 @@
/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.6.0
*/
YAHOO.namespace("util");YAHOO.util.Cookie={_createCookieString:function(B,D,C,A){var F=YAHOO.lang;var E=encodeURIComponent(B)+"="+(C?encodeURIComponent(D):D);if(F.isObject(A)){if(A.expires instanceof Date){E+="; expires="+A.expires.toGMTString();}if(F.isString(A.path)&&A.path!=""){E+="; path="+A.path;}if(F.isString(A.domain)&&A.domain!=""){E+="; domain="+A.domain;}if(A.secure===true){E+="; secure";}}return E;},_createCookieHashString:function(B){var D=YAHOO.lang;if(!D.isObject(B)){throw new TypeError("Cookie._createCookieHashString(): Argument must be an object.");}var C=new Array();for(var A in B){if(D.hasOwnProperty(B,A)&&!D.isFunction(B[A])&&!D.isUndefined(B[A])){C.push(encodeURIComponent(A)+"="+encodeURIComponent(String(B[A])));}}return C.join("&");},_parseCookieHash:function(E){var D=E.split("&"),F=null,C=new Object();if(E.length>0){for(var B=0,A=D.length;B<A;B++){F=D[B].split("=");C[decodeURIComponent(F[0])]=decodeURIComponent(F[1]);}}return C;},_parseCookieString:function(I,A){var J=new Object();if(YAHOO.lang.isString(I)&&I.length>0){var B=(A===false?function(K){return K;}:decodeURIComponent);if(/[^=]+=[^=;]?(?:; [^=]+=[^=]?)?/.test(I)){var G=I.split(/;\s/g);var H=null;var C=null;var E=null;for(var D=0,F=G.length;D<F;D++){E=G[D].match(/([^=]+)=/i);if(E instanceof Array){H=decodeURIComponent(E[1]);C=B(G[D].substring(E[1].length+1));}else{H=decodeURIComponent(G[D]);C=H;}J[H]=C;}}}return J;},get:function(A,B){var D=YAHOO.lang;var C=this._parseCookieString(document.cookie);if(!D.isString(A)||A===""){throw new TypeError("Cookie.get(): Cookie name must be a non-empty string.");}if(D.isUndefined(C[A])){return null;}if(!D.isFunction(B)){return C[A];}else{return B(C[A]);}},getSub:function(A,C,B){var E=YAHOO.lang;var D=this.getSubs(A);if(D!==null){if(!E.isString(C)||C===""){throw new TypeError("Cookie.getSub(): Subcookie name must be a non-empty string.");}if(E.isUndefined(D[C])){return null;}if(!E.isFunction(B)){return D[C];}else{return B(D[C]);}}else{return null;}},getSubs:function(A){if(!YAHOO.lang.isString(A)||A===""){throw new TypeError("Cookie.getSubs(): Cookie name must be a non-empty string.");}var B=this._parseCookieString(document.cookie,false);if(YAHOO.lang.isString(B[A])){return this._parseCookieHash(B[A]);}return null;},remove:function(B,A){if(!YAHOO.lang.isString(B)||B===""){throw new TypeError("Cookie.remove(): Cookie name must be a non-empty string.");}A=A||{};A.expires=new Date(0);return this.set(B,"",A);},removeSub:function(B,D,A){if(!YAHOO.lang.isString(B)||B===""){throw new TypeError("Cookie.removeSub(): Cookie name must be a non-empty string.");}if(!YAHOO.lang.isString(D)||D===""){throw new TypeError("Cookie.removeSub(): Subcookie name must be a non-empty string.");}var C=this.getSubs(B);if(YAHOO.lang.isObject(C)&&YAHOO.lang.hasOwnProperty(C,D)){delete C[D];return this.setSubs(B,C,A);}else{return"";}},set:function(B,C,A){var E=YAHOO.lang;if(!E.isString(B)){throw new TypeError("Cookie.set(): Cookie name must be a string.");}if(E.isUndefined(C)){throw new TypeError("Cookie.set(): Value cannot be undefined.");}var D=this._createCookieString(B,C,true,A);document.cookie=D;return D;},setSub:function(B,D,C,A){var F=YAHOO.lang;if(!F.isString(B)||B===""){throw new TypeError("Cookie.setSub(): Cookie name must be a non-empty string.");}if(!F.isString(D)||D===""){throw new TypeError("Cookie.setSub(): Subcookie name must be a non-empty string.");}if(F.isUndefined(C)){throw new TypeError("Cookie.setSub(): Subcookie value cannot be undefined.");}var E=this.getSubs(B);if(!F.isObject(E)){E=new Object();}E[D]=C;return this.setSubs(B,E,A);},setSubs:function(B,C,A){var E=YAHOO.lang;if(!E.isString(B)){throw new TypeError("Cookie.setSubs(): Cookie name must be a string.");}if(!E.isObject(C)){throw new TypeError("Cookie.setSubs(): Cookie value must be an object.");}var D=this._createCookieString(B,this._createCookieHashString(C),false,A);document.cookie=D;return D;}};YAHOO.register("cookie",YAHOO.util.Cookie,{version:"2.6.0",build:"1321"});

File diff suppressed because one or more lines are too long

View File

@ -300,8 +300,8 @@ $vars->{sentmail} = \@all_mail_results;
if (Bugzilla->usage_mode != USAGE_MODE_EMAIL)
{
my $title = template_var('terms')->{Bug}.' '.$bug->id.' Submitted '.$bug->short_desc;
my $header = template_var('terms')->{Bug}.' '.$bug->id.' Submitted';
my $title = Bugzilla->messages->{terms}->{Bug}.' '.$bug->id.' Submitted '.$bug->short_desc;
my $header = Bugzilla->messages->{terms}->{Bug}.' '.$bug->id.' Submitted';
my $ses = {
sent => \@all_mail_results,
title => $title,

View File

@ -719,11 +719,11 @@ elsif (($action eq 'next_bug' or $action eq 'same_bug') && ($bug = $vars->{bug})
my $title;
if (scalar(@bug_objects) == 1)
{
$title = template_var('terms')->{Bug} . ' ' . $bug_objects[0]->id . ' processed';
$title = Bugzilla->messages->{terms}->{Bug} . ' ' . $bug_objects[0]->id . ' processed';
}
else
{
$title = template_var('terms')->{Bugs} . ' processed';
$title = Bugzilla->messages->{terms}->{Bugs} . ' processed';
}
$send_attrs->{nextbug} = $action eq 'next_bug' ? 1 : 0;
my $ses = {

395
query.cgi
View File

@ -42,10 +42,11 @@ use Bugzilla::Field;
use Bugzilla::Install::Util qw(vers_cmp);
my $cgi = Bugzilla->cgi;
# Copy hash and throw away tied reference returned by Vars()
my $params = { %{ $cgi->Vars } };
my $dbh = Bugzilla->dbh;
my $template = Bugzilla->template;
my $vars = {};
my $buffer = $cgi->query_string();
my $user = Bugzilla->login();
my $userid = $user->id;
@ -53,21 +54,26 @@ my $userid = $user->id;
# Backwards compatibility hack -- if there are any of the old QUERY_*
# cookies around, and we are logged in, then move them into the database
# and nuke the cookie. This is required for Bugzilla 2.8 and earlier.
if ($userid) {
if ($userid)
{
my @oldquerycookies;
foreach my $i ($cgi->cookie()) {
if ($i =~ /^QUERY_(.*)$/) {
push(@oldquerycookies, [$1, $i, $cgi->cookie($i)]);
push @oldquerycookies, [$1, $i, $cgi->cookie($i)];
}
}
if (defined $cgi->cookie('DEFAULTQUERY')) {
push(@oldquerycookies, [DEFAULT_QUERY_NAME, 'DEFAULTQUERY',
$cgi->cookie('DEFAULTQUERY')]);
if (defined $cgi->cookie('DEFAULTQUERY'))
{
push @oldquerycookies, [DEFAULT_QUERY_NAME, 'DEFAULTQUERY',
$cgi->cookie('DEFAULTQUERY')];
}
if (@oldquerycookies) {
foreach my $ref (@oldquerycookies) {
if (@oldquerycookies)
{
foreach my $ref (@oldquerycookies)
{
my ($name, $cookiename, $value) = (@$ref);
if ($value) {
if ($value)
{
# If the query name contains invalid characters, don't import.
$name =~ /[<>&]/ && next;
trick_taint($name);
@ -75,11 +81,15 @@ if ($userid) {
my $query = $dbh->selectrow_array(
"SELECT query FROM namedqueries " .
"WHERE userid = ? AND name = ?",
undef, ($userid, $name));
if (!$query) {
$dbh->do("INSERT INTO namedqueries " .
"(userid, name, query) VALUES " .
"(?, ?, ?)", undef, ($userid, $name, $value));
undef, $userid, $name
);
if (!$query)
{
$dbh->do(
"INSERT INTO namedqueries " .
"(userid, name, query) VALUES (?, ?, ?)",
undef, $userid, $name, $value
);
}
$dbh->bz_commit_transaction();
}
@ -88,209 +98,168 @@ if ($userid) {
}
}
if ($cgi->param('nukedefaultquery')) {
if ($userid) {
$dbh->do("DELETE FROM namedqueries" .
" WHERE userid = ? AND name = ?",
undef, ($userid, DEFAULT_QUERY_NAME));
}
$buffer = "";
if ($params->{nukedefaultquery} && $userid)
{
$dbh->do(
"DELETE FROM namedqueries WHERE userid = ? AND name = ?",
undef, $userid, DEFAULT_QUERY_NAME
);
}
# We are done with changes committed to the DB.
$dbh = Bugzilla->switch_to_shadow_db;
my $userdefaultquery;
if ($userid) {
$userdefaultquery = $dbh->selectrow_array(
"SELECT query FROM namedqueries " .
"WHERE userid = ? AND name = ?",
undef, ($userid, DEFAULT_QUERY_NAME));
if ($userid)
{
($userdefaultquery) = $dbh->selectrow_array(
"SELECT query FROM namedqueries WHERE userid = ? AND name = ?",
undef, $userid, DEFAULT_QUERY_NAME
);
}
local our %default;
my $default = {};
# We pass the defaults as a hash of references to arrays. For those
# Items which are single-valued, the template should only reference [0]
# and ignore any multiple values.
sub PrefillForm {
my ($buf) = (@_);
my $cgi = Bugzilla->cgi;
$buf = new Bugzilla::CGI($buf);
my $foundone = 0;
# Nothing must be undef, otherwise the template complains.
my @list = qw(
bug_status resolution assigned_to
rep_platform priority bug_severity
classification product reporter op_sys
component version chfield chfieldfrom
chfieldto chfieldvalue target_milestone
email emailtype emailreporter
emailassigned_to emailcc emailqa_contact
emaillongdesc content
changedin votes short_desc short_desc_type
longdesc longdesc_type bug_file_loc
bug_file_loc_type status_whiteboard
status_whiteboard_type bug_id
bug_id_type keywords keywords_type
deadlinefrom deadlineto
x_axis_field y_axis_field z_axis_field
chart_format cumulate x_labels_vertical
category subcategory name newcategory
newsubcategory public frequency
);
# Nothing must be undef, otherwise the template complains.
my @list = ("bug_status", "resolution", "assigned_to",
"rep_platform", "priority", "bug_severity",
"classification", "product", "reporter", "op_sys",
"component", "version", "chfield", "chfieldfrom",
"chfieldto", "chfieldvalue", "target_milestone",
"email", "emailtype", "emailreporter",
"emailassigned_to", "emailcc", "emailqa_contact",
"emaillongdesc", "content",
"changedin", "votes", "short_desc", "short_desc_type",
"longdesc", "longdesc_type", "bug_file_loc",
"bug_file_loc_type", "status_whiteboard",
"status_whiteboard_type", "bug_id",
"bug_id_type", "keywords", "keywords_type",
"deadlinefrom", "deadlineto",
"x_axis_field", "y_axis_field", "z_axis_field",
"chart_format", "cumulate", "x_labels_vertical",
"category", "subcategory", "name", "newcategory",
"newsubcategory", "public", "frequency");
# These fields can also have default values (when used in reports).
# CustIS Bug 58300 - Add custom field to search filters
for my $field (Bugzilla->active_custom_fields)
{
push @list, $field->name;
push @list, $field->name . '_type';
}
foreach my $name (@list) {
$default{$name} = [];
}
# we won't prefill the boolean chart data from this query if
# there are any being submitted via params
my $prefillcharts = (grep(/^field-/, $cgi->param)) ? 0 : 1;
# Iterate over the URL parameters
foreach my $name ($buf->param()) {
my @values = $buf->param($name);
# If the name begins with the string 'field', 'type', 'value', or
# 'negate', then it is part of the boolean charts. Because
# these are built different than the rest of the form, we need
# to store these as parameters. We also need to indicate that
# we found something so the default query isn't added in if
# all we have are boolean chart items.
if ($name =~ m/^(?:field|type|value|negate)/) {
$cgi->param(-name => $name, -value => $values[0]) if ($prefillcharts);
$foundone = 1;
}
# If the name ends in a number (which it does for the fields which
# are part of the email searching), we use the array
# positions to show the defaults for that number field.
elsif ($name =~ m/^(.+)(\d)$/ && defined($default{$1})) {
$foundone = 1;
$default{$1}->[$2] = $values[0];
}
elsif (exists $default{$name}) {
$foundone = 1;
push (@{$default{$name}}, @values);
}
}
return $foundone;
# These fields can also have default values (when used in reports).
# CustIS Bug 58300 - Add custom field to search filters
for my $field (Bugzilla->active_custom_fields)
{
push @list, $field->name;
push @list, $field->name . '_type';
}
if (!PrefillForm($buffer)) {
# Ah-hah, there was no form stuff specified. Do it again with the
foreach my $name (@list)
{
$default->{$name} = [];
}
if ($params->{nukedefaultquery})
{
# Don't prefill form
}
elsif (!PrefillForm($params, $default))
{
# Ah-hah, there was no form stuff specified. Do it again with the
# default query.
if ($userdefaultquery) {
PrefillForm($userdefaultquery);
} else {
PrefillForm(Bugzilla->params->{"defaultquery"});
}
my $buf = new Bugzilla::CGI($userdefaultquery || Bugzilla->params->{defaultquery});
PrefillForm({ %{ $buf->Vars } }, $default);
}
if (!scalar(@{$default{'chfieldto'}}) || $default{'chfieldto'}->[0] eq "") {
$default{'chfieldto'} = ["Now"];
if (!@{$default->{chfieldto}} || $default->{chfieldto}->[0] eq '')
{
$default->{chfieldto} = [ 'Now' ];
}
# "where one or more of the following changed:"
$vars->{chfield} = [ map { $_->name } @{ Bugzilla::Search->CHANGEDFROMTO_FIELDS } ];
# Boolean charts
my $opdescs = Bugzilla->messages->{operator_descs};
$vars->{chart_types} = Bugzilla::Search->CHART_OPERATORS_ORDER;
$vars->{text_types} = Bugzilla::Search->TEXT_OPERATORS_ORDER;
# Fields for boolean charts
$vars->{fields} = [
$vars->{chart_fields} = [
map { { name => $_->{id}, title => $_->{title} } }
sort { $a->{title} cmp $b->{title} }
grep { !$_->{nocharts} }
values %{ Bugzilla::Search->COLUMNS }
];
# "where one or more of the following changed:"
$vars->{chfield} = [ map { $_->name } @{ Bugzilla::Search->CHANGEDFROMTO_FIELDS } ];
# Another hack...
unshift @{$vars->{fields}}, { name => "noop", description => "---" };
unshift @{$vars->{chart_fields}}, { id => 'noop', name => '---' };
# If we're not in the time-tracking group, exclude time-tracking fields.
if (!Bugzilla->user->is_timetracker) {
foreach my $tt_field (TIMETRACKING_FIELDS) {
@{$vars->{fields}} = grep($_->{name} ne $tt_field, @{$vars->{fields}});
@{$vars->{chart_fields}} = grep($_->{name} ne $tt_field, @{$vars->{chart_fields}});
}
}
# Boolean charts
# Creating new charts - if the cmd-add value is there, we define the field
# value so the code sees it and creates the chart. It will attempt to select
# "xyzzy" as the default, and fail. This is the correct behaviour.
foreach my $cmd (grep(/^cmd-/, $cgi->param)) {
if ($cmd =~ /^cmd-add(\d+)-(\d+)-(\d+)$/) {
$cgi->param(-name => "field$1-$2-$3", -value => "xyzzy");
}
}
if (!$cgi->param('field0-0-0')) {
$cgi->param(-name => 'field0-0-0', -value => "xyzzy");
}
# Create data structure of boolean chart info. It's an array of arrays of
# arrays - with the inner arrays having three members - field, type and
# value.
# Parse boolean charts from the form hash
my @charts;
for (my $chart = 0; $cgi->param("field$chart-0-0"); $chart++) {
my @rows;
for (my $row = 0; $cgi->param("field$chart-$row-0"); $row++) {
my @cols;
for (my $col = 0; $cgi->param("field$chart-$row-$col"); $col++) {
my $value = $cgi->param("value$chart-$row-$col");
if (!defined($value)) {
$value = '';
}
push(@cols, { field => $cgi->param("field$chart-$row-$col"),
type => $cgi->param("type$chart-$row-$col") || 'noop',
value => $value });
}
push(@rows, \@cols);
for (keys %$params)
{
if (/^(field|type|value)(\d+)-(\d+)-(\d+)$/so)
{
$charts[$2]{rows}[$3][$4]{$1} = $params->{$_};
}
elsif (/^negate(\d+)$/so)
{
$charts[$2]{negate} = $params->{$_};
}
push(@charts, {'rows' => \@rows, 'negate' => scalar($cgi->param("negate$chart")) });
}
$default{'charts'} = \@charts;
# Remove empty charts
for (@charts)
{
@$_ = grep { $_->{field} && $_->{field} ne 'noop' && $_->{field} ne '---' } @$_ for @{$_->{rows}};
@{$_->{rows}} = grep { @$_ } @{$_->{rows}};
}
@charts = grep { @{$_->{rows}} } @charts;
# Add one chart, if we've removed all of them
@charts = ( { rows => [ [ { field => 'noop' } ] ] } ) unless @charts;
$default->{charts} = \@charts;
# Named queries
if ($userid) {
$vars->{'namedqueries'} = $dbh->selectcol_arrayref(
"SELECT name FROM namedqueries " .
"WHERE userid = ? AND name != ? " .
"ORDER BY name",
undef, ($userid, DEFAULT_QUERY_NAME));
if ($userid)
{
$vars->{namedqueries} = $dbh->selectcol_arrayref(
"SELECT name FROM namedqueries " .
"WHERE userid = ? AND name != ? " .
"ORDER BY name",
undef, $userid, DEFAULT_QUERY_NAME
);
}
# Sort order
my $deforder;
my @orders = ('Bug Number', 'Importance', 'Assignee', 'Last Changed', 'relevance');
if ($cgi->cookie('LASTORDER')) {
if ($cgi->cookie('LASTORDER'))
{
$deforder = "Reuse same sort as last time";
unshift(@orders, $deforder);
}
if ($cgi->param('order'))
if ($params->{order} && !grep { $_ eq $params->{order} } @orders)
{
$deforder = $cgi->param('order');
if (lsearch(\@orders, $deforder) < 0)
{
unshift @orders, $deforder;
}
unshift @orders, $params->{order};
}
$vars->{'userdefaultquery'} = $userdefaultquery;
$vars->{'orders'} = \@orders;
$default{'order'} = [$deforder || 'Importance'];
$vars->{userdefaultquery} = $userdefaultquery;
$vars->{orders} = \@orders;
$default->{order} = [$deforder || 'Importance'];
if (($cgi->param('query_format') || $cgi->param('format') || "")
eq "create-series") {
if (($params->{query_format} || $params->{format} || "") eq "create-series")
{
require Bugzilla::Chart;
$vars->{'category'} = Bugzilla::Chart::getVisibleSeries();
$vars->{category} = Bugzilla::Chart::getVisibleSeries();
}
# CustIS Bug 58300 - Add custom fields to search filters
@ -306,47 +275,97 @@ if (Bugzilla->params->{usestatuswhiteboard})
push @{$vars->{freetext_fields}},
Bugzilla->active_custom_fields({ type => [ FIELD_TYPE_TEXTAREA, FIELD_TYPE_FREETEXT ] });
if ($cgi->param('format') && $cgi->param('format') =~ /^report-(table|graph)$/) {
if ($params->{format} && $params->{format} =~ /^report-(table|graph)$/)
{
# Get legal custom fields for tabular and graphical reports.
my @custom_fields_for_reports = Bugzilla->active_custom_fields({ type => FIELD_TYPE_SINGLE_SELECT });
$vars->{'custom_fields'} = \@custom_fields_for_reports;
$vars->{custom_fields} = \@custom_fields_for_reports;
}
$vars->{'known_name'} = $cgi->param('known_name');
$vars->{'columnlist'} = $cgi->param('columnlist');
($vars->{known_name}) = list $params->{known_name};
$vars->{columnlist} = $params->{columnlist};
# Add in the defaults.
$vars->{'default'} = \%default;
$vars->{default} = $default;
$vars->{'format'} = $cgi->param('format');
$vars->{'query_format'} = $cgi->param('query_format');
$vars->{format} = $params->{format};
$vars->{query_format} = $params->{query_format};
# Set default page to "specific" if none provided
if (!($cgi->param('query_format') || $cgi->param('format'))) {
if (defined $cgi->cookie('DEFAULTFORMAT')) {
$vars->{'format'} = $cgi->cookie('DEFAULTFORMAT');
} else {
$vars->{'format'} = 'specific';
# Set default page to "advanced" if none provided
if (!$params->{query_format} && !$params->{format})
{
if (defined $cgi->cookie('DEFAULTFORMAT'))
{
$params->{format} = $cgi->cookie('DEFAULTFORMAT');
}
else
{
$params->{format} = 'advanced';
}
}
# Set cookie to current format as default, but only if the format
# one that we should remember.
if (defined($vars->{'format'}) && IsValidQueryType($vars->{'format'})) {
$cgi->send_cookie(-name => 'DEFAULTFORMAT',
-value => $vars->{'format'},
-expires => "Fri, 01-Jan-2038 00:00:00 GMT");
if (defined $vars->{format} && IsValidQueryType($vars->{format}))
{
$cgi->send_cookie(
-name => 'DEFAULTFORMAT',
-value => $vars->{format},
-expires => "Fri, 01-Jan-2038 00:00:00 GMT"
);
}
# Generate and return the UI (HTML page) from the appropriate template.
# If we submit back to ourselves (for e.g. boolean charts), we need to
# preserve format information; hence query_format taking priority over
# format.
my $format = $template->get_format("search/search",
$vars->{'query_format'} || $vars->{'format'},
scalar $cgi->param('ctype'));
my $format = $template->get_format(
"search/search",
$params->{query_format} || $params->{format},
$params->{ctype}
);
$cgi->send_header($format->{'ctype'});
$cgi->send_header($format->{ctype});
$template->process($format->{template}, $vars)
|| ThrowTemplateError($template->error());
$template->process($format->{'template'}, $vars)
|| ThrowTemplateError($template->error());
# We pass the defaults as a hash of references to arrays. For those
# Items which are single-valued, the template should only reference [0]
# and ignore any multiple values.
# This is used only for prefilling full queries, not parts of them,
# so we always prefill boolean charts.
sub PrefillForm
{
my ($params, $default) = @_;
my $foundone = 0;
# Iterate over the URL parameters
foreach (keys %$params)
{
# If the name begins with the string 'field', 'type', 'value', or
# 'negate', then it is part of the boolean charts. Because
# these are built different than the rest of the form, we need
# to store these as parameters. We also need to indicate that
# we found something so the default query isn't added in if
# all we have are boolean chart items.
if (m/^(?:field|type|value|negate)/)
{
$foundone = 1;
}
# If the name ends in a number (which it does for the fields which
# are part of the email searching), we use the array
# positions to show the defaults for that number field.
elsif (m/^(.+)(\d)$/ && defined $default->{$1})
{
$foundone = 1;
$default->{$1}->[$2] = [ list $params->{$_} ]->[0];
}
elsif (exists $default->{$_})
{
$foundone = 1;
push @{$default->{$_}}, list $params->{$_};
}
}
return $foundone;
}

View File

@ -58,8 +58,7 @@ my $search = new Bugzilla::Search(
user => $user
);
my $sqlquery = $search->getSQL();
$sqlquery =~ s/ORDER\s+BY\s+`?bugs`?.`?bug_id`?//so;
my $sqlquery = $search->bugid_query;
my $tz = POSIX::strftime('%z', localtime);

View File

@ -8,7 +8,7 @@ use Bugzilla::Error;
my $cgi = Bugzilla->cgi;
my $user = Bugzilla->login;
my $args = $cgi->Vars;
my $args = { %{ $cgi->Vars } };
my $vars = {};
# Параметры по умолчанию:

Some files were not shown because too many files have changed in this diff Show More