summaryrefslogtreecommitdiffstats
path: root/Bugzilla/Template.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla/Template.pm')
-rw-r--r--Bugzilla/Template.pm142
1 files changed, 77 insertions, 65 deletions
diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm
index 98be21d55..d2d6a7dd1 100644
--- a/Bugzilla/Template.pm
+++ b/Bugzilla/Template.pm
@@ -168,6 +168,10 @@ sub quoteUrls {
# until we require Perl 5.13.9 or newer.
no warnings 'utf8';
+ # If the comment is already wrapped, we should ignore newlines when
+ # looking for matching regexps. Else we should take them into account.
+ my $s = ($comment && $comment->already_wrapped) ? qr/\s/ : qr/\h/;
+
# However, note that adding the title (for buglinks) can affect things
# In particular, attachment matches go before bug titles, so that titles
# with 'attachment 1' don't double match.
@@ -234,7 +238,8 @@ sub quoteUrls {
~<a href=\"mailto:$2\">$1$2</a>~igx;
# attachment links
- $text =~ s~\b(attachment\s*\#?\s*(\d+)(?:\s+\[details\])?)
+ # BMO: don't make diff view the default for patches (Bug 652332)
+ $text =~ s~\b(attachment$s*\#?$s*(\d+)(?:$s+\[diff\])?(?:\s+\[details\])?)
~($things[$count++] = get_attachment_link($2, $1, $user)) &&
("\x{FDD2}" . ($count-1) . "\x{FDD3}")
~egmxi;
@@ -247,14 +252,14 @@ sub quoteUrls {
# 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_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)
+ 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)
~ # We have several choices. $1 here is the link, and $2-4 are set
# depending on which part matched
(defined($2) ? get_bug_link($2, $1, { comment_num => $3, user => $user }) :
"<a href=\"$current_bugurl#c$4\">$1</a>")
- ~egox;
+ ~egx;
# Old duplicate markers. These don't use $bug_word because they are old
# and were never customizable.
@@ -278,7 +283,7 @@ sub get_attachment_link {
my $dbh = Bugzilla->dbh;
$user ||= Bugzilla->user;
- my $attachment = new Bugzilla::Attachment($attachid);
+ my $attachment = new Bugzilla::Attachment({ id => $attachid, cache => 1 });
if ($attachment) {
my $title = "";
@@ -295,19 +300,21 @@ sub get_attachment_link {
$title = html_quote(clean_text($title));
$link_text =~ s/ \[details\]$//;
+ $link_text =~ s/ \[diff\]$//;
my $linkval = "attachment.cgi?id=$attachid";
- # If the attachment is a patch, try to link to the diff rather
- # than the text, by default.
+ # If the attachment is a patch and patch_viewer feature is
+ # enabled, add link to the diff.
my $patchlink = "";
if ($attachment->ispatch and Bugzilla->feature('patch_viewer')) {
- $patchlink = '&amp;action=diff';
+ $patchlink = qq| <a href="${linkval}&amp;action=diff" title="$title">[diff]</a>|;
}
# Whitespace matters here because these links are in <pre> tags.
return qq|<span class="$className">|
- . qq|<a href="${linkval}${patchlink}" name="attach_${attachid}" title="$title">$link_text</a>|
+ . qq|<a href="${linkval}" name="attach_${attachid}" title="$title">$link_text</a>|
. qq| <a href="${linkval}&amp;action=edit" title="$title">[details]</a>|
+ . qq|${patchlink}|
. qq|</span>|;
}
else {
@@ -328,8 +335,8 @@ sub get_bug_link {
$options->{user} ||= Bugzilla->user;
my $dbh = Bugzilla->dbh;
- if (defined $bug) {
- $bug = blessed($bug) ? $bug : new Bugzilla::Bug($bug);
+ if (defined $bug && $bug ne '') {
+ $bug = blessed($bug) ? $bug : new Bugzilla::Bug({ id => $bug, cache => 1 });
return $link_text if $bug->{error};
}
@@ -396,13 +403,10 @@ sub mtime_filter {
#
# 1. YUI CSS
# 2. Standard Bugzilla stylesheet set (persistent)
-# 3. Standard Bugzilla stylesheet set (selectable)
-# 4. All third-party "skin" stylesheet sets (selectable)
-# 5. Page-specific styles
-# 6. Custom Bugzilla stylesheet set (persistent)
-#
-# "Selectable" skin file sets may be either preferred or alternate.
-# Exactly one is preferred, determined by the "skin" user preference.
+# 3. Third-party "skin" stylesheet set, per user prefs (persistent)
+# 4. Page-specific styles
+# 5. Custom Bugzilla stylesheet set (persistent)
+
sub css_files {
my ($style_urls, $yui, $yui_css) = @_;
@@ -419,18 +423,10 @@ sub css_files {
my @css_sets = map { _css_link_set($_) } @requested_css;
- my %by_type = (standard => [], alternate => {}, skin => [], custom => []);
+ my %by_type = (standard => [], skin => [], custom => []);
foreach my $set (@css_sets) {
foreach my $key (keys %$set) {
- if ($key eq 'alternate') {
- foreach my $alternate_skin (keys %{ $set->{alternate} }) {
- my $files = $by_type{alternate}->{$alternate_skin} ||= [];
- push(@$files, $set->{alternate}->{$alternate_skin});
- }
- }
- else {
- push(@{ $by_type{$key} }, $set->{$key});
- }
+ push(@{ $by_type{$key} }, $set->{$key});
}
}
@@ -447,27 +443,15 @@ sub _css_link_set {
if ($file_name !~ m{(^|/)skins/standard/}) {
return \%set;
}
-
- my $skin_user_prefs = Bugzilla->user->settings->{skin};
+
+ my $skin = Bugzilla->user->settings->{skin}->{value};
my $cgi_path = bz_locations()->{'cgi_path'};
- # If the DB is not accessible, user settings are not available.
- my $all_skins = $skin_user_prefs ? $skin_user_prefs->legal_values : [];
- my %skin_urls;
- foreach my $option (@$all_skins) {
- next if $option eq 'standard';
- my $skin_file_name = $file_name;
- $skin_file_name =~ s{(^|/)skins/standard/}{skins/contrib/$option/};
- if (my $mtime = _mtime("$cgi_path/$skin_file_name")) {
- $skin_urls{$option} = mtime_filter($skin_file_name, $mtime);
- }
- }
- $set{alternate} = \%skin_urls;
-
- my $skin = $skin_user_prefs->{'value'};
- if ($skin ne 'standard' and defined $set{alternate}->{$skin}) {
- $set{skin} = delete $set{alternate}->{$skin};
+ my $skin_file_name = $file_name;
+ $skin_file_name =~ s{(^|/)skins/standard/}{skins/contrib/$skin/};
+ if (my $mtime = _mtime("$cgi_path/$skin_file_name")) {
+ $set{skin} = mtime_filter($skin_file_name, $mtime);
}
-
+
my $custom_file_name = $file_name;
$custom_file_name =~ s{(^|/)skins/standard/}{skins/custom/};
if (my $custom_mtime = _mtime("$cgi_path/$custom_file_name")) {
@@ -553,10 +537,9 @@ $Template::Stash::SCALAR_OPS->{ 0 } =
$Template::Stash::SCALAR_OPS->{ truncate } =
sub {
my ($string, $length, $ellipsis) = @_;
- $ellipsis ||= "";
-
return $string if !$length || length($string) <= $length;
-
+
+ $ellipsis ||= '';
my $strlen = $length - length($ellipsis);
my $newstr = substr($string, 0, $strlen) . $ellipsis;
return $newstr;
@@ -612,6 +595,10 @@ sub create {
COMPILE_DIR => bz_locations()->{'template_cache'},
+ # Don't check for a template update until 1 hour has passed since the
+ # last check.
+ STAT_TTL => 60 * 60,
+
# Initialize templates (f.e. by loading plugins like Hook).
PRE_PROCESS => ["global/initialize.none.tmpl"],
@@ -663,6 +650,18 @@ sub create {
$var =~ s/>/\\x3e/g;
return $var;
},
+
+ # Sadly, different to the above. See http://www.json.org/
+ # for details.
+ json => sub {
+ my ($var) = @_;
+ $var =~ s/([\\\"\/])/\\$1/g;
+ $var =~ s/\n/\\n/g;
+ $var =~ s/\r/\\r/g;
+ $var =~ s/\f/\\f/g;
+ $var =~ s/\t/\\t/g;
+ return $var;
+ },
# Converts data to base64
base64 => sub {
@@ -837,9 +836,7 @@ sub create {
# (Wrapping the message in the WebService is unnecessary
# and causes awkward things like \n's appearing in error
# messages in JSON-RPC.)
- unless (Bugzilla->usage_mode == USAGE_MODE_JSON
- or Bugzilla->usage_mode == USAGE_MODE_XMLRPC)
- {
+ unless (i_am_webservice()) {
$var = wrap_comment($var, 72);
}
$var =~ s/\&nbsp;/ /g;
@@ -889,14 +886,9 @@ sub create {
# Currently logged in user, if any
# If an sudo session is in progress, this is the user we're faking
'user' => sub { return Bugzilla->user; },
-
+
# Currenly active language
- # XXX Eventually this should probably be replaced with something
- # like Bugzilla->language.
- 'current_language' => sub {
- my ($language) = include_languages();
- return $language;
- },
+ 'current_language' => sub { return Bugzilla->current_language; },
# If an sudo session is in progress, this is the user who
# started the session.
@@ -907,7 +899,7 @@ sub create {
# Allow templates to access docs url with users' preferred language
'docs_urlbase' => sub {
- my ($language) = include_languages();
+ my $language = Bugzilla->current_language;
my $docs_urlbase = Bugzilla->params->{'docs_urlbase'};
$docs_urlbase =~ s/\%lang\%/$language/;
return $docs_urlbase;
@@ -936,7 +928,15 @@ sub create {
Bugzilla->fields({ by_name => 1 });
return $cache->{template_bug_fields};
},
-
+
+ # A general purpose cache to store rendered templates for reuse.
+ # Make sure to not mix language-specific data.
+ 'template_cache' => sub {
+ my $cache = Bugzilla->request_cache->{template_cache} ||= {};
+ $cache->{users} ||= {};
+ return $cache;
+ },
+
'css_files' => \&css_files,
yui_resolve_deps => \&yui_resolve_deps,
@@ -983,8 +983,17 @@ sub create {
'default_authorizer' => sub { return Bugzilla::Auth->new() },
},
};
-
- local $Template::Config::CONTEXT = 'Bugzilla::Template::Context';
+ # Use a per-process provider to cache compiled templates in memory across
+ # requests.
+ my $provider_key = join(':', @{ $config->{INCLUDE_PATH} });
+ my $shared_providers = Bugzilla->process_cache->{shared_providers} ||= {};
+ $shared_providers->{$provider_key} ||= Template::Provider->new($config);
+ $config->{LOAD_TEMPLATES} = [ $shared_providers->{$provider_key} ];
+
+ # BMO - use metrics subclass
+ local $Template::Config::CONTEXT = Bugzilla->metrics_enabled()
+ ? 'Bugzilla::Metrics::Template::Context'
+ : 'Bugzilla::Template::Context';
Bugzilla::Hook::process('template_before_create', { config => $config });
my $template = $class->new($config)
@@ -1064,6 +1073,9 @@ sub precompile_templates {
# If anything created a Template object before now, clear it out.
delete Bugzilla->request_cache->{template};
+ # Clear out the cached Provider object
+ Bugzilla->process_cache->{shared_providers} = undef;
+
print install_string('done') . "\n" if $output;
}