| From 1bf877073ac36999c081e4b125ae0cd2a9c6580b Mon Sep 17 00:00:00 2001 |
| From: Jonathan Nieder <jrnieder@gmail.com> |
| Date: Fri, 3 Sep 2010 19:54:45 -0500 |
| Subject: Revert "Merge branch 'jn/gitweb-plackup'" |
| |
| The gitweb-plackup topic, among other changes, moves static content |
| from /usr/share/gitweb to a static/ subdirectory. That is a very |
| good change, but I do not think now is the time in Debian to iron out |
| the kinks in it. |
| |
| This reverts commit 7c1b228d26107d2cac9fd9549a6a1cff41c24b51, reversing |
| changes made to bcacc0ebdb17b55040826bf82d1bde4070119250. |
| |
| Conflicts: |
| |
| Makefile |
| git-instaweb.sh |
| gitweb/Makefile |
| |
| Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> |
| --- |
| Documentation/git-instaweb.txt | 2 +- |
| Makefile | 30 +- |
| git-instaweb.sh | 251 +++--------- |
| gitweb/INSTALL | 19 +- |
| gitweb/Makefile | 40 +- |
| gitweb/README | 14 +- |
| gitweb/git-favicon.png | Bin 0 -> 115 bytes |
| gitweb/git-logo.png | Bin 0 -> 207 bytes |
| gitweb/gitweb.css | 592 +++++++++++++++++++++++++++ |
| gitweb/gitweb.js | 875 ++++++++++++++++++++++++++++++++++++++++ |
| gitweb/static/git-favicon.png | Bin 115 -> 0 bytes |
| gitweb/static/git-logo.png | Bin 207 -> 0 bytes |
| gitweb/static/gitweb.css | 592 --------------------------- |
| gitweb/static/gitweb.js | 875 ---------------------------------------- |
| t/gitweb-lib.sh | 6 +- |
| 15 files changed, 1572 insertions(+), 1724 deletions(-) |
| create mode 100644 gitweb/git-favicon.png |
| create mode 100644 gitweb/git-logo.png |
| create mode 100644 gitweb/gitweb.css |
| create mode 100644 gitweb/gitweb.js |
| delete mode 100644 gitweb/static/git-favicon.png |
| delete mode 100644 gitweb/static/git-logo.png |
| delete mode 100644 gitweb/static/gitweb.css |
| delete mode 100644 gitweb/static/gitweb.js |
| |
| diff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt |
| index 2c3c4d2..a1f17df 100644 |
| --- a/Documentation/git-instaweb.txt |
| +++ b/Documentation/git-instaweb.txt |
| @@ -29,7 +29,7 @@ OPTIONS |
| The HTTP daemon command-line that will be executed. |
| Command-line options may be specified here, and the |
| configuration file will be added at the end of the command-line. |
| - Currently apache2, lighttpd, mongoose, plackup and webrick are supported. |
| + Currently apache2, lighttpd, mongoose and webrick are supported. |
| (Default: lighttpd) |
| |
| -m:: |
| diff --git a/Makefile b/Makefile |
| index 1f11618..16530d1 100644 |
| --- a/Makefile |
| +++ b/Makefile |
| @@ -280,7 +280,6 @@ mandir = share/man |
| infodir = share/info |
| gitexecdir = libexec/git-core |
| sharedir = $(prefix)/share |
| -gitwebdir = $(sharedir)/gitweb |
| template_dir = share/git-core/templates |
| htmldir = share/doc/git-doc |
| ifeq ($(prefix),/usr) |
| @@ -1512,7 +1511,6 @@ gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) |
| template_dir_SQ = $(subst ','\'',$(template_dir)) |
| htmldir_SQ = $(subst ','\'',$(htmldir)) |
| prefix_SQ = $(subst ','\'',$(prefix)) |
| -gitwebdir_SQ = $(subst ','\'',$(gitwebdir)) |
| |
| SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) |
| PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) |
| @@ -1650,38 +1648,45 @@ gitweb: |
| $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all |
| |
| ifdef JSMIN |
| -GITWEB_PROGRAMS += gitweb/static/gitweb.min.js |
| -GITWEB_JS = gitweb/static/gitweb.min.js |
| +GITWEB_PROGRAMS += gitweb/gitweb.min.js |
| +GITWEB_JS = gitweb/gitweb.min.js |
| else |
| -GITWEB_JS = gitweb/static/gitweb.js |
| +GITWEB_JS = gitweb/gitweb.js |
| endif |
| ifdef CSSMIN |
| -GITWEB_PROGRAMS += gitweb/static/gitweb.min.css |
| -GITWEB_CSS = gitweb/static/gitweb.min.css |
| +GITWEB_PROGRAMS += gitweb/gitweb.min.css |
| +GITWEB_CSS = gitweb/gitweb.min.css |
| else |
| -GITWEB_CSS = gitweb/static/gitweb.css |
| +GITWEB_CSS = gitweb/gitweb.css |
| endif |
| OTHER_PROGRAMS += gitweb/gitweb.cgi $(GITWEB_PROGRAMS) |
| gitweb/gitweb.cgi: gitweb/gitweb.perl $(GITWEB_PROGRAMS) |
| $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@) |
| |
| ifdef JSMIN |
| -gitweb/static/gitweb.min.js: gitweb/static/gitweb.js |
| +gitweb/gitweb.min.js: gitweb/gitweb.js |
| $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@) |
| endif # JSMIN |
| ifdef CSSMIN |
| -gitweb/static/gitweb.min.css: gitweb/static/gitweb.css |
| +gitweb/gitweb.min.css: gitweb/gitweb.css |
| $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@) |
| endif # CSSMIN |
| |
| |
| -git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/static/gitweb.css gitweb/static/gitweb.js |
| +git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js |
| $(QUIET_GEN)$(RM) $@ $@+ && \ |
| sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ |
| -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ |
| -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ |
| - -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \ |
| + -e '/@@GITWEB_CGI@@/r gitweb/gitweb.cgi' \ |
| + -e '/@@GITWEB_CGI@@/d' \ |
| + -e '/@@GITWEB_CSS@@/r $(GITWEB_CSS)' \ |
| + -e '/@@GITWEB_CSS@@/d' \ |
| + -e '/@@GITWEB_JS@@/r $(GITWEB_JS)' \ |
| + -e '/@@GITWEB_JS@@/d' \ |
| -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ |
| + -e 's|@@GITWEB_CSS_NAME@@|$(GITWEB_CSS)|' \ |
| + -e 's|@@GITWEB_JS_NAME@@|$(GITWEB_JS)|' \ |
| $@.sh > $@+ && \ |
| chmod +x $@+ && \ |
| mv $@+ $@ |
| @@ -2060,7 +2065,6 @@ install: all |
| $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install |
| ifndef NO_PERL |
| $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install |
| - $(MAKE) -C gitweb install |
| endif |
| ifndef NO_PYTHON |
| $(MAKE) -C git_remote_helpers prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install |
| diff --git a/git-instaweb.sh b/git-instaweb.sh |
| index b7342e2..0c6e103 100755 |
| --- a/git-instaweb.sh |
| +++ b/git-instaweb.sh |
| @@ -24,7 +24,6 @@ restart restart the web server |
| fqgitdir="$GIT_DIR" |
| local="$(git config --bool --get instaweb.local)" |
| httpd="$(git config --get instaweb.httpd)" |
| -root="$(git config --get instaweb.gitwebdir)" |
| port=$(git config --get instaweb.port) |
| module_path="$(git config --get instaweb.modulepath)" |
| |
| @@ -35,9 +34,6 @@ conf="$GIT_DIR/gitweb/httpd.conf" |
| # if installed, it doesn't need further configuration (module_path) |
| test -z "$httpd" && httpd='lighttpd -f' |
| |
| -# Default is @@GITWEBDIR@@ |
| -test -z "$root" && root='@@GITWEBDIR@@' |
| - |
| # any untaken local port will do... |
| test -z "$port" && port=1234 |
| |
| @@ -51,12 +47,6 @@ resolve_full_httpd () { |
| httpd="$httpd -f" |
| fi |
| ;; |
| - *plackup*) |
| - # server is started by running via generated gitweb.psgi in $fqgitdir/gitweb |
| - full_httpd="$fqgitdir/gitweb/gitweb.psgi" |
| - httpd_only="${httpd%% *}" # cut on first space |
| - return |
| - ;; |
| esac |
| |
| httpd_only="$(echo $httpd | cut -f1 -d' ')" |
| @@ -68,7 +58,7 @@ resolve_full_httpd () { |
| # these days and those are not in most users $PATHs |
| # in addition, we may have generated a server script |
| # in $fqgitdir/gitweb. |
| - for i in /usr/local/sbin /usr/sbin "$root" "$fqgitdir/gitweb" |
| + for i in /usr/local/sbin /usr/sbin "$fqgitdir/gitweb" |
| do |
| if test -x "$i/$httpd_only" |
| then |
| @@ -94,8 +84,8 @@ start_httpd () { |
| |
| # don't quote $full_httpd, there can be arguments to it (-f) |
| case "$httpd" in |
| - *mongoose*|*plackup*) |
| - #These servers don't have a daemon mode so we'll have to fork it |
| + *mongoose*) |
| + #The mongoose server doesn't have a daemon mode so we'll have to fork it |
| $full_httpd "$fqgitdir/gitweb/httpd.conf" & |
| #Save the pid before doing anything else (we'll print it later) |
| pid=$! |
| @@ -121,20 +111,6 @@ EOF |
| |
| stop_httpd () { |
| test -f "$fqgitdir/pid" && kill $(cat "$fqgitdir/pid") |
| - rm -f "$fqgitdir/pid" |
| -} |
| - |
| -httpd_is_ready () { |
| - "$PERL" -MIO::Socket::INET -e " |
| -local \$| = 1; # turn on autoflush |
| -exit if (IO::Socket::INET->new('127.0.0.1:$port')); |
| -print 'Waiting for \'$httpd\' to start ..'; |
| -do { |
| - print '.'; |
| - sleep(1); |
| -} until (IO::Socket::INET->new('127.0.0.1:$port')); |
| -print qq! (done)\n!; |
| -" |
| } |
| |
| while test $# != 0 |
| @@ -184,8 +160,8 @@ done |
| mkdir -p "$GIT_DIR/gitweb/tmp" |
| GIT_EXEC_PATH="$(git --exec-path)" |
| GIT_DIR="$fqgitdir" |
| -GITWEB_CONFIG="$fqgitdir/gitweb/gitweb_config.perl" |
| -export GIT_EXEC_PATH GIT_DIR GITWEB_CONFIG |
| +export GIT_EXEC_PATH GIT_DIR |
| + |
| |
| webrick_conf () { |
| # generate a standalone server script in $fqgitdir/gitweb. |
| @@ -217,7 +193,7 @@ EOF |
| |
| cat >"$conf" <<EOF |
| :Port: $port |
| -:DocumentRoot: "$root" |
| +:DocumentRoot: "$fqgitdir/gitweb" |
| :DirectoryIndex: ["gitweb.cgi"] |
| :PidFile: "$fqgitdir/pid" |
| EOF |
| @@ -226,18 +202,18 @@ EOF |
| |
| lighttpd_conf () { |
| cat > "$conf" <<EOF |
| -server.document-root = "$root" |
| +server.document-root = "$fqgitdir/gitweb" |
| server.port = $port |
| server.modules = ( "mod_setenv", "mod_cgi" ) |
| server.indexfiles = ( "gitweb.cgi" ) |
| server.pid-file = "$fqgitdir/pid" |
| -server.errorlog = "$fqgitdir/gitweb/$httpd_only/error.log" |
| +server.errorlog = "$fqgitdir/gitweb/error.log" |
| |
| # to enable, add "mod_access", "mod_accesslog" to server.modules |
| # variable above and uncomment this |
| -#accesslog.filename = "$fqgitdir/gitweb/$httpd_only/access.log" |
| +#accesslog.filename = "$fqgitdir/gitweb/access.log" |
| |
| -setenv.add-environment = ( "PATH" => env.PATH, "GITWEB_CONFIG" => env.GITWEB_CONFIG ) |
| +setenv.add-environment = ( "PATH" => env.PATH ) |
| |
| cgi.assign = ( ".cgi" => "" ) |
| |
| @@ -308,15 +284,14 @@ apache2_conf () { |
| test -d "/usr/lib/apache2/modules" && |
| module_path="/usr/lib/apache2/modules" |
| fi |
| + mkdir -p "$GIT_DIR/gitweb/logs" |
| bind= |
| test x"$local" = xtrue && bind='127.0.0.1:' |
| echo 'text/css css' > "$fqgitdir/mime.types" |
| cat > "$conf" <<EOF |
| ServerName "git-instaweb" |
| -ServerRoot "$root" |
| -DocumentRoot "$root" |
| -ErrorLog "$fqgitdir/gitweb/$httpd_only/error.log" |
| -CustomLog "$fqgitdir/gitweb/$httpd_only/access.log" combined |
| +ServerRoot "$fqgitdir/gitweb" |
| +DocumentRoot "$fqgitdir/gitweb" |
| PidFile "$fqgitdir/pid" |
| Listen $bind$port |
| EOF |
| @@ -337,14 +312,13 @@ EOF |
| # check to see if Dennis Stosberg's mod_perl compatibility patch |
| # (<20060621130708.Gcbc6e5c@leonov.stosberg.net>) has been applied |
| if test -f "$module_path/mod_perl.so" && |
| - sane_grep 'MOD_PERL' "$root/gitweb.cgi" >/dev/null |
| + sane_grep 'MOD_PERL' "$GIT_DIR/gitweb/gitweb.cgi" >/dev/null |
| then |
| # favor mod_perl if available |
| cat >> "$conf" <<EOF |
| LoadModule perl_module $module_path/mod_perl.so |
| PerlPassEnv GIT_DIR |
| PerlPassEnv GIT_EXEC_PATH |
| -PerlPassEnv GITWEB_CONFIG |
| <Location /gitweb.cgi> |
| SetHandler perl-script |
| PerlResponseHandler ModPerl::Registry |
| @@ -391,15 +365,15 @@ mongoose_conf() { |
| # For detailed description of every option, visit |
| # http://code.google.com/p/mongoose/wiki/MongooseManual |
| |
| -root $root |
| +root $fqgitdir/gitweb |
| ports $port |
| index_files gitweb.cgi |
| #ssl_cert $fqgitdir/gitweb/ssl_cert.pem |
| -error_log $fqgitdir/gitweb/$httpd_only/error.log |
| -access_log $fqgitdir/gitweb/$httpd_only/access.log |
| +error_log $fqgitdir/gitweb/error.log |
| +access_log $fqgitdir/gitweb/access.log |
| |
| #cgi setup |
| -cgi_env PATH=$PATH,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH,GITWEB_CONFIG=$GITWEB_CONFIG |
| +cgi_env PATH=$PATH,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH |
| cgi_interp $PERL |
| cgi_ext cgi,pl |
| |
| @@ -408,165 +382,41 @@ mime_types .gz=application/x-gzip,.tar.gz=application/x-tgz,.tgz=application/x-t |
| EOF |
| } |
| |
| -plackup_conf () { |
| - # generate a standalone 'plackup' server script in $fqgitdir/gitweb |
| - # with embedded configuration; it does not use "$conf" file |
| - cat > "$fqgitdir/gitweb/gitweb.psgi" <<EOF |
| -#!$PERL |
| - |
| -# gitweb - simple web interface to track changes in git repositories |
| -# PSGI wrapper and server starter (see http://plackperl.org) |
| - |
| -use strict; |
| - |
| -use IO::Handle; |
| -use Plack::MIME; |
| -use Plack::Builder; |
| -use Plack::App::WrapCGI; |
| -use CGI::Emulate::PSGI 0.07; # minimum version required to work with gitweb |
| - |
| -# mimetype mapping (from lighttpd_conf) |
| -Plack::MIME->add_type( |
| - ".pdf" => "application/pdf", |
| - ".sig" => "application/pgp-signature", |
| - ".spl" => "application/futuresplash", |
| - ".class" => "application/octet-stream", |
| - ".ps" => "application/postscript", |
| - ".torrent" => "application/x-bittorrent", |
| - ".dvi" => "application/x-dvi", |
| - ".gz" => "application/x-gzip", |
| - ".pac" => "application/x-ns-proxy-autoconfig", |
| - ".swf" => "application/x-shockwave-flash", |
| - ".tar.gz" => "application/x-tgz", |
| - ".tgz" => "application/x-tgz", |
| - ".tar" => "application/x-tar", |
| - ".zip" => "application/zip", |
| - ".mp3" => "audio/mpeg", |
| - ".m3u" => "audio/x-mpegurl", |
| - ".wma" => "audio/x-ms-wma", |
| - ".wax" => "audio/x-ms-wax", |
| - ".ogg" => "application/ogg", |
| - ".wav" => "audio/x-wav", |
| - ".gif" => "image/gif", |
| - ".jpg" => "image/jpeg", |
| - ".jpeg" => "image/jpeg", |
| - ".png" => "image/png", |
| - ".xbm" => "image/x-xbitmap", |
| - ".xpm" => "image/x-xpixmap", |
| - ".xwd" => "image/x-xwindowdump", |
| - ".css" => "text/css", |
| - ".html" => "text/html", |
| - ".htm" => "text/html", |
| - ".js" => "text/javascript", |
| - ".asc" => "text/plain", |
| - ".c" => "text/plain", |
| - ".cpp" => "text/plain", |
| - ".log" => "text/plain", |
| - ".conf" => "text/plain", |
| - ".text" => "text/plain", |
| - ".txt" => "text/plain", |
| - ".dtd" => "text/xml", |
| - ".xml" => "text/xml", |
| - ".mpeg" => "video/mpeg", |
| - ".mpg" => "video/mpeg", |
| - ".mov" => "video/quicktime", |
| - ".qt" => "video/quicktime", |
| - ".avi" => "video/x-msvideo", |
| - ".asf" => "video/x-ms-asf", |
| - ".asx" => "video/x-ms-asf", |
| - ".wmv" => "video/x-ms-wmv", |
| - ".bz2" => "application/x-bzip", |
| - ".tbz" => "application/x-bzip-compressed-tar", |
| - ".tar.bz2" => "application/x-bzip-compressed-tar", |
| - "" => "text/plain" |
| -); |
| - |
| -my \$app = builder { |
| - # to be able to override \$SIG{__WARN__} to log build time warnings |
| - use CGI::Carp; # it sets \$SIG{__WARN__} itself |
| - |
| - my \$logdir = "$fqgitdir/gitweb/$httpd_only"; |
| - open my \$access_log_fh, '>>', "\$logdir/access.log" |
| - or die "Couldn't open access log '\$logdir/access.log': \$!"; |
| - open my \$error_log_fh, '>>', "\$logdir/error.log" |
| - or die "Couldn't open error log '\$logdir/error.log': \$!"; |
| - |
| - \$access_log_fh->autoflush(1); |
| - \$error_log_fh->autoflush(1); |
| - |
| - # redirect build time warnings to error.log |
| - \$SIG{'__WARN__'} = sub { |
| - my \$msg = shift; |
| - # timestamp warning like in CGI::Carp::warn |
| - my \$stamp = CGI::Carp::stamp(); |
| - \$msg =~ s/^/\$stamp/gm; |
| - print \$error_log_fh \$msg; |
| - }; |
| - |
| - # write errors to error.log, access to access.log |
| - enable 'AccessLog', |
| - format => "combined", |
| - logger => sub { print \$access_log_fh @_; }; |
| - enable sub { |
| - my \$app = shift; |
| - sub { |
| - my \$env = shift; |
| - \$env->{'psgi.errors'} = \$error_log_fh; |
| - \$app->(\$env); |
| - } |
| - }; |
| - # gitweb currently doesn't work with $SIG{CHLD} set to 'IGNORE', |
| - # because it uses 'close $fd or die...' on piped filehandle $fh |
| - # (which causes the parent process to wait for child to finish). |
| - enable_if { \$SIG{'CHLD'} eq 'IGNORE' } sub { |
| - my \$app = shift; |
| - sub { |
| - my \$env = shift; |
| - local \$SIG{'CHLD'} = 'DEFAULT'; |
| - local \$SIG{'CLD'} = 'DEFAULT'; |
| - \$app->(\$env); |
| - } |
| - }; |
| - # serve static files, i.e. stylesheet, images, script |
| - enable 'Static', |
| - path => sub { m!\.(js|css|png)\$! && s!^/gitweb/!! }, |
| - root => "$root/", |
| - encoding => 'utf-8'; # encoding for 'text/plain' files |
| - # convert CGI application to PSGI app |
| - Plack::App::WrapCGI->new(script => "$root/gitweb.cgi")->to_app; |
| -}; |
| - |
| -# make it runnable as standalone app, |
| -# like it would be run via 'plackup' utility |
| -if (__FILE__ eq \$0) { |
| - require Plack::Runner; |
| - |
| - my \$runner = Plack::Runner->new(); |
| - \$runner->parse_options(qw(--env deployment --port $port), |
| - "$local" ? qw(--host 127.0.0.1) : ()); |
| - \$runner->run(\$app); |
| -} |
| -__END__ |
| -EOF |
| |
| - chmod a+x "$fqgitdir/gitweb/gitweb.psgi" |
| - # configuration is embedded in server script file, gitweb.psgi |
| - rm -f "$conf" |
| +script=' |
| +s#^(my|our) \$projectroot =.*#$1 \$projectroot = "'$(dirname "$fqgitdir")'";#; |
| +s#(my|our) \$gitbin =.*#$1 \$gitbin = "'$GIT_EXEC_PATH'";#; |
| +s#(my|our) \$projects_list =.*#$1 \$projects_list = \$projectroot;#; |
| +s#(my|our) \$git_temp =.*#$1 \$git_temp = "'$fqgitdir/gitweb/tmp'";#;' |
| + |
| +gitweb_cgi () { |
| + cat > "$1.tmp" <<\EOFGITWEB |
| +@@GITWEB_CGI@@ |
| +EOFGITWEB |
| + # Use the configured full path to perl to match the generated |
| + # scripts' 'hashpling' line |
| + "$PERL" -p -e "$script" "$1.tmp" > "$1" |
| + chmod +x "$1" |
| + rm -f "$1.tmp" |
| } |
| |
| -gitweb_conf() { |
| - cat > "$fqgitdir/gitweb/gitweb_config.perl" <<EOF |
| -#!/usr/bin/perl |
| -our \$projectroot = "$(dirname "$fqgitdir")"; |
| -our \$git_temp = "$fqgitdir/gitweb/tmp"; |
| -our \$projects_list = \$projectroot; |
| -EOF |
| +gitweb_css () { |
| + cat > "$1" <<\EOFGITWEB |
| +@@GITWEB_CSS@@ |
| + |
| +EOFGITWEB |
| } |
| |
| -gitweb_conf |
| +gitweb_js () { |
| + cat > "$1" <<\EOFGITWEB |
| +@@GITWEB_JS@@ |
| |
| -resolve_full_httpd |
| -mkdir -p "$fqgitdir/gitweb/$httpd_only" |
| +EOFGITWEB |
| +} |
| + |
| +gitweb_cgi "$GIT_DIR/gitweb/gitweb.cgi" |
| +gitweb_css "$GIT_DIR/@@GITWEB_CSS_NAME@@" |
| +gitweb_js "$GIT_DIR/@@GITWEB_JS_NAME@@" |
| |
| case "$httpd" in |
| *lighttpd*) |
| @@ -581,9 +431,6 @@ webrick) |
| *mongoose*) |
| mongoose_conf |
| ;; |
| -*plackup*) |
| - plackup_conf |
| - ;; |
| *) |
| echo "Unknown httpd specified: $httpd" |
| exit 1 |
| @@ -594,7 +441,7 @@ start_httpd |
| url=http://127.0.0.1:$port |
| |
| if test -n "$browser"; then |
| - httpd_is_ready && git web--browse -b "$browser" $url || echo $url |
| + git web--browse -b "$browser" $url || echo $url |
| else |
| - httpd_is_ready && git web--browse -c "instaweb.browser" $url || echo $url |
| + git web--browse -c "instaweb.browser" $url || echo $url |
| fi |
| diff --git a/gitweb/INSTALL b/gitweb/INSTALL |
| index 8230531..d484d76 100644 |
| --- a/gitweb/INSTALL |
| +++ b/gitweb/INSTALL |
| @@ -2,10 +2,9 @@ GIT web Interface (gitweb) Installation |
| ======================================= |
| |
| First you have to generate gitweb.cgi from gitweb.perl using |
| -"make gitweb", then "make install-gitweb" appropriate files |
| -(gitweb.cgi, gitweb.js, gitweb.css, git-logo.png and git-favicon.png) |
| -to their destination. For example if git was (or is) installed with |
| -/usr prefix and gitwebdir is /var/www/cgi-bin, you can do |
| +"make gitweb", then copy appropriate files (gitweb.cgi, gitweb.js, |
| +gitweb.css, git-logo.png and git-favicon.png) to their destination. |
| +For example if git was (or is) installed with /usr prefix, you can do |
| |
| $ make prefix=/usr gitweb ;# as yourself |
| # make gitwebdir=/var/www/cgi-bin install-gitweb ;# as root |
| @@ -82,14 +81,16 @@ Build example |
| minifiers, you can do |
| |
| make GITWEB_PROJECTROOT="/home/local/scm" \ |
| - GITWEB_JS="gitweb/static/gitweb.js" \ |
| - GITWEB_CSS="gitweb/static/gitweb.css" \ |
| - GITWEB_LOGO="gitweb/static/git-logo.png" \ |
| - GITWEB_FAVICON="gitweb/static/git-favicon.png" \ |
| + GITWEB_JS="/gitweb/gitweb.js" \ |
| + GITWEB_CSS="/gitweb/gitweb.css" \ |
| + GITWEB_LOGO="/gitweb/git-logo.png" \ |
| + GITWEB_FAVICON="/gitweb/git-favicon.png" \ |
| bindir=/usr/local/bin \ |
| gitweb |
| |
| - make gitwebdir=/var/www/cgi-bin/gitweb install-gitweb |
| + cp -fv gitweb/gitweb.{cgi,js,css} \ |
| + gitweb/git-{favicon,logo}.png \ |
| + /var/www/cgi-bin/gitweb/ |
| |
| |
| Gitweb config file |
| diff --git a/gitweb/Makefile b/gitweb/Makefile |
| index 2fb7c2d..d9e3629 100644 |
| --- a/gitweb/Makefile |
| +++ b/gitweb/Makefile |
| @@ -4,10 +4,10 @@ all:: |
| # Define V=1 to have a more verbose compile. |
| # |
| # Define JSMIN to point to JavaScript minifier that functions as |
| -# a filter to have static/gitweb.js minified. |
| +# a filter to have gitweb.js minified. |
| # |
| # Define CSSMIN to point to a CSS minifier in order to generate a minified |
| -# version of static/gitweb.css |
| +# version of gitweb.css |
| # |
| |
| prefix ?= $(HOME) |
| @@ -29,10 +29,10 @@ GITWEB_STRICT_EXPORT = |
| GITWEB_BASE_URL = |
| GITWEB_LIST = |
| GITWEB_HOMETEXT = indextext.html |
| -GITWEB_CSS = static/gitweb.css |
| -GITWEB_LOGO = static/git-logo.png |
| -GITWEB_FAVICON = static/git-favicon.png |
| -GITWEB_JS = static/gitweb.js |
| +GITWEB_CSS = gitweb.css |
| +GITWEB_LOGO = git-logo.png |
| +GITWEB_FAVICON = git-favicon.png |
| +GITWEB_JS = gitweb.js |
| GITWEB_SITE_HEADER = |
| GITWEB_SITE_FOOTER = |
| |
| @@ -54,7 +54,6 @@ PERL_PATH ?= /usr/bin/perl |
| # Shell quote; |
| bindir_SQ = $(subst ','\'',$(bindir))#' |
| gitwebdir_SQ = $(subst ','\'',$(gitwebdir))#' |
| -gitwebstaticdir_SQ = $(subst ','\'',$(gitwebdir)/static)#' |
| SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))#' |
| PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))#' |
| DESTDIR_SQ = $(subst ','\'',$(DESTDIR))#' |
| @@ -89,26 +88,26 @@ all:: gitweb.cgi |
| GITWEB_PROGRAMS = gitweb.cgi |
| |
| ifdef JSMIN |
| -GITWEB_FILES += static/gitweb.min.js |
| -GITWEB_JS = static/gitweb.min.js |
| -all:: static/gitweb.min.js |
| -static/gitweb.min.js: static/gitweb.js GITWEB-BUILD-OPTIONS |
| +GITWEB_FILES += gitweb.min.js |
| +GITWEB_JS = gitweb.min.js |
| +all:: gitweb.min.js |
| +gitweb.min.js: gitweb.js GITWEB-BUILD-OPTIONS |
| $(QUIET_GEN)$(JSMIN) <$< >$@ |
| else |
| -GITWEB_FILES += static/gitweb.js |
| +GITWEB_FILES += gitweb.js |
| endif |
| |
| ifdef CSSMIN |
| -GITWEB_FILES += static/gitweb.min.css |
| -GITWEB_CSS = static/gitweb.min.css |
| -all:: static/gitweb.min.css |
| -static/gitweb.min.css: static/gitweb.css GITWEB-BUILD-OPTIONS |
| +GITWEB_FILES += gitweb.min.css |
| +GITWEB_CSS = gitweb.min.css |
| +all:: gitweb.min.css |
| +gitweb.min.css: gitweb.css GITWEB-BUILD-OPTIONS |
| $(QUIET_GEN)$(CSSMIN) <$< >$@ |
| else |
| -GITWEB_FILES += static/gitweb.css |
| +GITWEB_FILES += gitweb.css |
| endif |
| |
| -GITWEB_FILES += static/git-logo.png static/git-favicon.png |
| +GITWEB_FILES += git-logo.png git-favicon.png |
| |
| GITWEB_REPLACE = \ |
| -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \ |
| @@ -148,13 +147,12 @@ gitweb.cgi: gitweb.perl GITWEB-BUILD-OPTIONS |
| install: all |
| $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitwebdir_SQ)' |
| $(INSTALL) -m 755 $(GITWEB_PROGRAMS) '$(DESTDIR_SQ)$(gitwebdir_SQ)' |
| - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitwebstaticdir_SQ)' |
| - $(INSTALL) -m 644 $(GITWEB_FILES) '$(DESTDIR_SQ)$(gitwebstaticdir_SQ)' |
| + $(INSTALL) -m 644 $(GITWEB_FILES) '$(DESTDIR_SQ)$(gitwebdir_SQ)' |
| |
| ### Cleaning rules |
| |
| clean: |
| - $(RM) gitweb.cgi static/gitweb.min.js static/gitweb.min.css GITWEB-BUILD-OPTIONS |
| + $(RM) gitweb.cgi gitweb.min.js gitweb.min.css GITWEB-BUILD-OPTIONS |
| |
| .PHONY: all clean install .FORCE-GIT-VERSION-FILE FORCE |
| |
| diff --git a/gitweb/README b/gitweb/README |
| index d481198..692b525 100644 |
| --- a/gitweb/README |
| +++ b/gitweb/README |
| @@ -80,26 +80,24 @@ You can specify the following configuration variables when building GIT: |
| Points to the location where you put gitweb.css on your web server |
| (or to be more generic, the URI of gitweb stylesheet). Relative to the |
| base URI of gitweb. Note that you can setup multiple stylesheets from |
| - the gitweb config file. [Default: static/gitweb.css (or |
| - static/gitweb.min.css if the CSSMIN variable is defined / CSS minifier |
| - is used)] |
| + the gitweb config file. [Default: gitweb.css (or gitweb.min.css if the |
| + CSSMIN variable is defined / CSS minifier is used)] |
| * GITWEB_LOGO |
| Points to the location where you put git-logo.png on your web server |
| (or to be more generic URI of logo, 72x27 size, displayed in top right |
| corner of each gitweb page, and used as logo for Atom feed). Relative |
| - to base URI of gitweb. [Default: static/git-logo.png] |
| + to base URI of gitweb. [Default: git-logo.png] |
| * GITWEB_FAVICON |
| Points to the location where you put git-favicon.png on your web server |
| (or to be more generic URI of favicon, assumed to be image/png type; |
| web browsers that support favicons (website icons) may display them |
| in the browser's URL bar and next to site name in bookmarks). Relative |
| - to base URI of gitweb. [Default: static/git-favicon.png] |
| + to base URI of gitweb. [Default: git-favicon.png] |
| * GITWEB_JS |
| Points to the location where you put gitweb.js on your web server |
| (or to be more generic URI of JavaScript code used by gitweb). |
| - Relative to base URI of gitweb. [Default: static/gitweb.js (or |
| - static/gitweb.min.js if JSMIN build variable is defined / JavaScript |
| - minifier is used)] |
| + Relative to base URI of gitweb. [Default: gitweb.js (or gitweb.min.js |
| + if JSMIN build variable is defined / JavaScript minifier is used)] |
| * GITWEB_CONFIG |
| This Perl file will be loaded using 'do' and can be used to override any |
| of the options above as well as some other options -- see the "Runtime |
| diff --git a/gitweb/git-favicon.png b/gitweb/git-favicon.png |
| new file mode 100644 |
| index 0000000..aae35a7 |
| --- /dev/null |
| +++ b/gitweb/git-favicon.png |
| @@ -0,0 +1,3 @@ |
| +PNG
|
| + |
| +
IHDRbò PLTEÀÿÿÿü|%IDAT×cXØ&[º2+ajjdsQµÄ#[Éov¡IEND®B` |
| \ No newline at end of file |
| diff --git a/gitweb/git-logo.png b/gitweb/git-logo.png |
| new file mode 100644 |
| index 0000000..f4ede2e |
| --- /dev/null |
| +++ b/gitweb/git-logo.png |
| @@ -0,0 +1,4 @@ |
| +PNG
|
| + |
| +
IHDRHè)9,PLTEÿÿÿ``]°¯ªÎÍÇÀèèæ÷÷ö§GrIDATxÚíÑ |
| + C¯wKÿÿK4tàC!EɦI$-è4
ÁÑÑVè²NTC0mFBëÑ)yV»6×PhS'jjÜêiÏWqDÌ×_ÿ´Hô"F
'<péÈG ÞSIEND®B` |
| \ No newline at end of file |
| diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css |
| new file mode 100644 |
| index 0000000..4132aab |
| --- /dev/null |
| +++ b/gitweb/gitweb.css |
| @@ -0,0 +1,592 @@ |
| +body { |
| + font-family: sans-serif; |
| + font-size: small; |
| + border: solid #d9d8d1; |
| + border-width: 1px; |
| + margin: 10px; |
| + background-color: #ffffff; |
| + color: #000000; |
| +} |
| + |
| +a { |
| + color: #0000cc; |
| +} |
| + |
| +a:hover, a:visited, a:active { |
| + color: #880000; |
| +} |
| + |
| +span.cntrl { |
| + border: dashed #aaaaaa; |
| + border-width: 1px; |
| + padding: 0px 2px 0px 2px; |
| + margin: 0px 2px 0px 2px; |
| +} |
| + |
| +img.logo { |
| + float: right; |
| + border-width: 0px; |
| +} |
| + |
| +img.avatar { |
| + vertical-align: middle; |
| +} |
| + |
| +a.list img.avatar { |
| + border-style: none; |
| +} |
| + |
| +div.page_header { |
| + height: 25px; |
| + padding: 8px; |
| + font-size: 150%; |
| + font-weight: bold; |
| + background-color: #d9d8d1; |
| +} |
| + |
| +div.page_header a:visited, a.header { |
| + color: #0000cc; |
| +} |
| + |
| +div.page_header a:hover { |
| + color: #880000; |
| +} |
| + |
| +div.page_nav { |
| + padding: 8px; |
| +} |
| + |
| +div.page_nav a:visited { |
| + color: #0000cc; |
| +} |
| + |
| +div.page_path { |
| + padding: 8px; |
| + font-weight: bold; |
| + border: solid #d9d8d1; |
| + border-width: 0px 0px 1px; |
| +} |
| + |
| +div.page_footer { |
| + height: 17px; |
| + padding: 4px 8px; |
| + background-color: #d9d8d1; |
| +} |
| + |
| +div.page_footer_text { |
| + float: left; |
| + color: #555555; |
| + font-style: italic; |
| +} |
| + |
| +div#generating_info { |
| + margin: 4px; |
| + font-size: smaller; |
| + text-align: center; |
| + color: #505050; |
| +} |
| + |
| +div.page_body { |
| + padding: 8px; |
| + font-family: monospace; |
| +} |
| + |
| +div.title, a.title { |
| + display: block; |
| + padding: 6px 8px; |
| + font-weight: bold; |
| + background-color: #edece6; |
| + text-decoration: none; |
| + color: #000000; |
| +} |
| + |
| +div.readme { |
| + padding: 8px; |
| +} |
| + |
| +a.title:hover { |
| + background-color: #d9d8d1; |
| +} |
| + |
| +div.title_text { |
| + padding: 6px 0px; |
| + border: solid #d9d8d1; |
| + border-width: 0px 0px 1px; |
| + font-family: monospace; |
| +} |
| + |
| +div.log_body { |
| + padding: 8px 8px 8px 150px; |
| +} |
| + |
| +span.age { |
| + position: relative; |
| + float: left; |
| + width: 142px; |
| + font-style: italic; |
| +} |
| + |
| +span.signoff { |
| + color: #888888; |
| +} |
| + |
| +div.log_link { |
| + padding: 0px 8px; |
| + font-size: 70%; |
| + font-family: sans-serif; |
| + font-style: normal; |
| + position: relative; |
| + float: left; |
| + width: 136px; |
| +} |
| + |
| +div.list_head { |
| + padding: 6px 8px 4px; |
| + border: solid #d9d8d1; |
| + border-width: 1px 0px 0px; |
| + font-style: italic; |
| +} |
| + |
| +.author_date, .author { |
| + font-style: italic; |
| +} |
| + |
| +div.author_date { |
| + padding: 8px; |
| + border: solid #d9d8d1; |
| + border-width: 0px 0px 1px 0px; |
| +} |
| + |
| +a.list { |
| + text-decoration: none; |
| + color: #000000; |
| +} |
| + |
| +a.subject, a.name { |
| + font-weight: bold; |
| +} |
| + |
| +table.tags a.subject { |
| + font-weight: normal; |
| +} |
| + |
| +a.list:hover { |
| + text-decoration: underline; |
| + color: #880000; |
| +} |
| + |
| +a.text { |
| + text-decoration: none; |
| + color: #0000cc; |
| +} |
| + |
| +a.text:visited { |
| + text-decoration: none; |
| + color: #880000; |
| +} |
| + |
| +a.text:hover { |
| + text-decoration: underline; |
| + color: #880000; |
| +} |
| + |
| +table { |
| + padding: 8px 4px; |
| + border-spacing: 0; |
| +} |
| + |
| +table.diff_tree { |
| + font-family: monospace; |
| +} |
| + |
| +table.combined.diff_tree th { |
| + text-align: center; |
| +} |
| + |
| +table.combined.diff_tree td { |
| + padding-right: 24px; |
| +} |
| + |
| +table.combined.diff_tree th.link, |
| +table.combined.diff_tree td.link { |
| + padding: 0px 2px; |
| +} |
| + |
| +table.combined.diff_tree td.nochange a { |
| + color: #6666ff; |
| +} |
| + |
| +table.combined.diff_tree td.nochange a:hover, |
| +table.combined.diff_tree td.nochange a:visited { |
| + color: #d06666; |
| +} |
| + |
| +table.blame { |
| + border-collapse: collapse; |
| +} |
| + |
| +table.blame td { |
| + padding: 0px 5px; |
| + font-size: 100%; |
| + vertical-align: top; |
| +} |
| + |
| +th { |
| + padding: 2px 5px; |
| + font-size: 100%; |
| + text-align: left; |
| +} |
| + |
| +/* do not change row style on hover for 'blame' view */ |
| +tr.light, |
| +table.blame .light:hover { |
| + background-color: #ffffff; |
| +} |
| + |
| +tr.dark, |
| +table.blame .dark:hover { |
| + background-color: #f6f6f0; |
| +} |
| + |
| +/* currently both use the same, but it can change */ |
| +tr.light:hover, |
| +tr.dark:hover { |
| + background-color: #edece6; |
| +} |
| + |
| +/* boundary commits in 'blame' view */ |
| +/* and commits without "previous" */ |
| +tr.boundary td.sha1, |
| +tr.no-previous td.linenr { |
| + font-weight: bold; |
| +} |
| + |
| +/* for 'blame_incremental', during processing */ |
| +tr.color1 { background-color: #f6fff6; } |
| +tr.color2 { background-color: #f6f6ff; } |
| +tr.color3 { background-color: #fff6f6; } |
| + |
| +td { |
| + padding: 2px 5px; |
| + font-size: 100%; |
| + vertical-align: top; |
| +} |
| + |
| +td.link, td.selflink { |
| + padding: 2px 5px; |
| + font-family: sans-serif; |
| + font-size: 70%; |
| +} |
| + |
| +td.selflink { |
| + padding-right: 0px; |
| +} |
| + |
| +td.sha1 { |
| + font-family: monospace; |
| +} |
| + |
| +.error { |
| + color: red; |
| + background-color: yellow; |
| +} |
| + |
| +td.current_head { |
| + text-decoration: underline; |
| +} |
| + |
| +table.diff_tree span.file_status.new { |
| + color: #008000; |
| +} |
| + |
| +table.diff_tree span.file_status.deleted { |
| + color: #c00000; |
| +} |
| + |
| +table.diff_tree span.file_status.moved, |
| +table.diff_tree span.file_status.mode_chnge { |
| + color: #777777; |
| +} |
| + |
| +table.diff_tree span.file_status.copied { |
| + color: #70a070; |
| +} |
| + |
| +/* noage: "No commits" */ |
| +table.project_list td.noage { |
| + color: #808080; |
| + font-style: italic; |
| +} |
| + |
| +/* age2: 60*60*24*2 <= age */ |
| +table.project_list td.age2, table.blame td.age2 { |
| + font-style: italic; |
| +} |
| + |
| +/* age1: 60*60*2 <= age < 60*60*24*2 */ |
| +table.project_list td.age1 { |
| + color: #009900; |
| + font-style: italic; |
| +} |
| + |
| +table.blame td.age1 { |
| + color: #009900; |
| + background: transparent; |
| +} |
| + |
| +/* age0: age < 60*60*2 */ |
| +table.project_list td.age0 { |
| + color: #009900; |
| + font-style: italic; |
| + font-weight: bold; |
| +} |
| + |
| +table.blame td.age0 { |
| + color: #009900; |
| + background: transparent; |
| + font-weight: bold; |
| +} |
| + |
| +td.pre, div.pre, div.diff { |
| + font-family: monospace; |
| + font-size: 12px; |
| + white-space: pre; |
| +} |
| + |
| +td.mode { |
| + font-family: monospace; |
| +} |
| + |
| +/* progress of blame_interactive */ |
| +div#progress_bar { |
| + height: 2px; |
| + margin-bottom: -2px; |
| + background-color: #d8d9d0; |
| +} |
| +div#progress_info { |
| + float: right; |
| + text-align: right; |
| +} |
| + |
| +/* format of (optional) objects size in 'tree' view */ |
| +td.size { |
| + font-family: monospace; |
| + text-align: right; |
| +} |
| + |
| +/* styling of diffs (patchsets): commitdiff and blobdiff views */ |
| +div.diff.header, |
| +div.diff.extended_header { |
| + white-space: normal; |
| +} |
| + |
| +div.diff.header { |
| + font-weight: bold; |
| + |
| + background-color: #edece6; |
| + |
| + margin-top: 4px; |
| + padding: 4px 0px 2px 0px; |
| + border: solid #d9d8d1; |
| + border-width: 1px 0px 1px 0px; |
| +} |
| + |
| +div.diff.header a.path { |
| + text-decoration: underline; |
| +} |
| + |
| +div.diff.extended_header, |
| +div.diff.extended_header a.path, |
| +div.diff.extended_header a.hash { |
| + color: #777777; |
| +} |
| + |
| +div.diff.extended_header .info { |
| + color: #b0b0b0; |
| +} |
| + |
| +div.diff.extended_header { |
| + background-color: #f6f5ee; |
| + padding: 2px 0px 2px 0px; |
| +} |
| + |
| +div.diff a.list, |
| +div.diff a.path, |
| +div.diff a.hash { |
| + text-decoration: none; |
| +} |
| + |
| +div.diff a.list:hover, |
| +div.diff a.path:hover, |
| +div.diff a.hash:hover { |
| + text-decoration: underline; |
| +} |
| + |
| +div.diff.to_file a.path, |
| +div.diff.to_file { |
| + color: #007000; |
| +} |
| + |
| +div.diff.add { |
| + color: #008800; |
| +} |
| + |
| +div.diff.from_file a.path, |
| +div.diff.from_file { |
| + color: #aa0000; |
| +} |
| + |
| +div.diff.rem { |
| + color: #cc0000; |
| +} |
| + |
| +div.diff.chunk_header a, |
| +div.diff.chunk_header { |
| + color: #990099; |
| +} |
| + |
| +div.diff.chunk_header { |
| + border: dotted #ffe0ff; |
| + border-width: 1px 0px 0px 0px; |
| + margin-top: 2px; |
| +} |
| + |
| +div.diff.chunk_header span.chunk_info { |
| + background-color: #ffeeff; |
| +} |
| + |
| +div.diff.chunk_header span.section { |
| + color: #aa22aa; |
| +} |
| + |
| +div.diff.incomplete { |
| + color: #cccccc; |
| +} |
| + |
| +div.diff.nodifferences { |
| + font-weight: bold; |
| + color: #600000; |
| +} |
| + |
| +div.index_include { |
| + border: solid #d9d8d1; |
| + border-width: 0px 0px 1px; |
| + padding: 12px 8px; |
| +} |
| + |
| +div.search { |
| + font-size: 100%; |
| + font-weight: normal; |
| + margin: 4px 8px; |
| + float: right; |
| + top: 56px; |
| + right: 12px |
| +} |
| + |
| +p.projsearch { |
| + text-align: center; |
| +} |
| + |
| +td.linenr { |
| + text-align: right; |
| +} |
| + |
| +a.linenr { |
| + color: #999999; |
| + text-decoration: none |
| +} |
| + |
| +a.rss_logo { |
| + float: right; |
| + padding: 3px 0px; |
| + width: 35px; |
| + line-height: 10px; |
| + border: 1px solid; |
| + border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e; |
| + color: #ffffff; |
| + background-color: #ff6600; |
| + font-weight: bold; |
| + font-family: sans-serif; |
| + font-size: 70%; |
| + text-align: center; |
| + text-decoration: none; |
| +} |
| + |
| +a.rss_logo:hover { |
| + background-color: #ee5500; |
| +} |
| + |
| +a.rss_logo.generic { |
| + background-color: #ff8800; |
| +} |
| + |
| +a.rss_logo.generic:hover { |
| + background-color: #ee7700; |
| +} |
| + |
| +span.refs span { |
| + padding: 0px 4px; |
| + font-size: 70%; |
| + font-weight: normal; |
| + border: 1px solid; |
| + background-color: #ffaaff; |
| + border-color: #ffccff #ff00ee #ff00ee #ffccff; |
| +} |
| + |
| +span.refs span a { |
| + text-decoration: none; |
| + color: inherit; |
| +} |
| + |
| +span.refs span a:hover { |
| + text-decoration: underline; |
| +} |
| + |
| +span.refs span.indirect { |
| + font-style: italic; |
| +} |
| + |
| +span.refs span.ref { |
| + background-color: #aaaaff; |
| + border-color: #ccccff #0033cc #0033cc #ccccff; |
| +} |
| + |
| +span.refs span.tag { |
| + background-color: #ffffaa; |
| + border-color: #ffffcc #ffee00 #ffee00 #ffffcc; |
| +} |
| + |
| +span.refs span.head { |
| + background-color: #aaffaa; |
| + border-color: #ccffcc #00cc33 #00cc33 #ccffcc; |
| +} |
| + |
| +span.atnight { |
| + color: #cc0000; |
| +} |
| + |
| +span.match { |
| + color: #e00000; |
| +} |
| + |
| +div.binary { |
| + font-style: italic; |
| +} |
| + |
| +/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */ |
| + |
| +/* Highlighting theme definition: */ |
| + |
| +.num { color:#2928ff; } |
| +.esc { color:#ff00ff; } |
| +.str { color:#ff0000; } |
| +.dstr { color:#818100; } |
| +.slc { color:#838183; font-style:italic; } |
| +.com { color:#838183; font-style:italic; } |
| +.dir { color:#008200; } |
| +.sym { color:#000000; } |
| +.line { color:#555555; } |
| +.kwa { color:#000000; font-weight:bold; } |
| +.kwb { color:#830000; } |
| +.kwc { color:#000000; font-weight:bold; } |
| +.kwd { color:#010181; } |
| diff --git a/gitweb/gitweb.js b/gitweb/gitweb.js |
| new file mode 100644 |
| index 0000000..9c66928 |
| --- /dev/null |
| +++ b/gitweb/gitweb.js |
| @@ -0,0 +1,875 @@ |
| +// Copyright (C) 2007, Fredrik Kuivinen <frekui@gmail.com> |
| +// 2007, Petr Baudis <pasky@suse.cz> |
| +// 2008-2009, Jakub Narebski <jnareb@gmail.com> |
| + |
| +/** |
| + * @fileOverview JavaScript code for gitweb (git web interface). |
| + * @license GPLv2 or later |
| + */ |
| + |
| +/* ============================================================ */ |
| +/* functions for generic gitweb actions and views */ |
| + |
| +/** |
| + * used to check if link has 'js' query parameter already (at end), |
| + * and other reasons to not add 'js=1' param at the end of link |
| + * @constant |
| + */ |
| +var jsExceptionsRe = /[;?]js=[01]$/; |
| + |
| +/** |
| + * Add '?js=1' or ';js=1' to the end of every link in the document |
| + * that doesn't have 'js' query parameter set already. |
| + * |
| + * Links with 'js=1' lead to JavaScript version of given action, if it |
| + * exists (currently there is only 'blame_incremental' for 'blame') |
| + * |
| + * @globals jsExceptionsRe |
| + */ |
| +function fixLinks() { |
| + var allLinks = document.getElementsByTagName("a") || document.links; |
| + for (var i = 0, len = allLinks.length; i < len; i++) { |
| + var link = allLinks[i]; |
| + if (!jsExceptionsRe.test(link)) { // =~ /[;?]js=[01]$/; |
| + link.href += |
| + (link.href.indexOf('?') === -1 ? '?' : ';') + 'js=1'; |
| + } |
| + } |
| +} |
| + |
| + |
| +/* ============================================================ */ |
| + |
| +/* |
| + * This code uses DOM methods instead of (nonstandard) innerHTML |
| + * to modify page. |
| + * |
| + * innerHTML is non-standard IE extension, though supported by most |
| + * browsers; however Firefox up to version 1.5 didn't implement it in |
| + * a strict mode (application/xml+xhtml mimetype). |
| + * |
| + * Also my simple benchmarks show that using elem.firstChild.data = |
| + * 'content' is slightly faster than elem.innerHTML = 'content'. It |
| + * is however more fragile (text element fragment must exists), and |
| + * less feature-rich (we cannot add HTML). |
| + * |
| + * Note that DOM 2 HTML is preferred over generic DOM 2 Core; the |
| + * equivalent using DOM 2 Core is usually shown in comments. |
| + */ |
| + |
| + |
| +/* ============================================================ */ |
| +/* generic utility functions */ |
| + |
| + |
| +/** |
| + * pad number N with nonbreakable spaces on the left, to WIDTH characters |
| + * example: padLeftStr(12, 3, '\u00A0') == '\u00A012' |
| + * ('\u00A0' is nonbreakable space) |
| + * |
| + * @param {Number|String} input: number to pad |
| + * @param {Number} width: visible width of output |
| + * @param {String} str: string to prefix to string, e.g. '\u00A0' |
| + * @returns {String} INPUT prefixed with (WIDTH - INPUT.length) x STR |
| + */ |
| +function padLeftStr(input, width, str) { |
| + var prefix = ''; |
| + |
| + width -= input.toString().length; |
| + while (width > 0) { |
| + prefix += str; |
| + width--; |
| + } |
| + return prefix + input; |
| +} |
| + |
| +/** |
| + * Pad INPUT on the left to SIZE width, using given padding character CH, |
| + * for example padLeft('a', 3, '_') is '__a'. |
| + * |
| + * @param {String} input: input value converted to string. |
| + * @param {Number} width: desired length of output. |
| + * @param {String} ch: single character to prefix to string. |
| + * |
| + * @returns {String} Modified string, at least SIZE length. |
| + */ |
| +function padLeft(input, width, ch) { |
| + var s = input + ""; |
| + while (s.length < width) { |
| + s = ch + s; |
| + } |
| + return s; |
| +} |
| + |
| +/** |
| + * Create XMLHttpRequest object in cross-browser way |
| + * @returns XMLHttpRequest object, or null |
| + */ |
| +function createRequestObject() { |
| + try { |
| + return new XMLHttpRequest(); |
| + } catch (e) {} |
| + try { |
| + return window.createRequest(); |
| + } catch (e) {} |
| + try { |
| + return new ActiveXObject("Msxml2.XMLHTTP"); |
| + } catch (e) {} |
| + try { |
| + return new ActiveXObject("Microsoft.XMLHTTP"); |
| + } catch (e) {} |
| + |
| + return null; |
| +} |
| + |
| + |
| +/* ============================================================ */ |
| +/* utility/helper functions (and variables) */ |
| + |
| +var xhr; // XMLHttpRequest object |
| +var projectUrl; // partial query + separator ('?' or ';') |
| + |
| +// 'commits' is an associative map. It maps SHA1s to Commit objects. |
| +var commits = {}; |
| + |
| +/** |
| + * constructor for Commit objects, used in 'blame' |
| + * @class Represents a blamed commit |
| + * @param {String} sha1: SHA-1 identifier of a commit |
| + */ |
| +function Commit(sha1) { |
| + if (this instanceof Commit) { |
| + this.sha1 = sha1; |
| + this.nprevious = 0; /* number of 'previous', effective parents */ |
| + } else { |
| + return new Commit(sha1); |
| + } |
| +} |
| + |
| +/* ............................................................ */ |
| +/* progress info, timing, error reporting */ |
| + |
| +var blamedLines = 0; |
| +var totalLines = '???'; |
| +var div_progress_bar; |
| +var div_progress_info; |
| + |
| +/** |
| + * Detects how many lines does a blamed file have, |
| + * This information is used in progress info |
| + * |
| + * @returns {Number|String} Number of lines in file, or string '...' |
| + */ |
| +function countLines() { |
| + var table = |
| + document.getElementById('blame_table') || |
| + document.getElementsByTagName('table')[0]; |
| + |
| + if (table) { |
| + return table.getElementsByTagName('tr').length - 1; // for header |
| + } else { |
| + return '...'; |
| + } |
| +} |
| + |
| +/** |
| + * update progress info and length (width) of progress bar |
| + * |
| + * @globals div_progress_info, div_progress_bar, blamedLines, totalLines |
| + */ |
| +function updateProgressInfo() { |
| + if (!div_progress_info) { |
| + div_progress_info = document.getElementById('progress_info'); |
| + } |
| + if (!div_progress_bar) { |
| + div_progress_bar = document.getElementById('progress_bar'); |
| + } |
| + if (!div_progress_info && !div_progress_bar) { |
| + return; |
| + } |
| + |
| + var percentage = Math.floor(100.0*blamedLines/totalLines); |
| + |
| + if (div_progress_info) { |
| + div_progress_info.firstChild.data = blamedLines + ' / ' + totalLines + |
| + ' (' + padLeftStr(percentage, 3, '\u00A0') + '%)'; |
| + } |
| + |
| + if (div_progress_bar) { |
| + //div_progress_bar.setAttribute('style', 'width: '+percentage+'%;'); |
| + div_progress_bar.style.width = percentage + '%'; |
| + } |
| +} |
| + |
| + |
| +var t_interval_server = ''; |
| +var cmds_server = ''; |
| +var t0 = new Date(); |
| + |
| +/** |
| + * write how much it took to generate data, and to run script |
| + * |
| + * @globals t0, t_interval_server, cmds_server |
| + */ |
| +function writeTimeInterval() { |
| + var info_time = document.getElementById('generating_time'); |
| + if (!info_time || !t_interval_server) { |
| + return; |
| + } |
| + var t1 = new Date(); |
| + info_time.firstChild.data += ' + (' + |
| + t_interval_server + ' sec server blame_data / ' + |
| + (t1.getTime() - t0.getTime())/1000 + ' sec client JavaScript)'; |
| + |
| + var info_cmds = document.getElementById('generating_cmd'); |
| + if (!info_time || !cmds_server) { |
| + return; |
| + } |
| + info_cmds.firstChild.data += ' + ' + cmds_server; |
| +} |
| + |
| +/** |
| + * show an error message alert to user within page (in prohress info area) |
| + * @param {String} str: plain text error message (no HTML) |
| + * |
| + * @globals div_progress_info |
| + */ |
| +function errorInfo(str) { |
| + if (!div_progress_info) { |
| + div_progress_info = document.getElementById('progress_info'); |
| + } |
| + if (div_progress_info) { |
| + div_progress_info.className = 'error'; |
| + div_progress_info.firstChild.data = str; |
| + } |
| +} |
| + |
| +/* ............................................................ */ |
| +/* coloring rows during blame_data (git blame --incremental) run */ |
| + |
| +/** |
| + * used to extract N from 'colorN', where N is a number, |
| + * @constant |
| + */ |
| +var colorRe = /\bcolor([0-9]*)\b/; |
| + |
| +/** |
| + * return N if <tr class="colorN">, otherwise return null |
| + * (some browsers require CSS class names to begin with letter) |
| + * |
| + * @param {HTMLElement} tr: table row element to check |
| + * @param {String} tr.className: 'class' attribute of tr element |
| + * @returns {Number|null} N if tr.className == 'colorN', otherwise null |
| + * |
| + * @globals colorRe |
| + */ |
| +function getColorNo(tr) { |
| + if (!tr) { |
| + return null; |
| + } |
| + var className = tr.className; |
| + if (className) { |
| + var match = colorRe.exec(className); |
| + if (match) { |
| + return parseInt(match[1], 10); |
| + } |
| + } |
| + return null; |
| +} |
| + |
| +var colorsFreq = [0, 0, 0]; |
| +/** |
| + * return one of given possible colors (curently least used one) |
| + * example: chooseColorNoFrom(2, 3) returns 2 or 3 |
| + * |
| + * @param {Number[]} arguments: one or more numbers |
| + * assumes that 1 <= arguments[i] <= colorsFreq.length |
| + * @returns {Number} Least used color number from arguments |
| + * @globals colorsFreq |
| + */ |
| +function chooseColorNoFrom() { |
| + // choose the color which is least used |
| + var colorNo = arguments[0]; |
| + for (var i = 1; i < arguments.length; i++) { |
| + if (colorsFreq[arguments[i]-1] < colorsFreq[colorNo-1]) { |
| + colorNo = arguments[i]; |
| + } |
| + } |
| + colorsFreq[colorNo-1]++; |
| + return colorNo; |
| +} |
| + |
| +/** |
| + * given two neigbour <tr> elements, find color which would be different |
| + * from color of both of neighbours; used to 3-color blame table |
| + * |
| + * @param {HTMLElement} tr_prev |
| + * @param {HTMLElement} tr_next |
| + * @returns {Number} color number N such that |
| + * colorN != tr_prev.className && colorN != tr_next.className |
| + */ |
| +function findColorNo(tr_prev, tr_next) { |
| + var color_prev = getColorNo(tr_prev); |
| + var color_next = getColorNo(tr_next); |
| + |
| + |
| + // neither of neighbours has color set |
| + // THEN we can use any of 3 possible colors |
| + if (!color_prev && !color_next) { |
| + return chooseColorNoFrom(1,2,3); |
| + } |
| + |
| + // either both neighbours have the same color, |
| + // or only one of neighbours have color set |
| + // THEN we can use any color except given |
| + var color; |
| + if (color_prev === color_next) { |
| + color = color_prev; // = color_next; |
| + } else if (!color_prev) { |
| + color = color_next; |
| + } else if (!color_next) { |
| + color = color_prev; |
| + } |
| + if (color) { |
| + return chooseColorNoFrom((color % 3) + 1, ((color+1) % 3) + 1); |
| + } |
| + |
| + // neighbours have different colors |
| + // THEN there is only one color left |
| + return (3 - ((color_prev + color_next) % 3)); |
| +} |
| + |
| +/* ............................................................ */ |
| +/* coloring rows like 'blame' after 'blame_data' finishes */ |
| + |
| +/** |
| + * returns true if given row element (tr) is first in commit group |
| + * to be used only after 'blame_data' finishes (after processing) |
| + * |
| + * @param {HTMLElement} tr: table row |
| + * @returns {Boolean} true if TR is first in commit group |
| + */ |
| +function isStartOfGroup(tr) { |
| + return tr.firstChild.className === 'sha1'; |
| +} |
| + |
| +/** |
| + * change colors to use zebra coloring (2 colors) instead of 3 colors |
| + * concatenate neighbour commit groups belonging to the same commit |
| + * |
| + * @globals colorRe |
| + */ |
| +function fixColorsAndGroups() { |
| + var colorClasses = ['light', 'dark']; |
| + var linenum = 1; |
| + var tr, prev_group; |
| + var colorClass = 0; |
| + var table = |
| + document.getElementById('blame_table') || |
| + document.getElementsByTagName('table')[0]; |
| + |
| + while ((tr = document.getElementById('l'+linenum))) { |
| + // index origin is 0, which is table header; start from 1 |
| + //while ((tr = table.rows[linenum])) { // <- it is slower |
| + if (isStartOfGroup(tr, linenum, document)) { |
| + if (prev_group && |
| + prev_group.firstChild.firstChild.href === |
| + tr.firstChild.firstChild.href) { |
| + // we have to concatenate groups |
| + var prev_rows = prev_group.firstChild.rowSpan || 1; |
| + var curr_rows = tr.firstChild.rowSpan || 1; |
| + prev_group.firstChild.rowSpan = prev_rows + curr_rows; |
| + //tr.removeChild(tr.firstChild); |
| + tr.deleteCell(0); // DOM2 HTML way |
| + } else { |
| + colorClass = (colorClass + 1) % 2; |
| + prev_group = tr; |
| + } |
| + } |
| + var tr_class = tr.className; |
| + tr.className = tr_class.replace(colorRe, colorClasses[colorClass]); |
| + linenum++; |
| + } |
| +} |
| + |
| +/* ............................................................ */ |
| +/* time and data */ |
| + |
| +/** |
| + * used to extract hours and minutes from timezone info, e.g '-0900' |
| + * @constant |
| + */ |
| +var tzRe = /^([+-][0-9][0-9])([0-9][0-9])$/; |
| + |
| +/** |
| + * return date in local time formatted in iso-8601 like format |
| + * 'yyyy-mm-dd HH:MM:SS +/-ZZZZ' e.g. '2005-08-07 21:49:46 +0200' |
| + * |
| + * @param {Number} epoch: seconds since '00:00:00 1970-01-01 UTC' |
| + * @param {String} timezoneInfo: numeric timezone '(+|-)HHMM' |
| + * @returns {String} date in local time in iso-8601 like format |
| + * |
| + * @globals tzRe |
| + */ |
| +function formatDateISOLocal(epoch, timezoneInfo) { |
| + var match = tzRe.exec(timezoneInfo); |
| + // date corrected by timezone |
| + var localDate = new Date(1000 * (epoch + |
| + (parseInt(match[1],10)*3600 + parseInt(match[2],10)*60))); |
| + var localDateStr = // e.g. '2005-08-07' |
| + localDate.getUTCFullYear() + '-' + |
| + padLeft(localDate.getUTCMonth()+1, 2, '0') + '-' + |
| + padLeft(localDate.getUTCDate(), 2, '0'); |
| + var localTimeStr = // e.g. '21:49:46' |
| + padLeft(localDate.getUTCHours(), 2, '0') + ':' + |
| + padLeft(localDate.getUTCMinutes(), 2, '0') + ':' + |
| + padLeft(localDate.getUTCSeconds(), 2, '0'); |
| + |
| + return localDateStr + ' ' + localTimeStr + ' ' + timezoneInfo; |
| +} |
| + |
| +/* ............................................................ */ |
| +/* unquoting/unescaping filenames */ |
| + |
| +/**#@+ |
| + * @constant |
| + */ |
| +var escCodeRe = /\\([^0-7]|[0-7]{1,3})/g; |
| +var octEscRe = /^[0-7]{1,3}$/; |
| +var maybeQuotedRe = /^\"(.*)\"$/; |
| +/**#@-*/ |
| + |
| +/** |
| + * unquote maybe git-quoted filename |
| + * e.g. 'aa' -> 'aa', '"a\ta"' -> 'a a' |
| + * |
| + * @param {String} str: git-quoted string |
| + * @returns {String} Unquoted and unescaped string |
| + * |
| + * @globals escCodeRe, octEscRe, maybeQuotedRe |
| + */ |
| +function unquote(str) { |
| + function unq(seq) { |
| + var es = { |
| + // character escape codes, aka escape sequences (from C) |
| + // replacements are to some extent JavaScript specific |
| + t: "\t", // tab (HT, TAB) |
| + n: "\n", // newline (NL) |
| + r: "\r", // return (CR) |
| + f: "\f", // form feed (FF) |
| + b: "\b", // backspace (BS) |
| + a: "\x07", // alarm (bell) (BEL) |
| + e: "\x1B", // escape (ESC) |
| + v: "\v" // vertical tab (VT) |
| + }; |
| + |
| + if (seq.search(octEscRe) !== -1) { |
| + // octal char sequence |
| + return String.fromCharCode(parseInt(seq, 8)); |
| + } else if (seq in es) { |
| + // C escape sequence, aka character escape code |
| + return es[seq]; |
| + } |
| + // quoted ordinary character |
| + return seq; |
| + } |
| + |
| + var match = str.match(maybeQuotedRe); |
| + if (match) { |
| + str = match[1]; |
| + // perhaps str = eval('"'+str+'"'); would be enough? |
| + str = str.replace(escCodeRe, |
| + function (substr, p1, offset, s) { return unq(p1); }); |
| + } |
| + return str; |
| +} |
| + |
| +/* ============================================================ */ |
| +/* main part: parsing response */ |
| + |
| +/** |
| + * Function called for each blame entry, as soon as it finishes. |
| + * It updates page via DOM manipulation, adding sha1 info, etc. |
| + * |
| + * @param {Commit} commit: blamed commit |
| + * @param {Object} group: object representing group of lines, |
| + * which blame the same commit (blame entry) |
| + * |
| + * @globals blamedLines |
| + */ |
| +function handleLine(commit, group) { |
| + /* |
| + This is the structure of the HTML fragment we are working |
| + with: |
| + |
| + <tr id="l123" class=""> |
| + <td class="sha1" title=""><a href=""> </a></td> |
| + <td class="linenr"><a class="linenr" href="">123</a></td> |
| + <td class="pre"># times (my ext3 doesn't).</td> |
| + </tr> |
| + */ |
| + |
| + var resline = group.resline; |
| + |
| + // format date and time string only once per commit |
| + if (!commit.info) { |
| + /* e.g. 'Kay Sievers, 2005-08-07 21:49:46 +0200' */ |
| + commit.info = commit.author + ', ' + |
| + formatDateISOLocal(commit.authorTime, commit.authorTimezone); |
| + } |
| + |
| + // color depends on group of lines, not only on blamed commit |
| + var colorNo = findColorNo( |
| + document.getElementById('l'+(resline-1)), |
| + document.getElementById('l'+(resline+group.numlines)) |
| + ); |
| + |
| + // loop over lines in commit group |
| + for (var i = 0; i < group.numlines; i++, resline++) { |
| + var tr = document.getElementById('l'+resline); |
| + if (!tr) { |
| + break; |
| + } |
| + /* |
| + <tr id="l123" class=""> |
| + <td class="sha1" title=""><a href=""> </a></td> |
| + <td class="linenr"><a class="linenr" href="">123</a></td> |
| + <td class="pre"># times (my ext3 doesn't).</td> |
| + </tr> |
| + */ |
| + var td_sha1 = tr.firstChild; |
| + var a_sha1 = td_sha1.firstChild; |
| + var a_linenr = td_sha1.nextSibling.firstChild; |
| + |
| + /* <tr id="l123" class=""> */ |
| + var tr_class = ''; |
| + if (colorNo !== null) { |
| + tr_class = 'color'+colorNo; |
| + } |
| + if (commit.boundary) { |
| + tr_class += ' boundary'; |
| + } |
| + if (commit.nprevious === 0) { |
| + tr_class += ' no-previous'; |
| + } else if (commit.nprevious > 1) { |
| + tr_class += ' multiple-previous'; |
| + } |
| + tr.className = tr_class; |
| + |
| + /* <td class="sha1" title="?" rowspan="?"><a href="?">?</a></td> */ |
| + if (i === 0) { |
| + td_sha1.title = commit.info; |
| + td_sha1.rowSpan = group.numlines; |
| + |
| + a_sha1.href = projectUrl + 'a=commit;h=' + commit.sha1; |
| + if (a_sha1.firstChild) { |
| + a_sha1.firstChild.data = commit.sha1.substr(0, 8); |
| + } else { |
| + a_sha1.appendChild( |
| + document.createTextNode(commit.sha1.substr(0, 8))); |
| + } |
| + if (group.numlines >= 2) { |
| + var fragment = document.createDocumentFragment(); |
| + var br = document.createElement("br"); |
| + var match = commit.author.match(/\b([A-Z])\B/g); |
| + if (match) { |
| + var text = document.createTextNode( |
| + match.join('')); |
| + } |
| + if (br && text) { |
| + var elem = fragment || td_sha1; |
| + elem.appendChild(br); |
| + elem.appendChild(text); |
| + if (fragment) { |
| + td_sha1.appendChild(fragment); |
| + } |
| + } |
| + } |
| + } else { |
| + //tr.removeChild(td_sha1); // DOM2 Core way |
| + tr.deleteCell(0); // DOM2 HTML way |
| + } |
| + |
| + /* <td class="linenr"><a class="linenr" href="?">123</a></td> */ |
| + var linenr_commit = |
| + ('previous' in commit ? commit.previous : commit.sha1); |
| + var linenr_filename = |
| + ('file_parent' in commit ? commit.file_parent : commit.filename); |
| + a_linenr.href = projectUrl + 'a=blame_incremental' + |
| + ';hb=' + linenr_commit + |
| + ';f=' + encodeURIComponent(linenr_filename) + |
| + '#l' + (group.srcline + i); |
| + |
| + blamedLines++; |
| + |
| + //updateProgressInfo(); |
| + } |
| +} |
| + |
| +// ---------------------------------------------------------------------- |
| + |
| +var inProgress = false; // are we processing response |
| + |
| +/**#@+ |
| + * @constant |
| + */ |
| +var sha1Re = /^([0-9a-f]{40}) ([0-9]+) ([0-9]+) ([0-9]+)/; |
| +var infoRe = /^([a-z-]+) ?(.*)/; |
| +var endRe = /^END ?([^ ]*) ?(.*)/; |
| +/**@-*/ |
| + |
| +var curCommit = new Commit(); |
| +var curGroup = {}; |
| + |
| +var pollTimer = null; |
| + |
| +/** |
| + * Parse output from 'git blame --incremental [...]', received via |
| + * XMLHttpRequest from server (blamedataUrl), and call handleLine |
| + * (which updates page) as soon as blame entry is completed. |
| + * |
| + * @param {String[]} lines: new complete lines from blamedata server |
| + * |
| + * @globals commits, curCommit, curGroup, t_interval_server, cmds_server |
| + * @globals sha1Re, infoRe, endRe |
| + */ |
| +function processBlameLines(lines) { |
| + var match; |
| + |
| + for (var i = 0, len = lines.length; i < len; i++) { |
| + |
| + if ((match = sha1Re.exec(lines[i]))) { |
| + var sha1 = match[1]; |
| + var srcline = parseInt(match[2], 10); |
| + var resline = parseInt(match[3], 10); |
| + var numlines = parseInt(match[4], 10); |
| + |
| + var c = commits[sha1]; |
| + if (!c) { |
| + c = new Commit(sha1); |
| + commits[sha1] = c; |
| + } |
| + curCommit = c; |
| + |
| + curGroup.srcline = srcline; |
| + curGroup.resline = resline; |
| + curGroup.numlines = numlines; |
| + |
| + } else if ((match = infoRe.exec(lines[i]))) { |
| + var info = match[1]; |
| + var data = match[2]; |
| + switch (info) { |
| + case 'filename': |
| + curCommit.filename = unquote(data); |
| + // 'filename' information terminates the entry |
| + handleLine(curCommit, curGroup); |
| + updateProgressInfo(); |
| + break; |
| + case 'author': |
| + curCommit.author = data; |
| + break; |
| + case 'author-time': |
| + curCommit.authorTime = parseInt(data, 10); |
| + break; |
| + case 'author-tz': |
| + curCommit.authorTimezone = data; |
| + break; |
| + case 'previous': |
| + curCommit.nprevious++; |
| + // store only first 'previous' header |
| + if (!'previous' in curCommit) { |
| + var parts = data.split(' ', 2); |
| + curCommit.previous = parts[0]; |
| + curCommit.file_parent = unquote(parts[1]); |
| + } |
| + break; |
| + case 'boundary': |
| + curCommit.boundary = true; |
| + break; |
| + } // end switch |
| + |
| + } else if ((match = endRe.exec(lines[i]))) { |
| + t_interval_server = match[1]; |
| + cmds_server = match[2]; |
| + |
| + } else if (lines[i] !== '') { |
| + // malformed line |
| + |
| + } // end if (match) |
| + |
| + } // end for (lines) |
| +} |
| + |
| +/** |
| + * Process new data and return pointer to end of processed part |
| + * |
| + * @param {String} unprocessed: new data (from nextReadPos) |
| + * @param {Number} nextReadPos: end of last processed data |
| + * @return {Number} end of processed data (new value for nextReadPos) |
| + */ |
| +function processData(unprocessed, nextReadPos) { |
| + var lastLineEnd = unprocessed.lastIndexOf('\n'); |
| + if (lastLineEnd !== -1) { |
| + var lines = unprocessed.substring(0, lastLineEnd).split('\n'); |
| + nextReadPos += lastLineEnd + 1 /* 1 == '\n'.length */; |
| + |
| + processBlameLines(lines); |
| + } // end if |
| + |
| + return nextReadPos; |
| +} |
| + |
| +/** |
| + * Handle XMLHttpRequest errors |
| + * |
| + * @param {XMLHttpRequest} xhr: XMLHttpRequest object |
| + * |
| + * @globals pollTimer, commits, inProgress |
| + */ |
| +function handleError(xhr) { |
| + errorInfo('Server error: ' + |
| + xhr.status + ' - ' + (xhr.statusText || 'Error contacting server')); |
| + |
| + clearInterval(pollTimer); |
| + commits = {}; // free memory |
| + |
| + inProgress = false; |
| +} |
| + |
| +/** |
| + * Called after XMLHttpRequest finishes (loads) |
| + * |
| + * @param {XMLHttpRequest} xhr: XMLHttpRequest object (unused) |
| + * |
| + * @globals pollTimer, commits, inProgress |
| + */ |
| +function responseLoaded(xhr) { |
| + clearInterval(pollTimer); |
| + |
| + fixColorsAndGroups(); |
| + writeTimeInterval(); |
| + commits = {}; // free memory |
| + |
| + inProgress = false; |
| +} |
| + |
| +/** |
| + * handler for XMLHttpRequest onreadystatechange event |
| + * @see startBlame |
| + * |
| + * @globals xhr, inProgress |
| + */ |
| +function handleResponse() { |
| + |
| + /* |
| + * xhr.readyState |
| + * |
| + * Value Constant (W3C) Description |
| + * ------------------------------------------------------------------- |
| + * 0 UNSENT open() has not been called yet. |
| + * 1 OPENED send() has not been called yet. |
| + * 2 HEADERS_RECEIVED send() has been called, and headers |
| + * and status are available. |
| + * 3 LOADING Downloading; responseText holds partial data. |
| + * 4 DONE The operation is complete. |
| + */ |
| + |
| + if (xhr.readyState !== 4 && xhr.readyState !== 3) { |
| + return; |
| + } |
| + |
| + // the server returned error |
| + // try ... catch block is to work around bug in IE8 |
| + try { |
| + if (xhr.readyState === 3 && xhr.status !== 200) { |
| + return; |
| + } |
| + } catch (e) { |
| + return; |
| + } |
| + if (xhr.readyState === 4 && xhr.status !== 200) { |
| + handleError(xhr); |
| + return; |
| + } |
| + |
| + // In konqueror xhr.responseText is sometimes null here... |
| + if (xhr.responseText === null) { |
| + return; |
| + } |
| + |
| + // in case we were called before finished processing |
| + if (inProgress) { |
| + return; |
| + } else { |
| + inProgress = true; |
| + } |
| + |
| + // extract new whole (complete) lines, and process them |
| + while (xhr.prevDataLength !== xhr.responseText.length) { |
| + if (xhr.readyState === 4 && |
| + xhr.prevDataLength === xhr.responseText.length) { |
| + break; |
| + } |
| + |
| + xhr.prevDataLength = xhr.responseText.length; |
| + var unprocessed = xhr.responseText.substring(xhr.nextReadPos); |
| + xhr.nextReadPos = processData(unprocessed, xhr.nextReadPos); |
| + } // end while |
| + |
| + // did we finish work? |
| + if (xhr.readyState === 4 && |
| + xhr.prevDataLength === xhr.responseText.length) { |
| + responseLoaded(xhr); |
| + } |
| + |
| + inProgress = false; |
| +} |
| + |
| +// ============================================================ |
| +// ------------------------------------------------------------ |
| + |
| +/** |
| + * Incrementally update line data in blame_incremental view in gitweb. |
| + * |
| + * @param {String} blamedataUrl: URL to server script generating blame data. |
| + * @param {String} bUrl: partial URL to project, used to generate links. |
| + * |
| + * Called from 'blame_incremental' view after loading table with |
| + * file contents, a base for blame view. |
| + * |
| + * @globals xhr, t0, projectUrl, div_progress_bar, totalLines, pollTimer |
| +*/ |
| +function startBlame(blamedataUrl, bUrl) { |
| + |
| + xhr = createRequestObject(); |
| + if (!xhr) { |
| + errorInfo('ERROR: XMLHttpRequest not supported'); |
| + return; |
| + } |
| + |
| + t0 = new Date(); |
| + projectUrl = bUrl + (bUrl.indexOf('?') === -1 ? '?' : ';'); |
| + if ((div_progress_bar = document.getElementById('progress_bar'))) { |
| + //div_progress_bar.setAttribute('style', 'width: 100%;'); |
| + div_progress_bar.style.cssText = 'width: 100%;'; |
| + } |
| + totalLines = countLines(); |
| + updateProgressInfo(); |
| + |
| + /* add extra properties to xhr object to help processing response */ |
| + xhr.prevDataLength = -1; // used to detect if we have new data |
| + xhr.nextReadPos = 0; // where unread part of response starts |
| + |
| + xhr.onreadystatechange = handleResponse; |
| + //xhr.onreadystatechange = function () { handleResponse(xhr); }; |
| + |
| + xhr.open('GET', blamedataUrl); |
| + xhr.setRequestHeader('Accept', 'text/plain'); |
| + xhr.send(null); |
| + |
| + // not all browsers call onreadystatechange event on each server flush |
| + // poll response using timer every second to handle this issue |
| + pollTimer = setInterval(xhr.onreadystatechange, 1000); |
| +} |
| + |
| +// end of gitweb.js |
| diff --git a/gitweb/static/git-favicon.png b/gitweb/static/git-favicon.png |
| deleted file mode 100644 |
| index aae35a7..0000000 |
| --- a/gitweb/static/git-favicon.png |
| +++ /dev/null |
| @@ -1,3 +0,0 @@ |
| -PNG
|
| - |
| -
IHDRbò PLTEÀÿÿÿü|%IDAT×cXØ&[º2+ajjdsQµÄ#[Éov¡IEND®B` |
| \ No newline at end of file |
| diff --git a/gitweb/static/git-logo.png b/gitweb/static/git-logo.png |
| deleted file mode 100644 |
| index f4ede2e..0000000 |
| --- a/gitweb/static/git-logo.png |
| +++ /dev/null |
| @@ -1,4 +0,0 @@ |
| -PNG
|
| - |
| -
IHDRHè)9,PLTEÿÿÿ``]°¯ªÎÍÇÀèèæ÷÷ö§GrIDATxÚíÑ |
| - C¯wKÿÿK4tàC!EɦI$-è4
ÁÑÑVè²NTC0mFBëÑ)yV»6×PhS'jjÜêiÏWqDÌ×_ÿ´Hô"F
'<péÈG ÞSIEND®B` |
| \ No newline at end of file |
| diff --git a/gitweb/static/gitweb.css b/gitweb/static/gitweb.css |
| deleted file mode 100644 |
| index 4132aab..0000000 |
| --- a/gitweb/static/gitweb.css |
| +++ /dev/null |
| @@ -1,592 +0,0 @@ |
| -body { |
| - font-family: sans-serif; |
| - font-size: small; |
| - border: solid #d9d8d1; |
| - border-width: 1px; |
| - margin: 10px; |
| - background-color: #ffffff; |
| - color: #000000; |
| -} |
| - |
| -a { |
| - color: #0000cc; |
| -} |
| - |
| -a:hover, a:visited, a:active { |
| - color: #880000; |
| -} |
| - |
| -span.cntrl { |
| - border: dashed #aaaaaa; |
| - border-width: 1px; |
| - padding: 0px 2px 0px 2px; |
| - margin: 0px 2px 0px 2px; |
| -} |
| - |
| -img.logo { |
| - float: right; |
| - border-width: 0px; |
| -} |
| - |
| -img.avatar { |
| - vertical-align: middle; |
| -} |
| - |
| -a.list img.avatar { |
| - border-style: none; |
| -} |
| - |
| -div.page_header { |
| - height: 25px; |
| - padding: 8px; |
| - font-size: 150%; |
| - font-weight: bold; |
| - background-color: #d9d8d1; |
| -} |
| - |
| -div.page_header a:visited, a.header { |
| - color: #0000cc; |
| -} |
| - |
| -div.page_header a:hover { |
| - color: #880000; |
| -} |
| - |
| -div.page_nav { |
| - padding: 8px; |
| -} |
| - |
| -div.page_nav a:visited { |
| - color: #0000cc; |
| -} |
| - |
| -div.page_path { |
| - padding: 8px; |
| - font-weight: bold; |
| - border: solid #d9d8d1; |
| - border-width: 0px 0px 1px; |
| -} |
| - |
| -div.page_footer { |
| - height: 17px; |
| - padding: 4px 8px; |
| - background-color: #d9d8d1; |
| -} |
| - |
| -div.page_footer_text { |
| - float: left; |
| - color: #555555; |
| - font-style: italic; |
| -} |
| - |
| -div#generating_info { |
| - margin: 4px; |
| - font-size: smaller; |
| - text-align: center; |
| - color: #505050; |
| -} |
| - |
| -div.page_body { |
| - padding: 8px; |
| - font-family: monospace; |
| -} |
| - |
| -div.title, a.title { |
| - display: block; |
| - padding: 6px 8px; |
| - font-weight: bold; |
| - background-color: #edece6; |
| - text-decoration: none; |
| - color: #000000; |
| -} |
| - |
| -div.readme { |
| - padding: 8px; |
| -} |
| - |
| -a.title:hover { |
| - background-color: #d9d8d1; |
| -} |
| - |
| -div.title_text { |
| - padding: 6px 0px; |
| - border: solid #d9d8d1; |
| - border-width: 0px 0px 1px; |
| - font-family: monospace; |
| -} |
| - |
| -div.log_body { |
| - padding: 8px 8px 8px 150px; |
| -} |
| - |
| -span.age { |
| - position: relative; |
| - float: left; |
| - width: 142px; |
| - font-style: italic; |
| -} |
| - |
| -span.signoff { |
| - color: #888888; |
| -} |
| - |
| -div.log_link { |
| - padding: 0px 8px; |
| - font-size: 70%; |
| - font-family: sans-serif; |
| - font-style: normal; |
| - position: relative; |
| - float: left; |
| - width: 136px; |
| -} |
| - |
| -div.list_head { |
| - padding: 6px 8px 4px; |
| - border: solid #d9d8d1; |
| - border-width: 1px 0px 0px; |
| - font-style: italic; |
| -} |
| - |
| -.author_date, .author { |
| - font-style: italic; |
| -} |
| - |
| -div.author_date { |
| - padding: 8px; |
| - border: solid #d9d8d1; |
| - border-width: 0px 0px 1px 0px; |
| -} |
| - |
| -a.list { |
| - text-decoration: none; |
| - color: #000000; |
| -} |
| - |
| -a.subject, a.name { |
| - font-weight: bold; |
| -} |
| - |
| -table.tags a.subject { |
| - font-weight: normal; |
| -} |
| - |
| -a.list:hover { |
| - text-decoration: underline; |
| - color: #880000; |
| -} |
| - |
| -a.text { |
| - text-decoration: none; |
| - color: #0000cc; |
| -} |
| - |
| -a.text:visited { |
| - text-decoration: none; |
| - color: #880000; |
| -} |
| - |
| -a.text:hover { |
| - text-decoration: underline; |
| - color: #880000; |
| -} |
| - |
| -table { |
| - padding: 8px 4px; |
| - border-spacing: 0; |
| -} |
| - |
| -table.diff_tree { |
| - font-family: monospace; |
| -} |
| - |
| -table.combined.diff_tree th { |
| - text-align: center; |
| -} |
| - |
| -table.combined.diff_tree td { |
| - padding-right: 24px; |
| -} |
| - |
| -table.combined.diff_tree th.link, |
| -table.combined.diff_tree td.link { |
| - padding: 0px 2px; |
| -} |
| - |
| -table.combined.diff_tree td.nochange a { |
| - color: #6666ff; |
| -} |
| - |
| -table.combined.diff_tree td.nochange a:hover, |
| -table.combined.diff_tree td.nochange a:visited { |
| - color: #d06666; |
| -} |
| - |
| -table.blame { |
| - border-collapse: collapse; |
| -} |
| - |
| -table.blame td { |
| - padding: 0px 5px; |
| - font-size: 100%; |
| - vertical-align: top; |
| -} |
| - |
| -th { |
| - padding: 2px 5px; |
| - font-size: 100%; |
| - text-align: left; |
| -} |
| - |
| -/* do not change row style on hover for 'blame' view */ |
| -tr.light, |
| -table.blame .light:hover { |
| - background-color: #ffffff; |
| -} |
| - |
| -tr.dark, |
| -table.blame .dark:hover { |
| - background-color: #f6f6f0; |
| -} |
| - |
| -/* currently both use the same, but it can change */ |
| -tr.light:hover, |
| -tr.dark:hover { |
| - background-color: #edece6; |
| -} |
| - |
| -/* boundary commits in 'blame' view */ |
| -/* and commits without "previous" */ |
| -tr.boundary td.sha1, |
| -tr.no-previous td.linenr { |
| - font-weight: bold; |
| -} |
| - |
| -/* for 'blame_incremental', during processing */ |
| -tr.color1 { background-color: #f6fff6; } |
| -tr.color2 { background-color: #f6f6ff; } |
| -tr.color3 { background-color: #fff6f6; } |
| - |
| -td { |
| - padding: 2px 5px; |
| - font-size: 100%; |
| - vertical-align: top; |
| -} |
| - |
| -td.link, td.selflink { |
| - padding: 2px 5px; |
| - font-family: sans-serif; |
| - font-size: 70%; |
| -} |
| - |
| -td.selflink { |
| - padding-right: 0px; |
| -} |
| - |
| -td.sha1 { |
| - font-family: monospace; |
| -} |
| - |
| -.error { |
| - color: red; |
| - background-color: yellow; |
| -} |
| - |
| -td.current_head { |
| - text-decoration: underline; |
| -} |
| - |
| -table.diff_tree span.file_status.new { |
| - color: #008000; |
| -} |
| - |
| -table.diff_tree span.file_status.deleted { |
| - color: #c00000; |
| -} |
| - |
| -table.diff_tree span.file_status.moved, |
| -table.diff_tree span.file_status.mode_chnge { |
| - color: #777777; |
| -} |
| - |
| -table.diff_tree span.file_status.copied { |
| - color: #70a070; |
| -} |
| - |
| -/* noage: "No commits" */ |
| -table.project_list td.noage { |
| - color: #808080; |
| - font-style: italic; |
| -} |
| - |
| -/* age2: 60*60*24*2 <= age */ |
| -table.project_list td.age2, table.blame td.age2 { |
| - font-style: italic; |
| -} |
| - |
| -/* age1: 60*60*2 <= age < 60*60*24*2 */ |
| -table.project_list td.age1 { |
| - color: #009900; |
| - font-style: italic; |
| -} |
| - |
| -table.blame td.age1 { |
| - color: #009900; |
| - background: transparent; |
| -} |
| - |
| -/* age0: age < 60*60*2 */ |
| -table.project_list td.age0 { |
| - color: #009900; |
| - font-style: italic; |
| - font-weight: bold; |
| -} |
| - |
| -table.blame td.age0 { |
| - color: #009900; |
| - background: transparent; |
| - font-weight: bold; |
| -} |
| - |
| -td.pre, div.pre, div.diff { |
| - font-family: monospace; |
| - font-size: 12px; |
| - white-space: pre; |
| -} |
| - |
| -td.mode { |
| - font-family: monospace; |
| -} |
| - |
| -/* progress of blame_interactive */ |
| -div#progress_bar { |
| - height: 2px; |
| - margin-bottom: -2px; |
| - background-color: #d8d9d0; |
| -} |
| -div#progress_info { |
| - float: right; |
| - text-align: right; |
| -} |
| - |
| -/* format of (optional) objects size in 'tree' view */ |
| -td.size { |
| - font-family: monospace; |
| - text-align: right; |
| -} |
| - |
| -/* styling of diffs (patchsets): commitdiff and blobdiff views */ |
| -div.diff.header, |
| -div.diff.extended_header { |
| - white-space: normal; |
| -} |
| - |
| -div.diff.header { |
| - font-weight: bold; |
| - |
| - background-color: #edece6; |
| - |
| - margin-top: 4px; |
| - padding: 4px 0px 2px 0px; |
| - border: solid #d9d8d1; |
| - border-width: 1px 0px 1px 0px; |
| -} |
| - |
| -div.diff.header a.path { |
| - text-decoration: underline; |
| -} |
| - |
| -div.diff.extended_header, |
| -div.diff.extended_header a.path, |
| -div.diff.extended_header a.hash { |
| - color: #777777; |
| -} |
| - |
| -div.diff.extended_header .info { |
| - color: #b0b0b0; |
| -} |
| - |
| -div.diff.extended_header { |
| - background-color: #f6f5ee; |
| - padding: 2px 0px 2px 0px; |
| -} |
| - |
| -div.diff a.list, |
| -div.diff a.path, |
| -div.diff a.hash { |
| - text-decoration: none; |
| -} |
| - |
| -div.diff a.list:hover, |
| -div.diff a.path:hover, |
| -div.diff a.hash:hover { |
| - text-decoration: underline; |
| -} |
| - |
| -div.diff.to_file a.path, |
| -div.diff.to_file { |
| - color: #007000; |
| -} |
| - |
| -div.diff.add { |
| - color: #008800; |
| -} |
| - |
| -div.diff.from_file a.path, |
| -div.diff.from_file { |
| - color: #aa0000; |
| -} |
| - |
| -div.diff.rem { |
| - color: #cc0000; |
| -} |
| - |
| -div.diff.chunk_header a, |
| -div.diff.chunk_header { |
| - color: #990099; |
| -} |
| - |
| -div.diff.chunk_header { |
| - border: dotted #ffe0ff; |
| - border-width: 1px 0px 0px 0px; |
| - margin-top: 2px; |
| -} |
| - |
| -div.diff.chunk_header span.chunk_info { |
| - background-color: #ffeeff; |
| -} |
| - |
| -div.diff.chunk_header span.section { |
| - color: #aa22aa; |
| -} |
| - |
| -div.diff.incomplete { |
| - color: #cccccc; |
| -} |
| - |
| -div.diff.nodifferences { |
| - font-weight: bold; |
| - color: #600000; |
| -} |
| - |
| -div.index_include { |
| - border: solid #d9d8d1; |
| - border-width: 0px 0px 1px; |
| - padding: 12px 8px; |
| -} |
| - |
| -div.search { |
| - font-size: 100%; |
| - font-weight: normal; |
| - margin: 4px 8px; |
| - float: right; |
| - top: 56px; |
| - right: 12px |
| -} |
| - |
| -p.projsearch { |
| - text-align: center; |
| -} |
| - |
| -td.linenr { |
| - text-align: right; |
| -} |
| - |
| -a.linenr { |
| - color: #999999; |
| - text-decoration: none |
| -} |
| - |
| -a.rss_logo { |
| - float: right; |
| - padding: 3px 0px; |
| - width: 35px; |
| - line-height: 10px; |
| - border: 1px solid; |
| - border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e; |
| - color: #ffffff; |
| - background-color: #ff6600; |
| - font-weight: bold; |
| - font-family: sans-serif; |
| - font-size: 70%; |
| - text-align: center; |
| - text-decoration: none; |
| -} |
| - |
| -a.rss_logo:hover { |
| - background-color: #ee5500; |
| -} |
| - |
| -a.rss_logo.generic { |
| - background-color: #ff8800; |
| -} |
| - |
| -a.rss_logo.generic:hover { |
| - background-color: #ee7700; |
| -} |
| - |
| -span.refs span { |
| - padding: 0px 4px; |
| - font-size: 70%; |
| - font-weight: normal; |
| - border: 1px solid; |
| - background-color: #ffaaff; |
| - border-color: #ffccff #ff00ee #ff00ee #ffccff; |
| -} |
| - |
| -span.refs span a { |
| - text-decoration: none; |
| - color: inherit; |
| -} |
| - |
| -span.refs span a:hover { |
| - text-decoration: underline; |
| -} |
| - |
| -span.refs span.indirect { |
| - font-style: italic; |
| -} |
| - |
| -span.refs span.ref { |
| - background-color: #aaaaff; |
| - border-color: #ccccff #0033cc #0033cc #ccccff; |
| -} |
| - |
| -span.refs span.tag { |
| - background-color: #ffffaa; |
| - border-color: #ffffcc #ffee00 #ffee00 #ffffcc; |
| -} |
| - |
| -span.refs span.head { |
| - background-color: #aaffaa; |
| - border-color: #ccffcc #00cc33 #00cc33 #ccffcc; |
| -} |
| - |
| -span.atnight { |
| - color: #cc0000; |
| -} |
| - |
| -span.match { |
| - color: #e00000; |
| -} |
| - |
| -div.binary { |
| - font-style: italic; |
| -} |
| - |
| -/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */ |
| - |
| -/* Highlighting theme definition: */ |
| - |
| -.num { color:#2928ff; } |
| -.esc { color:#ff00ff; } |
| -.str { color:#ff0000; } |
| -.dstr { color:#818100; } |
| -.slc { color:#838183; font-style:italic; } |
| -.com { color:#838183; font-style:italic; } |
| -.dir { color:#008200; } |
| -.sym { color:#000000; } |
| -.line { color:#555555; } |
| -.kwa { color:#000000; font-weight:bold; } |
| -.kwb { color:#830000; } |
| -.kwc { color:#000000; font-weight:bold; } |
| -.kwd { color:#010181; } |
| diff --git a/gitweb/static/gitweb.js b/gitweb/static/gitweb.js |
| deleted file mode 100644 |
| index 9c66928..0000000 |
| --- a/gitweb/static/gitweb.js |
| +++ /dev/null |
| @@ -1,875 +0,0 @@ |
| -// Copyright (C) 2007, Fredrik Kuivinen <frekui@gmail.com> |
| -// 2007, Petr Baudis <pasky@suse.cz> |
| -// 2008-2009, Jakub Narebski <jnareb@gmail.com> |
| - |
| -/** |
| - * @fileOverview JavaScript code for gitweb (git web interface). |
| - * @license GPLv2 or later |
| - */ |
| - |
| -/* ============================================================ */ |
| -/* functions for generic gitweb actions and views */ |
| - |
| -/** |
| - * used to check if link has 'js' query parameter already (at end), |
| - * and other reasons to not add 'js=1' param at the end of link |
| - * @constant |
| - */ |
| -var jsExceptionsRe = /[;?]js=[01]$/; |
| - |
| -/** |
| - * Add '?js=1' or ';js=1' to the end of every link in the document |
| - * that doesn't have 'js' query parameter set already. |
| - * |
| - * Links with 'js=1' lead to JavaScript version of given action, if it |
| - * exists (currently there is only 'blame_incremental' for 'blame') |
| - * |
| - * @globals jsExceptionsRe |
| - */ |
| -function fixLinks() { |
| - var allLinks = document.getElementsByTagName("a") || document.links; |
| - for (var i = 0, len = allLinks.length; i < len; i++) { |
| - var link = allLinks[i]; |
| - if (!jsExceptionsRe.test(link)) { // =~ /[;?]js=[01]$/; |
| - link.href += |
| - (link.href.indexOf('?') === -1 ? '?' : ';') + 'js=1'; |
| - } |
| - } |
| -} |
| - |
| - |
| -/* ============================================================ */ |
| - |
| -/* |
| - * This code uses DOM methods instead of (nonstandard) innerHTML |
| - * to modify page. |
| - * |
| - * innerHTML is non-standard IE extension, though supported by most |
| - * browsers; however Firefox up to version 1.5 didn't implement it in |
| - * a strict mode (application/xml+xhtml mimetype). |
| - * |
| - * Also my simple benchmarks show that using elem.firstChild.data = |
| - * 'content' is slightly faster than elem.innerHTML = 'content'. It |
| - * is however more fragile (text element fragment must exists), and |
| - * less feature-rich (we cannot add HTML). |
| - * |
| - * Note that DOM 2 HTML is preferred over generic DOM 2 Core; the |
| - * equivalent using DOM 2 Core is usually shown in comments. |
| - */ |
| - |
| - |
| -/* ============================================================ */ |
| -/* generic utility functions */ |
| - |
| - |
| -/** |
| - * pad number N with nonbreakable spaces on the left, to WIDTH characters |
| - * example: padLeftStr(12, 3, '\u00A0') == '\u00A012' |
| - * ('\u00A0' is nonbreakable space) |
| - * |
| - * @param {Number|String} input: number to pad |
| - * @param {Number} width: visible width of output |
| - * @param {String} str: string to prefix to string, e.g. '\u00A0' |
| - * @returns {String} INPUT prefixed with (WIDTH - INPUT.length) x STR |
| - */ |
| -function padLeftStr(input, width, str) { |
| - var prefix = ''; |
| - |
| - width -= input.toString().length; |
| - while (width > 0) { |
| - prefix += str; |
| - width--; |
| - } |
| - return prefix + input; |
| -} |
| - |
| -/** |
| - * Pad INPUT on the left to SIZE width, using given padding character CH, |
| - * for example padLeft('a', 3, '_') is '__a'. |
| - * |
| - * @param {String} input: input value converted to string. |
| - * @param {Number} width: desired length of output. |
| - * @param {String} ch: single character to prefix to string. |
| - * |
| - * @returns {String} Modified string, at least SIZE length. |
| - */ |
| -function padLeft(input, width, ch) { |
| - var s = input + ""; |
| - while (s.length < width) { |
| - s = ch + s; |
| - } |
| - return s; |
| -} |
| - |
| -/** |
| - * Create XMLHttpRequest object in cross-browser way |
| - * @returns XMLHttpRequest object, or null |
| - */ |
| -function createRequestObject() { |
| - try { |
| - return new XMLHttpRequest(); |
| - } catch (e) {} |
| - try { |
| - return window.createRequest(); |
| - } catch (e) {} |
| - try { |
| - return new ActiveXObject("Msxml2.XMLHTTP"); |
| - } catch (e) {} |
| - try { |
| - return new ActiveXObject("Microsoft.XMLHTTP"); |
| - } catch (e) {} |
| - |
| - return null; |
| -} |
| - |
| - |
| -/* ============================================================ */ |
| -/* utility/helper functions (and variables) */ |
| - |
| -var xhr; // XMLHttpRequest object |
| -var projectUrl; // partial query + separator ('?' or ';') |
| - |
| -// 'commits' is an associative map. It maps SHA1s to Commit objects. |
| -var commits = {}; |
| - |
| -/** |
| - * constructor for Commit objects, used in 'blame' |
| - * @class Represents a blamed commit |
| - * @param {String} sha1: SHA-1 identifier of a commit |
| - */ |
| -function Commit(sha1) { |
| - if (this instanceof Commit) { |
| - this.sha1 = sha1; |
| - this.nprevious = 0; /* number of 'previous', effective parents */ |
| - } else { |
| - return new Commit(sha1); |
| - } |
| -} |
| - |
| -/* ............................................................ */ |
| -/* progress info, timing, error reporting */ |
| - |
| -var blamedLines = 0; |
| -var totalLines = '???'; |
| -var div_progress_bar; |
| -var div_progress_info; |
| - |
| -/** |
| - * Detects how many lines does a blamed file have, |
| - * This information is used in progress info |
| - * |
| - * @returns {Number|String} Number of lines in file, or string '...' |
| - */ |
| -function countLines() { |
| - var table = |
| - document.getElementById('blame_table') || |
| - document.getElementsByTagName('table')[0]; |
| - |
| - if (table) { |
| - return table.getElementsByTagName('tr').length - 1; // for header |
| - } else { |
| - return '...'; |
| - } |
| -} |
| - |
| -/** |
| - * update progress info and length (width) of progress bar |
| - * |
| - * @globals div_progress_info, div_progress_bar, blamedLines, totalLines |
| - */ |
| -function updateProgressInfo() { |
| - if (!div_progress_info) { |
| - div_progress_info = document.getElementById('progress_info'); |
| - } |
| - if (!div_progress_bar) { |
| - div_progress_bar = document.getElementById('progress_bar'); |
| - } |
| - if (!div_progress_info && !div_progress_bar) { |
| - return; |
| - } |
| - |
| - var percentage = Math.floor(100.0*blamedLines/totalLines); |
| - |
| - if (div_progress_info) { |
| - div_progress_info.firstChild.data = blamedLines + ' / ' + totalLines + |
| - ' (' + padLeftStr(percentage, 3, '\u00A0') + '%)'; |
| - } |
| - |
| - if (div_progress_bar) { |
| - //div_progress_bar.setAttribute('style', 'width: '+percentage+'%;'); |
| - div_progress_bar.style.width = percentage + '%'; |
| - } |
| -} |
| - |
| - |
| -var t_interval_server = ''; |
| -var cmds_server = ''; |
| -var t0 = new Date(); |
| - |
| -/** |
| - * write how much it took to generate data, and to run script |
| - * |
| - * @globals t0, t_interval_server, cmds_server |
| - */ |
| -function writeTimeInterval() { |
| - var info_time = document.getElementById('generating_time'); |
| - if (!info_time || !t_interval_server) { |
| - return; |
| - } |
| - var t1 = new Date(); |
| - info_time.firstChild.data += ' + (' + |
| - t_interval_server + ' sec server blame_data / ' + |
| - (t1.getTime() - t0.getTime())/1000 + ' sec client JavaScript)'; |
| - |
| - var info_cmds = document.getElementById('generating_cmd'); |
| - if (!info_time || !cmds_server) { |
| - return; |
| - } |
| - info_cmds.firstChild.data += ' + ' + cmds_server; |
| -} |
| - |
| -/** |
| - * show an error message alert to user within page (in prohress info area) |
| - * @param {String} str: plain text error message (no HTML) |
| - * |
| - * @globals div_progress_info |
| - */ |
| -function errorInfo(str) { |
| - if (!div_progress_info) { |
| - div_progress_info = document.getElementById('progress_info'); |
| - } |
| - if (div_progress_info) { |
| - div_progress_info.className = 'error'; |
| - div_progress_info.firstChild.data = str; |
| - } |
| -} |
| - |
| -/* ............................................................ */ |
| -/* coloring rows during blame_data (git blame --incremental) run */ |
| - |
| -/** |
| - * used to extract N from 'colorN', where N is a number, |
| - * @constant |
| - */ |
| -var colorRe = /\bcolor([0-9]*)\b/; |
| - |
| -/** |
| - * return N if <tr class="colorN">, otherwise return null |
| - * (some browsers require CSS class names to begin with letter) |
| - * |
| - * @param {HTMLElement} tr: table row element to check |
| - * @param {String} tr.className: 'class' attribute of tr element |
| - * @returns {Number|null} N if tr.className == 'colorN', otherwise null |
| - * |
| - * @globals colorRe |
| - */ |
| -function getColorNo(tr) { |
| - if (!tr) { |
| - return null; |
| - } |
| - var className = tr.className; |
| - if (className) { |
| - var match = colorRe.exec(className); |
| - if (match) { |
| - return parseInt(match[1], 10); |
| - } |
| - } |
| - return null; |
| -} |
| - |
| -var colorsFreq = [0, 0, 0]; |
| -/** |
| - * return one of given possible colors (curently least used one) |
| - * example: chooseColorNoFrom(2, 3) returns 2 or 3 |
| - * |
| - * @param {Number[]} arguments: one or more numbers |
| - * assumes that 1 <= arguments[i] <= colorsFreq.length |
| - * @returns {Number} Least used color number from arguments |
| - * @globals colorsFreq |
| - */ |
| -function chooseColorNoFrom() { |
| - // choose the color which is least used |
| - var colorNo = arguments[0]; |
| - for (var i = 1; i < arguments.length; i++) { |
| - if (colorsFreq[arguments[i]-1] < colorsFreq[colorNo-1]) { |
| - colorNo = arguments[i]; |
| - } |
| - } |
| - colorsFreq[colorNo-1]++; |
| - return colorNo; |
| -} |
| - |
| -/** |
| - * given two neigbour <tr> elements, find color which would be different |
| - * from color of both of neighbours; used to 3-color blame table |
| - * |
| - * @param {HTMLElement} tr_prev |
| - * @param {HTMLElement} tr_next |
| - * @returns {Number} color number N such that |
| - * colorN != tr_prev.className && colorN != tr_next.className |
| - */ |
| -function findColorNo(tr_prev, tr_next) { |
| - var color_prev = getColorNo(tr_prev); |
| - var color_next = getColorNo(tr_next); |
| - |
| - |
| - // neither of neighbours has color set |
| - // THEN we can use any of 3 possible colors |
| - if (!color_prev && !color_next) { |
| - return chooseColorNoFrom(1,2,3); |
| - } |
| - |
| - // either both neighbours have the same color, |
| - // or only one of neighbours have color set |
| - // THEN we can use any color except given |
| - var color; |
| - if (color_prev === color_next) { |
| - color = color_prev; // = color_next; |
| - } else if (!color_prev) { |
| - color = color_next; |
| - } else if (!color_next) { |
| - color = color_prev; |
| - } |
| - if (color) { |
| - return chooseColorNoFrom((color % 3) + 1, ((color+1) % 3) + 1); |
| - } |
| - |
| - // neighbours have different colors |
| - // THEN there is only one color left |
| - return (3 - ((color_prev + color_next) % 3)); |
| -} |
| - |
| -/* ............................................................ */ |
| -/* coloring rows like 'blame' after 'blame_data' finishes */ |
| - |
| -/** |
| - * returns true if given row element (tr) is first in commit group |
| - * to be used only after 'blame_data' finishes (after processing) |
| - * |
| - * @param {HTMLElement} tr: table row |
| - * @returns {Boolean} true if TR is first in commit group |
| - */ |
| -function isStartOfGroup(tr) { |
| - return tr.firstChild.className === 'sha1'; |
| -} |
| - |
| -/** |
| - * change colors to use zebra coloring (2 colors) instead of 3 colors |
| - * concatenate neighbour commit groups belonging to the same commit |
| - * |
| - * @globals colorRe |
| - */ |
| -function fixColorsAndGroups() { |
| - var colorClasses = ['light', 'dark']; |
| - var linenum = 1; |
| - var tr, prev_group; |
| - var colorClass = 0; |
| - var table = |
| - document.getElementById('blame_table') || |
| - document.getElementsByTagName('table')[0]; |
| - |
| - while ((tr = document.getElementById('l'+linenum))) { |
| - // index origin is 0, which is table header; start from 1 |
| - //while ((tr = table.rows[linenum])) { // <- it is slower |
| - if (isStartOfGroup(tr, linenum, document)) { |
| - if (prev_group && |
| - prev_group.firstChild.firstChild.href === |
| - tr.firstChild.firstChild.href) { |
| - // we have to concatenate groups |
| - var prev_rows = prev_group.firstChild.rowSpan || 1; |
| - var curr_rows = tr.firstChild.rowSpan || 1; |
| - prev_group.firstChild.rowSpan = prev_rows + curr_rows; |
| - //tr.removeChild(tr.firstChild); |
| - tr.deleteCell(0); // DOM2 HTML way |
| - } else { |
| - colorClass = (colorClass + 1) % 2; |
| - prev_group = tr; |
| - } |
| - } |
| - var tr_class = tr.className; |
| - tr.className = tr_class.replace(colorRe, colorClasses[colorClass]); |
| - linenum++; |
| - } |
| -} |
| - |
| -/* ............................................................ */ |
| -/* time and data */ |
| - |
| -/** |
| - * used to extract hours and minutes from timezone info, e.g '-0900' |
| - * @constant |
| - */ |
| -var tzRe = /^([+-][0-9][0-9])([0-9][0-9])$/; |
| - |
| -/** |
| - * return date in local time formatted in iso-8601 like format |
| - * 'yyyy-mm-dd HH:MM:SS +/-ZZZZ' e.g. '2005-08-07 21:49:46 +0200' |
| - * |
| - * @param {Number} epoch: seconds since '00:00:00 1970-01-01 UTC' |
| - * @param {String} timezoneInfo: numeric timezone '(+|-)HHMM' |
| - * @returns {String} date in local time in iso-8601 like format |
| - * |
| - * @globals tzRe |
| - */ |
| -function formatDateISOLocal(epoch, timezoneInfo) { |
| - var match = tzRe.exec(timezoneInfo); |
| - // date corrected by timezone |
| - var localDate = new Date(1000 * (epoch + |
| - (parseInt(match[1],10)*3600 + parseInt(match[2],10)*60))); |
| - var localDateStr = // e.g. '2005-08-07' |
| - localDate.getUTCFullYear() + '-' + |
| - padLeft(localDate.getUTCMonth()+1, 2, '0') + '-' + |
| - padLeft(localDate.getUTCDate(), 2, '0'); |
| - var localTimeStr = // e.g. '21:49:46' |
| - padLeft(localDate.getUTCHours(), 2, '0') + ':' + |
| - padLeft(localDate.getUTCMinutes(), 2, '0') + ':' + |
| - padLeft(localDate.getUTCSeconds(), 2, '0'); |
| - |
| - return localDateStr + ' ' + localTimeStr + ' ' + timezoneInfo; |
| -} |
| - |
| -/* ............................................................ */ |
| -/* unquoting/unescaping filenames */ |
| - |
| -/**#@+ |
| - * @constant |
| - */ |
| -var escCodeRe = /\\([^0-7]|[0-7]{1,3})/g; |
| -var octEscRe = /^[0-7]{1,3}$/; |
| -var maybeQuotedRe = /^\"(.*)\"$/; |
| -/**#@-*/ |
| - |
| -/** |
| - * unquote maybe git-quoted filename |
| - * e.g. 'aa' -> 'aa', '"a\ta"' -> 'a a' |
| - * |
| - * @param {String} str: git-quoted string |
| - * @returns {String} Unquoted and unescaped string |
| - * |
| - * @globals escCodeRe, octEscRe, maybeQuotedRe |
| - */ |
| -function unquote(str) { |
| - function unq(seq) { |
| - var es = { |
| - // character escape codes, aka escape sequences (from C) |
| - // replacements are to some extent JavaScript specific |
| - t: "\t", // tab (HT, TAB) |
| - n: "\n", // newline (NL) |
| - r: "\r", // return (CR) |
| - f: "\f", // form feed (FF) |
| - b: "\b", // backspace (BS) |
| - a: "\x07", // alarm (bell) (BEL) |
| - e: "\x1B", // escape (ESC) |
| - v: "\v" // vertical tab (VT) |
| - }; |
| - |
| - if (seq.search(octEscRe) !== -1) { |
| - // octal char sequence |
| - return String.fromCharCode(parseInt(seq, 8)); |
| - } else if (seq in es) { |
| - // C escape sequence, aka character escape code |
| - return es[seq]; |
| - } |
| - // quoted ordinary character |
| - return seq; |
| - } |
| - |
| - var match = str.match(maybeQuotedRe); |
| - if (match) { |
| - str = match[1]; |
| - // perhaps str = eval('"'+str+'"'); would be enough? |
| - str = str.replace(escCodeRe, |
| - function (substr, p1, offset, s) { return unq(p1); }); |
| - } |
| - return str; |
| -} |
| - |
| -/* ============================================================ */ |
| -/* main part: parsing response */ |
| - |
| -/** |
| - * Function called for each blame entry, as soon as it finishes. |
| - * It updates page via DOM manipulation, adding sha1 info, etc. |
| - * |
| - * @param {Commit} commit: blamed commit |
| - * @param {Object} group: object representing group of lines, |
| - * which blame the same commit (blame entry) |
| - * |
| - * @globals blamedLines |
| - */ |
| -function handleLine(commit, group) { |
| - /* |
| - This is the structure of the HTML fragment we are working |
| - with: |
| - |
| - <tr id="l123" class=""> |
| - <td class="sha1" title=""><a href=""> </a></td> |
| - <td class="linenr"><a class="linenr" href="">123</a></td> |
| - <td class="pre"># times (my ext3 doesn't).</td> |
| - </tr> |
| - */ |
| - |
| - var resline = group.resline; |
| - |
| - // format date and time string only once per commit |
| - if (!commit.info) { |
| - /* e.g. 'Kay Sievers, 2005-08-07 21:49:46 +0200' */ |
| - commit.info = commit.author + ', ' + |
| - formatDateISOLocal(commit.authorTime, commit.authorTimezone); |
| - } |
| - |
| - // color depends on group of lines, not only on blamed commit |
| - var colorNo = findColorNo( |
| - document.getElementById('l'+(resline-1)), |
| - document.getElementById('l'+(resline+group.numlines)) |
| - ); |
| - |
| - // loop over lines in commit group |
| - for (var i = 0; i < group.numlines; i++, resline++) { |
| - var tr = document.getElementById('l'+resline); |
| - if (!tr) { |
| - break; |
| - } |
| - /* |
| - <tr id="l123" class=""> |
| - <td class="sha1" title=""><a href=""> </a></td> |
| - <td class="linenr"><a class="linenr" href="">123</a></td> |
| - <td class="pre"># times (my ext3 doesn't).</td> |
| - </tr> |
| - */ |
| - var td_sha1 = tr.firstChild; |
| - var a_sha1 = td_sha1.firstChild; |
| - var a_linenr = td_sha1.nextSibling.firstChild; |
| - |
| - /* <tr id="l123" class=""> */ |
| - var tr_class = ''; |
| - if (colorNo !== null) { |
| - tr_class = 'color'+colorNo; |
| - } |
| - if (commit.boundary) { |
| - tr_class += ' boundary'; |
| - } |
| - if (commit.nprevious === 0) { |
| - tr_class += ' no-previous'; |
| - } else if (commit.nprevious > 1) { |
| - tr_class += ' multiple-previous'; |
| - } |
| - tr.className = tr_class; |
| - |
| - /* <td class="sha1" title="?" rowspan="?"><a href="?">?</a></td> */ |
| - if (i === 0) { |
| - td_sha1.title = commit.info; |
| - td_sha1.rowSpan = group.numlines; |
| - |
| - a_sha1.href = projectUrl + 'a=commit;h=' + commit.sha1; |
| - if (a_sha1.firstChild) { |
| - a_sha1.firstChild.data = commit.sha1.substr(0, 8); |
| - } else { |
| - a_sha1.appendChild( |
| - document.createTextNode(commit.sha1.substr(0, 8))); |
| - } |
| - if (group.numlines >= 2) { |
| - var fragment = document.createDocumentFragment(); |
| - var br = document.createElement("br"); |
| - var match = commit.author.match(/\b([A-Z])\B/g); |
| - if (match) { |
| - var text = document.createTextNode( |
| - match.join('')); |
| - } |
| - if (br && text) { |
| - var elem = fragment || td_sha1; |
| - elem.appendChild(br); |
| - elem.appendChild(text); |
| - if (fragment) { |
| - td_sha1.appendChild(fragment); |
| - } |
| - } |
| - } |
| - } else { |
| - //tr.removeChild(td_sha1); // DOM2 Core way |
| - tr.deleteCell(0); // DOM2 HTML way |
| - } |
| - |
| - /* <td class="linenr"><a class="linenr" href="?">123</a></td> */ |
| - var linenr_commit = |
| - ('previous' in commit ? commit.previous : commit.sha1); |
| - var linenr_filename = |
| - ('file_parent' in commit ? commit.file_parent : commit.filename); |
| - a_linenr.href = projectUrl + 'a=blame_incremental' + |
| - ';hb=' + linenr_commit + |
| - ';f=' + encodeURIComponent(linenr_filename) + |
| - '#l' + (group.srcline + i); |
| - |
| - blamedLines++; |
| - |
| - //updateProgressInfo(); |
| - } |
| -} |
| - |
| -// ---------------------------------------------------------------------- |
| - |
| -var inProgress = false; // are we processing response |
| - |
| -/**#@+ |
| - * @constant |
| - */ |
| -var sha1Re = /^([0-9a-f]{40}) ([0-9]+) ([0-9]+) ([0-9]+)/; |
| -var infoRe = /^([a-z-]+) ?(.*)/; |
| -var endRe = /^END ?([^ ]*) ?(.*)/; |
| -/**@-*/ |
| - |
| -var curCommit = new Commit(); |
| -var curGroup = {}; |
| - |
| -var pollTimer = null; |
| - |
| -/** |
| - * Parse output from 'git blame --incremental [...]', received via |
| - * XMLHttpRequest from server (blamedataUrl), and call handleLine |
| - * (which updates page) as soon as blame entry is completed. |
| - * |
| - * @param {String[]} lines: new complete lines from blamedata server |
| - * |
| - * @globals commits, curCommit, curGroup, t_interval_server, cmds_server |
| - * @globals sha1Re, infoRe, endRe |
| - */ |
| -function processBlameLines(lines) { |
| - var match; |
| - |
| - for (var i = 0, len = lines.length; i < len; i++) { |
| - |
| - if ((match = sha1Re.exec(lines[i]))) { |
| - var sha1 = match[1]; |
| - var srcline = parseInt(match[2], 10); |
| - var resline = parseInt(match[3], 10); |
| - var numlines = parseInt(match[4], 10); |
| - |
| - var c = commits[sha1]; |
| - if (!c) { |
| - c = new Commit(sha1); |
| - commits[sha1] = c; |
| - } |
| - curCommit = c; |
| - |
| - curGroup.srcline = srcline; |
| - curGroup.resline = resline; |
| - curGroup.numlines = numlines; |
| - |
| - } else if ((match = infoRe.exec(lines[i]))) { |
| - var info = match[1]; |
| - var data = match[2]; |
| - switch (info) { |
| - case 'filename': |
| - curCommit.filename = unquote(data); |
| - // 'filename' information terminates the entry |
| - handleLine(curCommit, curGroup); |
| - updateProgressInfo(); |
| - break; |
| - case 'author': |
| - curCommit.author = data; |
| - break; |
| - case 'author-time': |
| - curCommit.authorTime = parseInt(data, 10); |
| - break; |
| - case 'author-tz': |
| - curCommit.authorTimezone = data; |
| - break; |
| - case 'previous': |
| - curCommit.nprevious++; |
| - // store only first 'previous' header |
| - if (!'previous' in curCommit) { |
| - var parts = data.split(' ', 2); |
| - curCommit.previous = parts[0]; |
| - curCommit.file_parent = unquote(parts[1]); |
| - } |
| - break; |
| - case 'boundary': |
| - curCommit.boundary = true; |
| - break; |
| - } // end switch |
| - |
| - } else if ((match = endRe.exec(lines[i]))) { |
| - t_interval_server = match[1]; |
| - cmds_server = match[2]; |
| - |
| - } else if (lines[i] !== '') { |
| - // malformed line |
| - |
| - } // end if (match) |
| - |
| - } // end for (lines) |
| -} |
| - |
| -/** |
| - * Process new data and return pointer to end of processed part |
| - * |
| - * @param {String} unprocessed: new data (from nextReadPos) |
| - * @param {Number} nextReadPos: end of last processed data |
| - * @return {Number} end of processed data (new value for nextReadPos) |
| - */ |
| -function processData(unprocessed, nextReadPos) { |
| - var lastLineEnd = unprocessed.lastIndexOf('\n'); |
| - if (lastLineEnd !== -1) { |
| - var lines = unprocessed.substring(0, lastLineEnd).split('\n'); |
| - nextReadPos += lastLineEnd + 1 /* 1 == '\n'.length */; |
| - |
| - processBlameLines(lines); |
| - } // end if |
| - |
| - return nextReadPos; |
| -} |
| - |
| -/** |
| - * Handle XMLHttpRequest errors |
| - * |
| - * @param {XMLHttpRequest} xhr: XMLHttpRequest object |
| - * |
| - * @globals pollTimer, commits, inProgress |
| - */ |
| -function handleError(xhr) { |
| - errorInfo('Server error: ' + |
| - xhr.status + ' - ' + (xhr.statusText || 'Error contacting server')); |
| - |
| - clearInterval(pollTimer); |
| - commits = {}; // free memory |
| - |
| - inProgress = false; |
| -} |
| - |
| -/** |
| - * Called after XMLHttpRequest finishes (loads) |
| - * |
| - * @param {XMLHttpRequest} xhr: XMLHttpRequest object (unused) |
| - * |
| - * @globals pollTimer, commits, inProgress |
| - */ |
| -function responseLoaded(xhr) { |
| - clearInterval(pollTimer); |
| - |
| - fixColorsAndGroups(); |
| - writeTimeInterval(); |
| - commits = {}; // free memory |
| - |
| - inProgress = false; |
| -} |
| - |
| -/** |
| - * handler for XMLHttpRequest onreadystatechange event |
| - * @see startBlame |
| - * |
| - * @globals xhr, inProgress |
| - */ |
| -function handleResponse() { |
| - |
| - /* |
| - * xhr.readyState |
| - * |
| - * Value Constant (W3C) Description |
| - * ------------------------------------------------------------------- |
| - * 0 UNSENT open() has not been called yet. |
| - * 1 OPENED send() has not been called yet. |
| - * 2 HEADERS_RECEIVED send() has been called, and headers |
| - * and status are available. |
| - * 3 LOADING Downloading; responseText holds partial data. |
| - * 4 DONE The operation is complete. |
| - */ |
| - |
| - if (xhr.readyState !== 4 && xhr.readyState !== 3) { |
| - return; |
| - } |
| - |
| - // the server returned error |
| - // try ... catch block is to work around bug in IE8 |
| - try { |
| - if (xhr.readyState === 3 && xhr.status !== 200) { |
| - return; |
| - } |
| - } catch (e) { |
| - return; |
| - } |
| - if (xhr.readyState === 4 && xhr.status !== 200) { |
| - handleError(xhr); |
| - return; |
| - } |
| - |
| - // In konqueror xhr.responseText is sometimes null here... |
| - if (xhr.responseText === null) { |
| - return; |
| - } |
| - |
| - // in case we were called before finished processing |
| - if (inProgress) { |
| - return; |
| - } else { |
| - inProgress = true; |
| - } |
| - |
| - // extract new whole (complete) lines, and process them |
| - while (xhr.prevDataLength !== xhr.responseText.length) { |
| - if (xhr.readyState === 4 && |
| - xhr.prevDataLength === xhr.responseText.length) { |
| - break; |
| - } |
| - |
| - xhr.prevDataLength = xhr.responseText.length; |
| - var unprocessed = xhr.responseText.substring(xhr.nextReadPos); |
| - xhr.nextReadPos = processData(unprocessed, xhr.nextReadPos); |
| - } // end while |
| - |
| - // did we finish work? |
| - if (xhr.readyState === 4 && |
| - xhr.prevDataLength === xhr.responseText.length) { |
| - responseLoaded(xhr); |
| - } |
| - |
| - inProgress = false; |
| -} |
| - |
| -// ============================================================ |
| -// ------------------------------------------------------------ |
| - |
| -/** |
| - * Incrementally update line data in blame_incremental view in gitweb. |
| - * |
| - * @param {String} blamedataUrl: URL to server script generating blame data. |
| - * @param {String} bUrl: partial URL to project, used to generate links. |
| - * |
| - * Called from 'blame_incremental' view after loading table with |
| - * file contents, a base for blame view. |
| - * |
| - * @globals xhr, t0, projectUrl, div_progress_bar, totalLines, pollTimer |
| -*/ |
| -function startBlame(blamedataUrl, bUrl) { |
| - |
| - xhr = createRequestObject(); |
| - if (!xhr) { |
| - errorInfo('ERROR: XMLHttpRequest not supported'); |
| - return; |
| - } |
| - |
| - t0 = new Date(); |
| - projectUrl = bUrl + (bUrl.indexOf('?') === -1 ? '?' : ';'); |
| - if ((div_progress_bar = document.getElementById('progress_bar'))) { |
| - //div_progress_bar.setAttribute('style', 'width: 100%;'); |
| - div_progress_bar.style.cssText = 'width: 100%;'; |
| - } |
| - totalLines = countLines(); |
| - updateProgressInfo(); |
| - |
| - /* add extra properties to xhr object to help processing response */ |
| - xhr.prevDataLength = -1; // used to detect if we have new data |
| - xhr.nextReadPos = 0; // where unread part of response starts |
| - |
| - xhr.onreadystatechange = handleResponse; |
| - //xhr.onreadystatechange = function () { handleResponse(xhr); }; |
| - |
| - xhr.open('GET', blamedataUrl); |
| - xhr.setRequestHeader('Accept', 'text/plain'); |
| - xhr.send(null); |
| - |
| - // not all browsers call onreadystatechange event on each server flush |
| - // poll response using timer every second to handle this issue |
| - pollTimer = setInterval(xhr.onreadystatechange, 1000); |
| -} |
| - |
| -// end of gitweb.js |
| diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh |
| index 81ef2a0..939ddaf 100644 |
| --- a/t/gitweb-lib.sh |
| +++ b/t/gitweb-lib.sh |
| @@ -19,9 +19,9 @@ our \$site_name = '[localhost]'; |
| our \$site_header = ''; |
| our \$site_footer = ''; |
| our \$home_text = 'indextext.html'; |
| -our @stylesheets = ('file:///$TEST_DIRECTORY/../gitweb/static/gitweb.css'); |
| -our \$logo = 'file:///$TEST_DIRECTORY/../gitweb/static/git-logo.png'; |
| -our \$favicon = 'file:///$TEST_DIRECTORY/../gitweb/static/git-favicon.png'; |
| +our @stylesheets = ('file:///$TEST_DIRECTORY/../gitweb/gitweb.css'); |
| +our \$logo = 'file:///$TEST_DIRECTORY/../gitweb/git-logo.png'; |
| +our \$favicon = 'file:///$TEST_DIRECTORY/../gitweb/git-favicon.png'; |
| our \$projects_list = ''; |
| our \$export_ok = ''; |
| our \$strict_export = ''; |
| -- |
| 1.7.2.2 |
| |