Cope with non-ASCII $site_name
[gitweb] / gitweb.cgi
index f57ed5a65700e539c8a0054866873f39ddec79e7..28a64eabb1b037574724638a19d98320c6e34a24 100755 (executable)
@@ -519,18 +519,6 @@ our %feature = (
                'override' => 0,
                'default' => [0]},
 
-       # Enable and configure ability to change common timezone for dates
-       # in gitweb output via JavaScript.  Enabled by default.
-       # Project specific override is not supported.
-       'javascript-timezone' => {
-               'override' => 0,
-               'default' => [
-                       'local',     # default timezone: 'utc', 'local', or '(-|+)HHMM' format,
-                                    # or undef to turn off this feature
-                       'gitweb_tz', # name of cookie where to store selected timezone
-                       'datetime',  # CSS class used to mark up dates for manipulation
-               ]},
-
        # Syntax highlighting support. This is based on Daniel Svensson's
        # and Sham Chukoury's work in gitweb-xmms2.git.
        # It requires the 'highlight' program present in $PATH,
@@ -1874,7 +1862,7 @@ sub esc_html_hl_regions {
 
                $out .= esc_html(substr($str, $pos, $begin - $pos), %opts)
                        if ($begin - $pos > 0);
-               $out .= $cgi->span({-class => $css_class}, $escaped);
+               $out .= "<mark class=\"$css_class\">$escaped</mark>";
 
                $pos = $end;
        }
@@ -1904,7 +1892,7 @@ sub esc_html_match_hl {
        my @matches = matchpos_list($str, $regexp);
        return esc_html($str) unless @matches;
 
-       return esc_html_hl_regions($str, 'match', @matches);
+       return esc_html_hl_regions($str, undef, @matches);
 }
 
 
@@ -1936,7 +1924,7 @@ sub esc_html_match_hl_chopped {
                push @filtered, $m;
        }
 
-       return esc_html_hl_regions($chopped . $tail, 'match', @filtered);
+       return esc_html_hl_regions($chopped . $tail, undef, @filtered);
 }
 
 ## ----------------------------------------------------------------------
@@ -3044,7 +3032,7 @@ sub git_populate_project_tagcloud {
                        $title =~ s/^/&nbsp;/g;
                        $title =~ s/$/&nbsp;/g;
                        if (defined $matched && $matched eq $ctag) {
-                               $title = qq(<span class="match">$title</span>);
+                               $title = qq(<mark>$title</mark>);
                        }
                        $cloud->add($title, href(project=>undef, ctag=>$ctag),
                                    $ctags_lc{$ctag}->{count});
@@ -3054,7 +3042,7 @@ sub git_populate_project_tagcloud {
                foreach my $ctag (keys %ctags_lc) {
                        my $title = esc_html($ctags_lc{$ctag}->{topname}, -nbsp=>1);
                        if (defined $matched && $matched eq $ctag) {
-                               $title = qq(<span class="match">$title</span>);
+                               $title = qq(<mark>$title</mark>);
                        }
                        $cloud->{$ctag}{count} = $ctags_lc{$ctag}->{count};
                        $cloud->{$ctag}{ctag} =
@@ -3594,12 +3582,13 @@ sub parse_commit_text {
        $co{'age'} = $age;
        $co{'age_string'} = age_string($age);
        my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($co{'committer_epoch'});
+       $co{'age_string_iso8601'} = sprintf "%4i-%02u-%02i %02u:%02u:%02uZ", 1900 + $year, $mon+1, $mday, $hour, $min, $sec;
        if ($age > 60*60*24*7*2) {
                $co{'age_string_date'} = sprintf "%4i-%02u-%02i", 1900 + $year, $mon+1, $mday;
-               $co{'age_string_age'} = $co{'age_string'};
+               $co{'age_string_age'} = "$co{'age_string_iso8601'} ($co{'age_string'})";
        } else {
                $co{'age_string_date'} = $co{'age_string'};
-               $co{'age_string_age'} = sprintf "%4i-%02u-%02i", 1900 + $year, $mon+1, $mday;
+               $co{'age_string_age'} = $co{'age_string_iso8601'};
        }
        return %co;
 }
@@ -4097,11 +4086,11 @@ sub print_feed_meta {
        } else {
                printf('<link rel="alternate" title="%s projects list" '.
                       'href="%s" type="text/plain; charset=utf-8" />'."\n",
-                      esc_attr($site_name),
+                      esc_attr(to_utf8($site_name)),
                       esc_attr(href(project=>undef, action=>"project_index")));
                printf('<link rel="alternate" title="%s projects feeds" '.
                       'href="%s" type="text/x-opml" />'."\n",
-                      esc_attr($site_name),
+                      esc_attr(to_utf8($site_name)),
                       esc_attr(href(project=>undef, action=>"opml")));
        }
 }
@@ -4310,28 +4299,24 @@ sub git_footer_html {
                insert_file($site_footer);
        }
 
-       print qq!<script type="text/javascript" src="!.esc_url($javascript).qq!"></script>\n!;
        if (defined $action &&
            $action eq 'blame_incremental') {
-               print qq!<script type="text/javascript">\n!.
+               print qq!<script src="!.esc_url($javascript).qq!"></script>\n!;
+               print qq!<script>\n!.
                      qq!startBlame("!. esc_attr(href(action=>"blame_data", -replay=>1)) .qq!",\n!.
                      qq!           "!. esc_attr(href()) .qq!");\n!.
                      qq!</script>\n!;
        } else {
-               my ($jstimezone, $tz_cookie, $datetime_class) =
-                       gitweb_get_feature('javascript-timezone');
-
-               print qq!<script type="text/javascript">\n!.
-                     qq!window.onload = function () {\n!;
                if (gitweb_check_feature('javascript-actions')) {
-                       print qq!       fixLinks();\n!;
-               }
-               if ($jstimezone && $tz_cookie && $datetime_class) {
-                       print qq!       var tz_cookie = { name: '$tz_cookie', expires: 14, path: '/' };\n!. # in days
-                             qq!       onloadTZSetup('$jstimezone', tz_cookie, '$datetime_class');\n!;
+                       print qq!<script src="!.esc_url($javascript).qq!"></script>\n!;
+                       print qq!<script>\n!.
+                               qq!window.onload = function () {\n!;
+                       if (gitweb_check_feature('javascript-actions')) {
+                               print qq!       fixLinks();\n!;
+                       }
+                       print qq!};\n!.
+                               qq!</script>\n!;
                }
-               print qq!};\n!.
-                     qq!</script>\n!;
        }
 
        print "</body>\n" .
@@ -4429,7 +4414,7 @@ sub git_print_page_nav {
        print "<div class=\"page_nav\">\n" .
                (join " | ",
                 map { $_ eq $current ?
-                      $_ : $cgi->a({-href => ($arg{$_}{_href} ? $arg{$_}{_href} : href(%{$arg{$_}}))}, "$_")
+                      $cgi->span({-class => "current"}, $_) : $cgi->a({-href => ($arg{$_}{_href} ? $arg{$_}{_href} : href(%{$arg{$_}}))}, "$_")
                 } @navs);
        print "<br/>\n$extra" if defined $extra; # pager or formats
        print "</div>\n";
@@ -4494,7 +4479,7 @@ sub git_print_header_div {
 
 sub format_repo_url {
        my ($name, $url) = @_;
-       return "<tr class=\"metadata_url\"><td>$name</td><td>$url</td></tr>\n";
+       return "<tr class=\"metadata_url\"><th>$name</th><td>$url</td></tr>\n";
 }
 
 # Group output by placing it in a DIV element and adding a header.
@@ -4537,23 +4522,8 @@ sub git_print_section {
 
 sub format_timestamp_html {
        my $date = shift;
-       my $strtime = $date->{'rfc2822'};
-
-       my (undef, undef, $datetime_class) =
-               gitweb_get_feature('javascript-timezone');
-       if ($datetime_class) {
-               $strtime = qq!<span class="$datetime_class">$strtime</span>!;
-       }
-
-       my $localtime_format = '(%02d:%02d %s)';
-       if ($date->{'hour_local'} < 6) {
-               $localtime_format = '(<span class="atnight">%02d:%02d</span> %s)';
-       }
-       $strtime .= ' ' .
-                   sprintf($localtime_format,
-                           $date->{'hour_local'}, $date->{'minute_local'}, $date->{'tz_local'});
 
-       return $strtime;
+       return qq!<time datetime="$date->{'iso-8601'}" title="$date->{'iso-tz'}">$date->{'rfc2822'}</time>!;
 }
 
 # Outputs the author name and date in long form
@@ -4583,7 +4553,7 @@ sub git_print_authorship_rows {
        @people = ('author', 'committer') unless @people;
        foreach my $who (@people) {
                my %wd = parse_date($co->{"${who}_epoch"}, $co->{"${who}_tz"});
-               print "<tr><td>$who</td><td>" .
+               print "<tr><th>$who</th><td>" .
                      format_search_author($co->{"${who}_name"}, $who,
                                           esc_html($co->{"${who}_name"})) . " " .
                      format_search_author($co->{"${who}_email"}, $who,
@@ -4682,11 +4652,6 @@ sub git_print_log {
 
                print format_log_line_html($line) . "<br/>\n";
        }
-
-       if ($opts{'-final_empty_line'}) {
-               # end with single empty line
-               print "<br/>\n" unless $skip_blank_line;
-       }
 }
 
 # return link target (what link points to)
@@ -4883,11 +4848,11 @@ sub git_difftree_body {
        my ($difftree, $hash, @parents) = @_;
        my ($parent) = $parents[0];
        my $have_blame = gitweb_check_feature('blame');
-       print "<div class=\"list_head\">\n";
        if ($#{$difftree} > 10) {
+               print "<div class=\"list_head\">\n";
                print(($#{$difftree} + 1) . " files changed:\n");
+               print "</div>\n";
        }
-       print "</div>\n";
 
        print "<table class=\"" .
              (@parents > 1 ? "combined " : "") .
@@ -5912,13 +5877,15 @@ sub git_log_body {
        $from = 0 unless defined $from;
        $to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to);
 
+       print "<section class=\"cards\">\n";
        for (my $i = 0; $i <= $to; $i++) {
                my %co = %{$commitlist->[$i]};
                next if !%co;
                my $commit = $co{'id'};
                my $ref = format_ref_marker($refs, $commit);
+               print "<article>\n";
                git_print_header_div('commit',
-                              "<span class=\"age\">$co{'age_string'}</span>" .
+                              "<time datetime=\"$co{'age_string_iso8601'}\" title=\"$co{'age_string_iso8601'}\" class=\"age\">$co{'age_string'}</time>" .
                               esc_html($co{'title'}) . $ref,
                               $commit);
                print "<div class=\"title_text\">\n" .
@@ -5928,15 +5895,16 @@ sub git_log_body {
                      $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") .
                      " | " .
                      $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") .
-                     "<br/>\n" .
                      "</div>\n";
                      git_print_authorship(\%co, -tag => 'span');
-                     print "<br/>\n</div>\n";
+                     print "</div>\n";
 
                print "<div class=\"log_body\">\n";
-               git_print_log($co{'comment'}, -final_empty_line=> 1);
+               git_print_log($co{'comment'});
                print "</div>\n";
+               print "</article>\n";
        }
+       print "</section>\n";
        if ($extra) {
                print "<div class=\"page_nav\">\n";
                print "$extra\n";
@@ -5964,7 +5932,7 @@ sub git_shortlog_body {
                }
                $alternate ^= 1;
                # git_summary() used print "<td><i>$co{'age_string'}</i></td>\n" .
-               print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+               print "<td title=\"$co{'age_string_age'}\"><time datetime=\"$co{'age_string_iso8601'}\">$co{'age_string_date'}</time></td>\n" .
                      format_author_html('td', \%co, 10) . "<td>";
                print format_subject_html($co{'title'}, $co{'title_short'},
                                          href(action=>"commit", hash=>$commit), $ref);
@@ -6013,7 +5981,7 @@ sub git_history_body {
                        print "<tr class=\"light\">\n";
                }
                $alternate ^= 1;
-               print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+               print "<td title=\"$co{'age_string_age'}\"><time datetime=\"$co{'age_string_iso8601'}\">$co{'age_string_date'}</time></td>\n" .
        # shortlog:   format_author_html('td', \%co, 10)
                      format_author_html('td', \%co, 15, 3) . "<td>";
                # originally git_history used chop_str($co{'title'}, 50)
@@ -6343,7 +6311,7 @@ sub git_search_changes {
                        $alternate ^= 1;
                        %co = parse_commit($set{'commit'});
                        my $author = chop_and_escape_str($co{'author_name'}, 15, 5);
-                       print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+                       print "<td title=\"$co{'age_string_age'}\"><time datetime=\"$co{'age_string_iso8601'}\">$co{'age_string_date'}</time></td>\n" .
                              "<td><i>$author</i></td>\n" .
                              "<td>" .
                              $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}),
@@ -6355,7 +6323,7 @@ sub git_search_changes {
                        print $cgi->a({-href => href(action=>"blob", hash_base=>$co{'id'},
                                                     hash=>$set{'to_id'}, file_name=>$set{'to_file'}),
                                      -class => "list"},
-                                     "<span class=\"match\">" . esc_path($set{'file'}) . "</span>") .
+                                     "<mark>" . esc_path($set{'file'}) . "</mark>") .
                              "<br/>\n";
                }
        }
@@ -6430,9 +6398,9 @@ sub git_search_files {
                        $ltext = untabify($ltext);
                        if ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) {
                                $ltext = esc_html($1, -nbsp=>1);
-                               $ltext .= '<span class="match">';
+                               $ltext .= '<mark>';
                                $ltext .= esc_html($2, -nbsp=>1);
-                               $ltext .= '</span>';
+                               $ltext .= '</mark>';
                                $ltext .= esc_html($3, -nbsp=>1);
                        } else {
                                $ltext = esc_html($ltext, -nbsp=>1);
@@ -6477,7 +6445,7 @@ sub git_search_grep_body {
                        print "<tr class=\"light\">\n";
                }
                $alternate ^= 1;
-               print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+               print "<td title=\"$co{'age_string_age'}\"><time datetime=\"$co{'age_string_iso8601'}\">$co{'age_string_date'}</time></td>\n" .
                      format_author_html('td', \%co, 15, 5) .
                      "<td>" .
                      $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}),
@@ -6497,7 +6465,7 @@ sub git_search_grep_body {
                                $match = esc_html($match);
                                $trail = esc_html($trail);
 
-                               print "$lead<span class=\"match\">$match</span>$trail<br />";
+                               print "$lead<mark>$match</mark>$trail<br />";
                        }
                }
                print "</td>\n" .
@@ -6624,14 +6592,13 @@ sub git_summary {
        git_header_html();
        git_print_page_nav('summary','', $head);
 
-       print "<div class=\"title\">&nbsp;</div>\n";
        print "<table class=\"projects_list\">\n" .
-             "<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n";
+             "<tr id=\"metadata_desc\"><th>description</th><td>" . esc_html($descr) . "</td></tr>\n";
         if ($owner and not $omit_owner) {
-               print  "<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
+               print  "<tr id=\"metadata_owner\"><th>owner</th><td>" . esc_html($owner) . "</td></tr>\n";
         }
        if (defined $cd{'rfc2822'}) {
-               print "<tr id=\"metadata_lchange\"><td>last change</td>" .
+               print "<tr id=\"metadata_lchange\"><th>last change</th>" .
                      "<td>".format_timestamp_html(\%cd)."</td></tr>\n";
        }
 
@@ -6654,7 +6621,7 @@ sub git_summary {
                        # without ability to add tags, don't show if there are none
                        my $cloud = git_populate_project_tagcloud($ctags);
                        print "<tr id=\"metadata_ctags\">" .
-                             "<td>content tags</td>" .
+                             "<th>content tags</th>" .
                              "<td>".git_show_project_tagcloud($cloud, 48)."</td>" .
                              "</tr>\n";
                }
@@ -6662,51 +6629,66 @@ sub git_summary {
 
        print "</table>\n";
 
+       print("<section class=\"cards\">\n");
+
        # If XSS prevention is on, we don't include README.html.
        # TODO: Allow a readme in some safe format.
        if (!$prevent_xss && -s "$projectroot/$project/README.html") {
+               print("<article>\n");
                print "<div class=\"title\">readme</div>\n" .
                      "<div class=\"readme\">\n";
                insert_file("$projectroot/$project/README.html");
                print "\n</div>\n"; # class="readme"
+               print("</article>\n");
        }
 
        # we need to request one more than 16 (0..15) to check if
        # those 16 are all
        my @commitlist = $head ? parse_commits($head, 17) : ();
        if (@commitlist) {
+               print("<article>\n");
                git_print_header_div('shortlog');
                git_shortlog_body(\@commitlist, 0, 15, $refs,
                                  $#commitlist <=  15 ? undef :
                                  $cgi->a({-href => href(action=>"shortlog")}, "..."));
+               print("</article>\n");
        }
 
        if (@taglist) {
+               print("<article>\n");
                git_print_header_div('tags');
                git_tags_body(\@taglist, 0, 15,
                              $#taglist <=  15 ? undef :
                              $cgi->a({-href => href(action=>"tags")}, "..."));
+               print("</article>\n");
        }
 
        if (@headlist) {
+               print("<article>\n");
                git_print_header_div('heads');
                git_heads_body(\@headlist, $head, 0, 15,
                               $#headlist <= 15 ? undef :
                               $cgi->a({-href => href(action=>"heads")}, "..."));
+               print("</article>\n");
        }
 
        if (%remotedata) {
+               print("<article>\n");
                git_print_header_div('remotes');
                git_remotes_body(\%remotedata, 15, $head);
+               print("</article>\n");
        }
 
        if (@forklist) {
+               print("<article>\n");
                git_print_header_div('forks');
                git_project_list_body(\@forklist, 'age', 0, 15,
                                      $#forklist <= 15 ? undef :
                                      $cgi->a({-href => href(action=>"forks")}, "..."),
                                      'no_header');
+               print("</article>\n");
        }
+       print("</section>\n");
 
        git_footer_html();
 }
@@ -6725,7 +6707,7 @@ sub git_tag {
        print "<div class=\"title_text\">\n" .
              "<table class=\"object_header\">\n" .
              "<tr>\n" .
-             "<td>object</td>\n" .
+             "<th>object</th>\n" .
              "<td>" . $cgi->a({-class => "list", -href => href(action=>$tag{'type'}, hash=>$tag{'object'})},
                               $tag{'object'}) . "</td>\n" .
              "<td class=\"link\">" . $cgi->a({-href => href(action=>$tag{'type'}, hash=>$tag{'object'})},
@@ -7602,9 +7584,9 @@ sub git_commit {
        print "<div class=\"title_text\">\n" .
              "<table class=\"object_header\">\n";
        git_print_authorship_rows(\%co);
-       print "<tr><td>commit</td><td class=\"sha1\">$co{'id'}</td></tr>\n";
+       print "<tr><th>commit</th><td class=\"sha1\">$co{'id'}</td></tr>\n";
        print "<tr>" .
-             "<td>tree</td>" .
+             "<th>tree</th>" .
              "<td class=\"sha1\">" .
              $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash),
                       class => "list"}, $co{'tree'}) .
@@ -7621,7 +7603,7 @@ sub git_commit {
 
        foreach my $par (@$parents) {
                print "<tr>" .
-                     "<td>parent</td>" .
+                     "<th>parent</th>" .
                      "<td class=\"sha1\">" .
                      $cgi->a({-href => href(action=>"commit", hash=>$par),
                               class => "list"}, $par) .
@@ -8018,7 +8000,7 @@ sub git_commitdiff {
                print "<div class=\"page_body\">\n";
                if (@{$co{'comment'}} > 1) {
                        print "<div class=\"log\">\n";
-                       git_print_log($co{'comment'}, -final_empty_line=> 1, -remove_title => 1);
+                       git_print_log($co{'comment'}, -remove_title => 1);
                        print "</div>\n"; # class="log"
                }
 
@@ -8236,7 +8218,7 @@ sub git_feed {
        return if ($cgi->request_method() eq 'HEAD');
 
        # header variables
-       my $title = "$site_name - $project/$action";
+       my $title = to_utf8($site_name) . " - $project/$action";
        my $feed_type = 'log';
        if (defined $hash) {
                $title .= " - '$hash'";
@@ -8399,7 +8381,7 @@ sub git_opml {
                -charset => 'utf-8',
                -content_disposition => 'inline; filename="opml.xml"');
 
-       my $title = esc_html($site_name);
+       my $title = esc_html(to_utf8($site_name));
        my $filter = " within subdirectory ";
        if (defined $project_filter) {
                $filter .= esc_html($project_filter);