Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
bugzilla
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
etersoft
bugzilla
Commits
4acb2424
You need to sign in or sign up before continuing.
Commit
4acb2424
authored
Jun 21, 2010
by
Max Kanat-Alexander
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bug 22353: Automatic duplicate bug detection on enter_bug.cgi
r=glob, a=mkanat
parent
601bda78
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
400 additions
and
79 deletions
+400
-79
.bzrignore
.bzrignore
+1
-0
Bug.pm
Bugzilla/Bug.pm
+115
-18
Constants.pm
Bugzilla/Constants.pm
+5
-0
DB.pm
Bugzilla/DB.pm
+5
-0
Mysql.pm
Bugzilla/DB/Mysql.pm
+2
-3
Oracle.pm
Bugzilla/DB/Oracle.pm
+2
-3
User.pm
Bugzilla/User.pm
+1
-1
Bug.pm
Bugzilla/WebService/Bug.pm
+31
-4
bug.js
js/bug.js
+117
-0
enter_bug.css
skins/standard/enter_bug.css
+65
-0
global.css
skins/standard/global.css
+0
-39
create.html.tmpl
template/en/default/bug/create/create.html.tmpl
+41
-5
header.html.tmpl
template/en/default/global/header.html.tmpl
+15
-6
No files found.
.bzrignore
View file @
4acb2424
...
...
@@ -19,6 +19,7 @@
/skins/contrib/Dusk/dependency-tree.css
/skins/contrib/Dusk/duplicates.css
/skins/contrib/Dusk/editusers.css
/skins/contrib/Dusk/enter_bug.css
/skins/contrib/Dusk/help.css
/skins/contrib/Dusk/panel.css
/skins/contrib/Dusk/page.css
...
...
Bugzilla/Bug.pm
View file @
4acb2424
...
...
@@ -49,7 +49,7 @@ use Bugzilla::Group;
use
Bugzilla::
Status
;
use
Bugzilla::
Comment
;
use
List::
MoreUtils
qw(firstidx)
;
use
List::
MoreUtils
qw(firstidx
uniq
)
;
use
List::
Util
qw(min first)
;
use
Storable
qw(dclone)
;
use
URI
;
...
...
@@ -446,6 +446,87 @@ sub match {
return
$class
->
SUPER::
match
(
@_
);
}
sub
possible_duplicates
{
my
(
$class
,
$params
)
=
@_
;
my
$short_desc
=
$params
->
{
summary
};
my
$products
=
$params
->
{
products
}
||
[]
;
my
$limit
=
$params
->
{
limit
}
||
MAX_POSSIBLE_DUPLICATES
;
$limit
=
MAX_POSSIBLE_DUPLICATES
if
$limit
>
MAX_POSSIBLE_DUPLICATES
;
$products
=
[
$products
]
if
!
ref
(
$products
)
eq
'ARRAY'
;
my
$orig_limit
=
$limit
;
detaint_natural
(
$limit
)
||
ThrowCodeError
(
'param_must_be_numeric'
,
{
function
=>
'possible_duplicates'
,
param
=>
$orig_limit
});
my
$dbh
=
Bugzilla
->
dbh
;
my
$user
=
Bugzilla
->
user
;
my
@words
=
split
(
/[\b\s]+/
,
$short_desc
||
''
);
# Exclude punctuation from the array.
@words
=
map
{
/(\w+)/
;
$1
}
@words
;
# And make sure that each word is longer than 2 characters.
@words
=
grep
{
defined
$_
and
length
(
$_
)
>
2
}
@words
;
return
[]
if
!
@words
;
my
(
$where_sql
,
$relevance_sql
);
if
(
$dbh
->
FULLTEXT_OR
)
{
my
$joined_terms
=
join
(
$dbh
->
FULLTEXT_OR
,
@words
);
(
$where_sql
,
$relevance_sql
)
=
$dbh
->
sql_fulltext_search
(
'bugs_fulltext.short_desc'
,
$joined_terms
,
1
);
$relevance_sql
||=
$where_sql
;
}
else
{
my
(
@where
,
@relevance
);
my
$count
=
0
;
foreach
my
$word
(
@words
)
{
$count
++
;
my
(
$term
,
$rel_term
)
=
$dbh
->
sql_fulltext_search
(
'bugs_fulltext.short_desc'
,
$word
,
$count
);
push
(
@where
,
$term
);
push
(
@relevance
,
$rel_term
||
$term
);
}
$where_sql
=
join
(
' OR '
,
@where
);
$relevance_sql
=
join
(
' + '
,
@relevance
);
}
my
$product_ids
=
join
(
','
,
map
{
$_
->
id
}
@$products
);
my
$product_sql
=
$product_ids
?
"AND product_id IN ($product_ids)"
:
""
;
# Because we collapse duplicates, we want to get slightly more bugs
# than were actually asked for.
my
$sql_limit
=
$limit
+
5
;
my
$possible_dupes
=
$dbh
->
selectall_arrayref
(
"SELECT bugs.bug_id AS bug_id, bugs.resolution AS resolution,
($relevance_sql) AS relevance
FROM bugs
INNER JOIN bugs_fulltext ON bugs.bug_id = bugs_fulltext.bug_id
WHERE ($where_sql) $product_sql
ORDER BY relevance DESC, bug_id DESC
LIMIT $sql_limit"
,
{
Slice
=>
{}});
my
@actual_dupe_ids
;
# Resolve duplicates into their ultimate target duplicates.
foreach
my
$bug
(
@$possible_dupes
)
{
my
$push_id
=
$bug
->
{
bug_id
};
if
(
$bug
->
{
resolution
}
&&
$bug
->
{
resolution
}
eq
'DUPLICATE'
)
{
$push_id
=
_resolve_ultimate_dup_id
(
$bug
->
{
bug_id
});
}
push
(
@actual_dupe_ids
,
$push_id
);
}
@actual_dupe_ids
=
uniq
@actual_dupe_ids
;
if
(
scalar
@actual_dupe_ids
>
$limit
)
{
@actual_dupe_ids
=
@actual_dupe_ids
[
0
..
(
$limit
-
1
)];
}
my
$visible
=
$user
->
visible_bugs
(
\
@actual_dupe_ids
);
return
$class
->
new_from_list
(
$visible
);
}
# Docs for create() (there's no POD in this file yet, but we very
# much need this documented right now):
#
...
...
@@ -1426,23 +1507,7 @@ sub _check_dup_id {
# Make sure a loop isn't created when marking this bug
# as duplicate.
my
%
dupes
;
my
$this_dup
=
$dupe_of
;
my
$sth
=
$dbh
->
prepare
(
'SELECT dupe_of FROM duplicates WHERE dupe = ?'
);
while
(
$this_dup
)
{
if
(
$this_dup
==
$self
->
id
)
{
ThrowUserError
(
'dupe_loop_detected'
,
{
bug_id
=>
$self
->
id
,
dupe_of
=>
$dupe_of
});
}
# If $dupes{$this_dup} is already set to 1, then a loop
# already exists which does not involve this bug.
# As the user is not responsible for this loop, do not
# prevent him from marking this bug as a duplicate.
last
if
exists
$dupes
{
$this_dup
};
$dupes
{
$this_dup
}
=
1
;
$this_dup
=
$dbh
->
selectrow_array
(
$sth
,
undef
,
$this_dup
);
}
_resolve_ultimate_dup_id
(
$self
->
id
,
$dupe_of
,
1
);
my
$cur_dup
=
$self
->
dup_id
||
0
;
if
(
$cur_dup
!=
$dupe_of
&&
Bugzilla
->
params
->
{
'commentonduplicate'
}
...
...
@@ -2843,6 +2908,38 @@ sub dup_id {
return
$self
->
{
'dup_id'
};
}
sub
_resolve_ultimate_dup_id
{
my
(
$bug_id
,
$dupe_of
,
$loops_are_an_error
)
=
@_
;
my
$dbh
=
Bugzilla
->
dbh
;
my
$sth
=
$dbh
->
prepare
(
'SELECT dupe_of FROM duplicates WHERE dupe = ?'
);
my
$this_dup
=
$dupe_of
||
$dbh
->
selectrow_array
(
$sth
,
undef
,
$bug_id
);
my
$last_dup
=
$bug_id
;
my
%
dupes
;
while
(
$this_dup
)
{
if
(
$this_dup
==
$bug_id
)
{
if
(
$loops_are_an_error
)
{
ThrowUserError
(
'dupe_loop_detected'
,
{
bug_id
=>
$bug_id
,
dupe_of
=>
$dupe_of
});
}
else
{
return
$last_dup
;
}
}
# If $dupes{$this_dup} is already set to 1, then a loop
# already exists which does not involve this bug.
# As the user is not responsible for this loop, do not
# prevent him from marking this bug as a duplicate.
return
$last_dup
if
exists
$dupes
{
$this_dup
};
$dupes
{
$this_dup
}
=
1
;
$last_dup
=
$this_dup
;
$this_dup
=
$dbh
->
selectrow_array
(
$sth
,
undef
,
$this_dup
);
}
return
$last_dup
;
}
sub
actual_time
{
my
(
$self
)
=
@_
;
return
$self
->
{
'actual_time'
}
if
exists
$self
->
{
'actual_time'
};
...
...
Bugzilla/Constants.pm
View file @
4acb2424
...
...
@@ -175,6 +175,7 @@ use File::Basename;
MAX_FIELD_VALUE_SIZE
MAX_FREETEXT_LENGTH
MAX_BUG_URL_LENGTH
MAX_POSSIBLE_DUPLICATES
PASSWORD_DIGEST_ALGORITHM
PASSWORD_SALT_LENGTH
...
...
@@ -527,6 +528,10 @@ use constant MAX_FREETEXT_LENGTH => 255;
# The longest a bug URL in a BUG_URLS field can be.
use
constant
MAX_BUG_URL_LENGTH
=>
255
;
# The largest number of possible duplicates that Bug::possible_duplicates
# will return.
use
constant
MAX_POSSIBLE_DUPLICATES
=>
25
;
# This is the name of the algorithm used to hash passwords before storing
# them in the database. This can be any string that is valid to pass to
# Perl's "Digest" module. Note that if you change this, it won't take
...
...
Bugzilla/DB.pm
View file @
4acb2424
...
...
@@ -73,6 +73,11 @@ use constant ENUM_DEFAULTS => {
resolution
=>
[
""
,
"FIXED"
,
"INVALID"
,
"WONTFIX"
,
"DUPLICATE"
,
"WORKSFORME"
],
};
# The character that means "OR" in a boolean fulltext search. If empty,
# the database doesn't support OR searches in fulltext searches.
# Used by Bugzilla::Bug::possible_duplicates.
use
constant
FULLTEXT_OR
=>
''
;
#####################################################################
# Connection Methods
#####################################################################
...
...
Bugzilla/DB/Mysql.pm
View file @
4acb2424
...
...
@@ -40,8 +40,8 @@ For interface details see L<Bugzilla::DB> and L<DBI>.
=cut
package
Bugzilla::DB::
Mysql
;
use
strict
;
use
base
qw(Bugzilla::DB)
;
use
Bugzilla::
Constants
;
use
Bugzilla::Install::
Util
qw(install_string)
;
...
...
@@ -57,8 +57,7 @@ use Text::ParseWords;
# MAX_COMMENT_LENGTH is big.
use
constant
MAX_COMMENTS
=>
50
;
# This module extends the DB interface via inheritance
use
base
qw(Bugzilla::DB)
;
use
constant
FULLTEXT_OR
=>
'|'
;
sub
new
{
my
(
$class
,
$params
)
=
@_
;
...
...
Bugzilla/DB/Oracle.pm
View file @
4acb2424
...
...
@@ -35,16 +35,14 @@ For interface details see L<Bugzilla::DB> and L<DBI>.
=cut
package
Bugzilla::DB::
Oracle
;
use
strict
;
use
base
qw(Bugzilla::DB)
;
use
DBD::
Oracle
;
use
DBD::
Oracle
qw(:ora_types)
;
use
Bugzilla::
Constants
;
use
Bugzilla::
Error
;
use
Bugzilla::
Util
;
# This module extends the DB interface via inheritance
use
base
qw(Bugzilla::DB)
;
#####################################################################
# Constants
...
...
@@ -52,6 +50,7 @@ use base qw(Bugzilla::DB);
use
constant
EMPTY_STRING
=>
'__BZ_EMPTY_STR__'
;
use
constant
ISOLATION_LEVEL
=>
'READ COMMITTED'
;
use
constant
BLOB_TYPE
=>
{
ora_type
=>
ORA_BLOB
};
use
constant
FULLTEXT_OR
=>
' OR '
;
sub
new
{
my
(
$class
,
$params
)
=
@_
;
...
...
Bugzilla/User.pm
View file @
4acb2424
...
...
@@ -900,7 +900,7 @@ sub can_enter_product {
$product
&&
grep
(
$_
->
name
eq
$product
->
name
,
@
{
$self
->
get_enterable_products
});
return
1
if
$can_enter
;
return
$product
if
$can_enter
;
return
0
unless
$warn
==
THROW_ERROR
;
...
...
Bugzilla/WebService/Bug.pm
View file @
4acb2424
...
...
@@ -36,6 +36,7 @@ use Bugzilla::Util qw(trick_taint trim);
use
Bugzilla::
Version
;
use
Bugzilla::
Milestone
;
use
Bugzilla::
Status
;
use
Bugzilla::
Token
qw(issue_hash_token)
;
#############
# Constants #
...
...
@@ -322,7 +323,7 @@ sub get {
else
{
$bug
=
Bugzilla::
Bug
->
check
(
$bug_id
);
}
push
(
@bugs
,
$self
->
_bug_to_hash
(
$bug
));
push
(
@bugs
,
$self
->
_bug_to_hash
(
$bug
,
$params
));
}
return
{
bugs
=>
\
@bugs
,
faults
=>
\
@faults
};
...
...
@@ -421,7 +422,28 @@ sub search {
my
$bugs
=
Bugzilla::
Bug
->
match
(
$params
);
my
$visible
=
Bugzilla
->
user
->
visible_bugs
(
$bugs
);
my
@hashes
=
map
{
$self
->
_bug_to_hash
(
$_
)
}
@$visible
;
my
@hashes
=
map
{
$self
->
_bug_to_hash
(
$_
,
$params
)
}
@$visible
;
return
{
bugs
=>
\
@hashes
};
}
sub
possible_duplicates
{
my
(
$self
,
$params
)
=
validate
(
@_
,
'product'
);
my
$user
=
Bugzilla
->
user
;
# Undo the array-ification that validate() does, for "summary".
$params
->
{
summary
}
||
ThrowCodeError
(
'param_required'
,
{
function
=>
'Bug.possible_duplicates'
,
param
=>
'summary'
});
my
@products
;
foreach
my
$name
(
@
{
$params
->
{
'product'
}
||
[]
})
{
my
$object
=
$user
->
can_enter_product
(
$name
,
THROW_ERROR
);
push
(
@products
,
$object
);
}
my
$possible_dupes
=
Bugzilla::
Bug
->
possible_duplicates
(
{
summary
=>
$params
->
{
summary
},
products
=>
\
@products
,
limit
=>
$params
->
{
limit
}
});
my
@hashes
=
map
{
$self
->
_bug_to_hash
(
$_
,
$params
)
}
@$possible_dupes
;
return
{
bugs
=>
\
@hashes
};
}
...
...
@@ -617,7 +639,7 @@ sub attachments {
# A helper for get() and search().
sub
_bug_to_hash
{
my
(
$self
,
$bug
)
=
@_
;
my
(
$self
,
$bug
,
$filters
)
=
@_
;
# Timetracking fields are deleted if the user doesn't belong to
# the corresponding group.
...
...
@@ -646,6 +668,11 @@ sub _bug_to_hash {
$item
{
'component'
}
=
$self
->
type
(
'string'
,
$bug
->
component
);
$item
{
'dupe_of'
}
=
$self
->
type
(
'int'
,
$bug
->
dup_id
);
if
(
Bugzilla
->
user
->
id
)
{
my
$token
=
issue_hash_token
([
$bug
->
id
,
$bug
->
delta_ts
]);
$item
{
'update_token'
}
=
$self
->
type
(
'string'
,
$token
);
}
# if we do not delete this key, additional user info, including their
# real name, etc, will wind up in the 'internals' hashref
delete
$item
{
internals
}
->
{
assigned_to_obj
};
...
...
@@ -659,7 +686,7 @@ sub _bug_to_hash {
$item
{
'alias'
}
=
undef
;
}
return
\%
item
;
return
filter
$filters
,
\%
item
;
}
sub
_attachment_to_hash
{
...
...
js/bug.js
0 → 100644
View file @
4acb2424
/* 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 Everything Solved, Inc.
* Portions created by Everything Solved are Copyright (C) 2010 Everything
* Solved, Inc. All Rights Reserved.
*
* Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
*/
/* This library assumes that the needed YUI libraries have been loaded
already. */
YAHOO
.
bugzilla
.
dupTable
=
{
counter
:
0
,
dataSource
:
null
,
updateTable
:
function
(
dataTable
,
product_name
,
summary_field
)
{
if
(
summary_field
.
value
.
length
<
4
)
return
;
YAHOO
.
bugzilla
.
dupTable
.
counter
=
YAHOO
.
bugzilla
.
dupTable
.
counter
+
1
;
YAHOO
.
util
.
Connect
.
setDefaultPostHeader
(
'application/json'
,
true
);
var
json_object
=
{
version
:
"1.1"
,
method
:
"Bug.possible_duplicates"
,
id
:
YAHOO
.
bugzilla
.
dupTable
.
counter
,
params
:
{
product
:
product_name
,
summary
:
summary_field
.
value
,
limit
:
7
,
include_fields
:
[
"id"
,
"summary"
,
"status"
,
"resolution"
,
"update_token"
]
}
};
var
post_data
=
YAHOO
.
lang
.
JSON
.
stringify
(
json_object
);
var
callback
=
{
success
:
dataTable
.
onDataReturnInitializeTable
,
failure
:
dataTable
.
onDataReturnInitializeTable
,
scope
:
dataTable
,
argument
:
dataTable
.
getState
()
};
dataTable
.
showTableMessage
(
dataTable
.
get
(
"MSG_LOADING"
),
YAHOO
.
widget
.
DataTable
.
CLASS_LOADING
);
YAHOO
.
util
.
Dom
.
removeClass
(
'possible_duplicates_container'
,
'bz_default_hidden'
);
dataTable
.
getDataSource
().
sendRequest
(
post_data
,
callback
);
},
formatBugLink
:
function
(
el
,
oRecord
,
oColumn
,
oData
)
{
el
.
innerHTML
=
'<a href="show_bug.cgi?id='
+
oData
+
'">'
+
oData
+
'</a>'
;
},
formatStatus
:
function
(
el
,
oRecord
,
oColumn
,
oData
)
{
var
resolution
=
oRecord
.
getData
(
'resolution'
);
if
(
resolution
)
{
el
.
innerHTML
=
oData
+
' '
+
resolution
;
}
else
{
el
.
innerHTML
=
oData
;
}
},
formatCcButton
:
function
(
el
,
oRecord
,
oColumn
,
oData
)
{
var
url
=
'process_bug.cgi?id='
+
oRecord
.
getData
(
'id'
)
+
'&addselfcc=1&token='
+
escape
(
oData
);
var
button
=
document
.
createElement
(
'button'
);
button
.
setAttribute
(
'type'
,
'button'
);
button
.
innerHTML
=
YAHOO
.
bugzilla
.
dupTable
.
addCcMessage
;
button
.
onclick
=
function
()
{
window
.
location
=
url
;
return
false
;
};
el
.
appendChild
(
button
);
},
init_ds
:
function
()
{
var
new_ds
=
new
YAHOO
.
util
.
XHRDataSource
(
"jsonrpc.cgi"
);
new_ds
.
connTimeout
=
30000
;
new_ds
.
connMethodPost
=
true
;
new_ds
.
connXhrMode
=
"cancelStaleRequests"
;
new_ds
.
maxCacheEntries
=
3
;
new_ds
.
responseSchema
=
{
resultsList
:
"result.bugs"
,
metaFields
:
{
error
:
"error"
,
jsonRpcId
:
"id"
},
};
// DataSource can't understand a JSON-RPC error response, so
// we have to modify the result data if we get one.
new_ds
.
doBeforeParseData
=
function
(
oRequest
,
oFullResponse
,
oCallback
)
{
if
(
oFullResponse
.
error
)
{
oFullResponse
.
result
=
{};
oFullResponse
.
result
.
bugs
=
[];
if
(
console
)
{
console
.
log
(
"JSON-RPC error:"
,
oFullResponse
.
error
);
}
}
return
oFullResponse
;
}
this
.
dataSource
=
new_ds
;
},
init
:
function
(
data
)
{
if
(
this
.
dataSource
==
null
)
this
.
init_ds
();
data
.
options
.
initialLoad
=
false
;
var
dt
=
new
YAHOO
.
widget
.
DataTable
(
data
.
container
,
data
.
columns
,
this
.
dataSource
,
data
.
options
);
YAHOO
.
util
.
Event
.
on
(
data
.
summary_field
,
'blur'
,
function
(
e
)
{
YAHOO
.
bugzilla
.
dupTable
.
updateTable
(
dt
,
data
.
product_name
,
YAHOO
.
util
.
Event
.
getTarget
(
e
))
}
);
},
};
skins/standard/enter_bug.css
0 → 100644
View file @
4acb2424
/* 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): Byron Jones <bugzilla@glob.com.au>
* Christian Reis <kiko@async.com.br>
* Vitaly Harisov <vitaly@rathedg.com>
* Svetlana Harisova <light@rathedg.com>
* Marc Schumann <wurblzap@gmail.com>
* Pascal Held <paheld@gmail.com>
* Max Kanat-Alexander <mkanat@bugzilla.org>
*/
/* These are specified using the class instead of the id so that they
don't override the YUI CSS. */
.enter_bug_form
table
{
border-spacing
:
0
;
border-width
:
0
;
}
.enter_bug_form
td
,
.enter_bug_form
th
{
padding
:
.25em
;
}
.enter_bug_form
th
{
text-align
:
right
;
}
/* This makes the "component" column as small as possible (since it
* contains only fixed-width content) and the Reporter column
* as large as possible, which makes the form not jump around
* when the Component Description changes size. This works
* pretty well on all browsers except IE 8.
*/
#Create
#field_container_component
{
width
:
1px
;
}
#Create
#field_container_reporter
{
width
:
100%
;
}
#Create
.comment
{
vertical-align
:
top
;
overflow
:
auto
;
color
:
green
;
}
#Create
#comp_desc_container
td
{
padding
:
0
;
}
#Create
#comp_desc
{
height
:
11ex
;
}
#Create
#os_guess_note
{
padding-top
:
0
;
}
#Create
#os_guess_note
div
{
max-width
:
35em
;
}
/* The Possible Duplicates table on enter_bug. */
#possible_duplicates
th
{
text-align
:
center
;
background
:
none
;
border-collapse
:
collapse
;
}
/* Make the Add Me to CC button never wrap. */
#possible_duplicates
.yui-dt-col-update_token
{
white-space
:
nowrap
;
}
skins/standard/global.css
View file @
4acb2424
...
...
@@ -504,45 +504,6 @@ input.required, select.required, span.required_explanation {
list-style-type
:
none
;
}
/*************/
/* enter_bug */
/*************/
form
#Create
table
{
border-spacing
:
0
;
border-width
:
0
;
}
form
#Create
td
,
form
#Create
th
{
padding
:
.25em
;
}
form
#Create
th
{
text-align
:
right
;
}
/* This makes the "component" column as small as possible (since it
* contains only fixed-width content) and the Reporter column
* as large as possible, which makes the form not jump around
* when the Component Description changes size. This works
* pretty well on all browsers except IE 8.
*/
form
#Create
#field_container_component
{
width
:
1px
;
}
form
#Create
#field_container_reporter
{
width
:
100%
;
}
form
#Create
.comment
{
vertical-align
:
top
;
overflow
:
auto
;
color
:
green
;
}
form
#Create
#comp_desc_container
td
{
padding
:
0
;
}
form
#Create
#comp_desc
{
height
:
11ex
;
}
form
#Create
#os_guess_note
{
padding-top
:
0
;
}
form
#Create
#os_guess_note
div
{
max-width
:
35em
;
}
.image_button
{
background-repeat
:
no-repeat
;
background-position
:
center
center
;
...
...
template/en/default/bug/create/create.html.tmpl
View file @
4acb2424
...
...
@@ -30,10 +30,11 @@
[% PROCESS global/header.html.tmpl
title = title
yui = [ 'autocomplete', 'calendar' ]
style_urls = [ 'skins/standard/attachment.css' ]
yui = [ 'autocomplete', 'calendar', 'datatable' ]
style_urls = [ 'skins/standard/attachment.css',
'skins/standard/enter_bug.css' ]
javascript_urls = [ "js/attachment.js", "js/util.js",
"js/field.js", "js/TUI.js" ]
"js/field.js", "js/TUI.js"
, "js/bug.js"
]
onload = 'set_assign_to();'
%]
...
...
@@ -169,7 +170,7 @@ TUI_hide_default('expert_fields');
</script>
<form name="Create" id="Create" method="post" action="post_bug.cgi"
enctype="multipart/form-data">
class="enter_bug_form"
enctype="multipart/form-data">
<input type="hidden" name="product" value="[% product.name FILTER html %]">
<input type="hidden" name="token" value="[% token FILTER html %]">
...
...
@@ -508,13 +509,48 @@ TUI_hide_default('expert_fields');
<td colspan="3">
<input name="short_desc" size="70" value="[% short_desc FILTER html %]"
maxlength="255" spellcheck="true" aria-required="true"
class="required">
class="required"
id="short_desc"
>
</td>
</tr>
[% IF feature_enabled('jsonrpc') AND !cloned_bug_id %]
<tr id="possible_duplicates_container" class="bz_default_hidden">
<th>Possible<br>Duplicates:</th>
<td colspan="3">
<div id="possible_duplicates"></div>
<script type="text/javascript">
var dt_columns = [
{ key: "id", label: "[% field_descs.bug_id FILTER js %]",
formatter: YAHOO.bugzilla.dupTable.formatBugLink },
{ key: "summary",
label: "[% field_descs.short_desc FILTER js %]" },
{ key: "status",
label: "[% field_descs.bug_status FILTER js %]",
formatter: YAHOO.bugzilla.dupTable.formatStatus },
{ key: "update_token", label: '',
formatter: YAHOO.bugzilla.dupTable.formatCcButton }
];
YAHOO.bugzilla.dupTable.addCcMessage = "Add Me to the CC List";
YAHOO.bugzilla.dupTable.init({
container: 'possible_duplicates',
columns: dt_columns,
product_name: '[% product.name FILTER js %]',
summary_field: 'short_desc',
options: {
MSG_LOADING: 'Searching for possible duplicates...',
MSG_EMPTY: 'No possible duplicates found.',
SUMMARY: 'Possible Duplicates'
},
});
</script>
</td>
</tr>
[% END %]
<tr>
<th>Description:</th>
<td colspan="3">
[% defaultcontent = BLOCK %]
[% IF cloned_bug_id %]
+++ This [% terms.bug %] was initially created as a clone of [% terms.Bug %] #[% cloned_bug_id %] +++
...
...
template/en/default/global/header.html.tmpl
View file @
4acb2424
...
...
@@ -52,6 +52,7 @@
[% SET yui_css = {
autocomplete => 1,
calendar => 1,
datatable => 1,
} %]
[%# Note: This is simple dependency resolution--you can't have dependencies
...
...
@@ -60,6 +61,7 @@
#%]
[% SET yui_deps = {
autocomplete => ['json', 'connection', 'datasource'],
datatable => ['json', 'connection', 'datasource', 'element'],
} %]
...
...
@@ -99,7 +101,20 @@
[% END %]
[% style_urls.unshift('skins/standard/global.css') %]
[%# YUI dependency resolution %]
[%# We have to do this in a separate array, because modifying the
# existing array by unshift'ing dependencies confuses FOREACH.
#%]
[% SET yui_resolved = [] %]
[% FOREACH yui_name = yui %]
[% FOREACH yui_dep = yui_deps.${yui_name}.reverse %]
[% yui_resolved.push(yui_dep) IF NOT yui_resolved.contains(yui_dep) %]
[% END %]
[% yui_resolved.push(yui_name) IF NOT yui_resolved.contains(yui_name) %]
[% END %]
[% SET yui = yui_resolved %]
[%# YUI CSS %]
[% FOREACH yui_name = yui %]
[% IF yui_css.$yui_name %]
<link
rel=
"stylesheet"
type=
"text/css"
...
...
@@ -218,12 +233,6 @@
<script
src=
"js/yui/yahoo-dom-event/yahoo-dom-event.js"
type=
"text/javascript"
></script>
<script
src=
"js/yui/cookie/cookie-min.js"
type=
"text/javascript"
></script>
[%# Resolve YUI dependencies. Note that CSS was already done above. %]
[% FOREACH yui_name = yui %]
[% IF yui_deps.$yui_name %]
[% yui = yui_deps.${yui_name}.merge(yui) %]
[% END %]
[% END %]
[% FOREACH yui_name = yui %]
<script
type=
"text/javascript"
src=
"js/yui/[% yui_name FILTER html %]/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment