Merge branch 'jn/gitweb-hilite-regions'

* jn/gitweb-hilite-regions:
  gitweb: Highlight matched part of shortened project description
  gitweb: Highlight matched part of project description when searching projects
  gitweb: Highlight matched part of project name when searching projects
  gitweb: Introduce esc_html_match_hl and esc_html_hl_regions
This commit is contained in:
Junio C Hamano 2012-03-04 23:35:18 -08:00
Родитель 250f0a074a e607b79fb1
Коммит 6759f95d63
1 изменённых файлов: 92 добавлений и 3 удалений

Просмотреть файл

@ -1724,6 +1724,88 @@ sub chop_and_escape_str {
}
}
# Highlight selected fragments of string, using given CSS class,
# and escape HTML. It is assumed that fragments do not overlap.
# Regions are passed as list of pairs (array references).
#
# Example: esc_html_hl_regions("foobar", "mark", [ 0, 3 ]) returns
# '<span class="mark">foo</span>bar'
sub esc_html_hl_regions {
my ($str, $css_class, @sel) = @_;
return esc_html($str) unless @sel;
my $out = '';
my $pos = 0;
for my $s (@sel) {
$out .= esc_html(substr($str, $pos, $s->[0] - $pos))
if ($s->[0] - $pos > 0);
$out .= $cgi->span({-class => $css_class},
esc_html(substr($str, $s->[0], $s->[1] - $s->[0])));
$pos = $s->[1];
}
$out .= esc_html(substr($str, $pos))
if ($pos < length($str));
return $out;
}
# return positions of beginning and end of each match
sub matchpos_list {
my ($str, $regexp) = @_;
return unless (defined $str && defined $regexp);
my @matches;
while ($str =~ /$regexp/g) {
push @matches, [$-[0], $+[0]];
}
return @matches;
}
# highlight match (if any), and escape HTML
sub esc_html_match_hl {
my ($str, $regexp) = @_;
return esc_html($str) unless defined $regexp;
my @matches = matchpos_list($str, $regexp);
return esc_html($str) unless @matches;
return esc_html_hl_regions($str, 'match', @matches);
}
# highlight match (if any) of shortened string, and escape HTML
sub esc_html_match_hl_chopped {
my ($str, $chopped, $regexp) = @_;
return esc_html_match_hl($str, $regexp) unless defined $chopped;
my @matches = matchpos_list($str, $regexp);
return esc_html($chopped) unless @matches;
# filter matches so that we mark chopped string
my $tail = "... "; # see chop_str
unless ($chopped =~ s/\Q$tail\E$//) {
$tail = '';
}
my $chop_len = length($chopped);
my $tail_len = length($tail);
my @filtered;
for my $m (@matches) {
if ($m->[0] > $chop_len) {
push @filtered, [ $chop_len, $chop_len + $tail_len ] if ($tail_len > 0);
last;
} elsif ($m->[1] > $chop_len) {
push @filtered, [ $m->[0], $chop_len + $tail_len ];
last;
}
push @filtered, $m;
}
return esc_html_hl_regions($chopped . $tail, 'match', @filtered);
}
## ----------------------------------------------------------------------
## functions returning short strings
@ -5368,10 +5450,17 @@ sub git_project_list_rows {
print "</td>\n";
}
print "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
-class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
-class => "list"},
esc_html_match_hl($pr->{'path'}, $search_regexp)) .
"</td>\n" .
"<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
-class => "list", -title => $pr->{'descr_long'}},
esc_html($pr->{'descr'})) . "</td>\n" .
-class => "list",
-title => $pr->{'descr_long'}},
$search_regexp
? esc_html_match_hl_chopped($pr->{'descr_long'},
$pr->{'descr'}, $search_regexp)
: esc_html($pr->{'descr'})) .
"</td>\n" .
"<td><i>" . chop_and_escape_str($pr->{'owner'}, 15) . "</i></td>\n";
print "<td class=\"". age_class($pr->{'age'}) . "\">" .
(defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</td>\n" .