Code

gitweb: Move static files into seperate subdirectory
authorPavan Kumar Sunkara <pavan.sss1991@gmail.com>
Fri, 28 May 2010 06:25:49 +0000 (11:55 +0530)
committerJunio C Hamano <gitster@pobox.com>
Tue, 1 Jun 2010 00:56:29 +0000 (17:56 -0700)
Create a new subdirectory called 'static' in gitweb/, and move
all static files required by gitweb.cgi when running, which means
styles, images and Javascript code. This should make gitweb more
readable and easier to maintain.

Update t/gitweb-lib.sh to reflect this change.The install-gitweb
now also include moving of static files into 'static' subdirectory
in target directory: update Makefile, gitweb's INSTALL, README and
Makefile accordingly.

Signed-off-by: Pavan Kumar Sunkara <pavan.sss1991@gmail.com>
Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Mentored-by: Petr Baudis <pasky@ucw.cz>
Acked-by: Jakub Narebski <jnareb@gmail.com>
Acked-by: Petr Baudis <pasky@suse.cz>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 files changed:
Makefile
gitweb/INSTALL
gitweb/Makefile
gitweb/README
gitweb/git-favicon.png [deleted file]
gitweb/git-logo.png [deleted file]
gitweb/gitweb.css [deleted file]
gitweb/gitweb.js [deleted file]
gitweb/static/git-favicon.png [new file with mode: 0644]
gitweb/static/git-logo.png [new file with mode: 0644]
gitweb/static/gitweb.css [new file with mode: 0644]
gitweb/static/gitweb.js [new file with mode: 0644]
t/gitweb-lib.sh

index 07cab8f6a47d4e49fab4d4f68d6998b2e0fff74b..1ec90f53faeec949a1240bd362096f31426d3a68 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1578,32 +1578,32 @@ gitweb:
        $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
 
 ifdef JSMIN
-GITWEB_PROGRAMS += gitweb/gitweb.min.js
-GITWEB_JS = gitweb/gitweb.min.js
+GITWEB_PROGRAMS += gitweb/static/gitweb.min.js
+GITWEB_JS = gitweb/static/gitweb.min.js
 else
-GITWEB_JS = gitweb/gitweb.js
+GITWEB_JS = gitweb/static/gitweb.js
 endif
 ifdef CSSMIN
-GITWEB_PROGRAMS += gitweb/gitweb.min.css
-GITWEB_CSS = gitweb/gitweb.min.css
+GITWEB_PROGRAMS += gitweb/static/gitweb.min.css
+GITWEB_CSS = gitweb/static/gitweb.min.css
 else
-GITWEB_CSS = gitweb/gitweb.css
+GITWEB_CSS = gitweb/static/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/gitweb.min.js: gitweb/gitweb.js
+gitweb/static/gitweb.min.js: gitweb/static/gitweb.js
        $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
 endif # JSMIN
 ifdef CSSMIN
-gitweb/gitweb.min.css: gitweb/gitweb.css
+gitweb/static/gitweb.min.css: gitweb/static/gitweb.css
        $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) $(patsubst gitweb/%,%,$@)
 endif # CSSMIN
 
 
-git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js
+git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/static/gitweb.css gitweb/static/gitweb.js
        $(QUIET_GEN)$(RM) $@ $@+ && \
        sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
            -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
index d484d76b753ef3d4ca0d75725e44f3c58ab2b482..823053173c92e4097dad54945db16f42b4b5d994 100644 (file)
@@ -2,9 +2,10 @@ GIT web Interface (gitweb) Installation
 =======================================
 
 First you have to generate gitweb.cgi from gitweb.perl using
-"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 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 prefix=/usr gitweb                            ;# as yourself
        # make gitwebdir=/var/www/cgi-bin install-gitweb     ;# as root
@@ -81,16 +82,14 @@ Build example
   minifiers, you can do
 
        make GITWEB_PROJECTROOT="/home/local/scm" \
-            GITWEB_JS="/gitweb/gitweb.js" \
-            GITWEB_CSS="/gitweb/gitweb.css" \
-            GITWEB_LOGO="/gitweb/git-logo.png" \
-            GITWEB_FAVICON="/gitweb/git-favicon.png" \
+            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" \
             bindir=/usr/local/bin \
             gitweb
 
-       cp -fv gitweb/gitweb.{cgi,js,css} \
-              gitweb/git-{favicon,logo}.png \
-            /var/www/cgi-bin/gitweb/
+       make gitwebdir=/var/www/cgi-bin/gitweb install-gitweb
 
 
 Gitweb config file
index 935d2d2e0775234fc99a29fd5b7610978a00099f..d2584fedd8811a47c35d6f814c5b57e4a0fb2f2c 100644 (file)
@@ -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 gitweb.js minified.
+# a filter to have static/gitweb.js minified.
 #
 # Define CSSMIN to point to a CSS minifier in order to generate a minified
-# version of gitweb.css
+# version of static/gitweb.css
 #
 
 prefix ?= $(HOME)
@@ -29,10 +29,10 @@ GITWEB_STRICT_EXPORT =
 GITWEB_BASE_URL =
 GITWEB_LIST =
 GITWEB_HOMETEXT = indextext.html
-GITWEB_CSS = gitweb.css
-GITWEB_LOGO = git-logo.png
-GITWEB_FAVICON = git-favicon.png
-GITWEB_JS = gitweb.js
+GITWEB_CSS = static/gitweb.css
+GITWEB_LOGO = static/git-logo.png
+GITWEB_FAVICON = static/git-favicon.png
+GITWEB_JS = static/gitweb.js
 GITWEB_SITE_HEADER =
 GITWEB_SITE_FOOTER =
 
@@ -54,6 +54,7 @@ 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))#'
@@ -88,26 +89,26 @@ all:: gitweb.cgi
 GITWEB_PROGRAMS = gitweb.cgi
 
 ifdef JSMIN
-GITWEB_FILES += gitweb.min.js
-GITWEB_JS = gitweb.min.js
-all:: gitweb.min.js
-gitweb.min.js: gitweb.js GITWEB-BUILD-OPTIONS
+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
        $(QUIET_GEN)$(JSMIN) <$< >$@
 else
-GITWEB_FILES += gitweb.js
+GITWEB_FILES += static/gitweb.js
 endif
 
 ifdef CSSMIN
-GITWEB_FILES += gitweb.min.css
-GITWEB_CSS = gitweb.min.css
-all:: gitweb.min.css
-gitweb.min.css: gitweb.css GITWEB-BUILD-OPTIONS
+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
        $(QUIET_GEN)$(CSSMIN) <$ >$@
 else
-GITWEB_FILES += gitweb.css
+GITWEB_FILES += static/gitweb.css
 endif
 
-GITWEB_FILES += git-logo.png git-favicon.png
+GITWEB_FILES += static/git-logo.png static/git-favicon.png
 
 GITWEB_REPLACE = \
        -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
@@ -147,12 +148,13 @@ 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) -m 644 $(GITWEB_FILES)    '$(DESTDIR_SQ)$(gitwebdir_SQ)'
+       $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitwebstaticdir_SQ)'
+       $(INSTALL) -m 644 $(GITWEB_FILES) '$(DESTDIR_SQ)$(gitwebstaticdir_SQ)'
 
 ### Cleaning rules
 
 clean:
-       $(RM) gitweb.cgi gitweb.min.js gitweb.min.css GITWEB-BUILD-OPTIONS
+       $(RM) gitweb.cgi static/gitweb.min.js static/gitweb.min.css GITWEB-BUILD-OPTIONS
 
 .PHONY: all clean install .FORCE-GIT-VERSION-FILE FORCE
 
index 71742b335dd786a24699b06b17519e264724ea5b..0e19be8d216aa813221c8663d6424f96f80bfb14 100644 (file)
@@ -80,24 +80,26 @@ 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: gitweb.css (or gitweb.min.css if the
-   CSSMIN variable is defined / CSS minifier is used)]
+   the gitweb config file.  [Default: static/gitweb.css (or
+   static/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: git-logo.png]
+   to base URI of gitweb.  [Default: static/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: git-favicon.png]
+   to base URI of gitweb.  [Default: static/git-favicon.png]
  * GITWEB_JS
    Points to the localtion 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: gitweb.js (or gitweb.min.js
-   if JSMIN build variable is defined / JavaScript minifier is used)]
+   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)]
  * 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
deleted file mode 100644 (file)
index aae35a7..0000000
Binary files a/gitweb/git-favicon.png and /dev/null differ
diff --git a/gitweb/git-logo.png b/gitweb/git-logo.png
deleted file mode 100644 (file)
index f4ede2e..0000000
Binary files a/gitweb/git-logo.png and /dev/null differ
diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
deleted file mode 100644 (file)
index 50067f2..0000000
+++ /dev/null
@@ -1,574 +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;
-}
diff --git a/gitweb/gitweb.js b/gitweb/gitweb.js
deleted file mode 100644 (file)
index 9c66928..0000000
+++ /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&#39;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&#39;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
new file mode 100644 (file)
index 0000000..aae35a7
Binary files /dev/null and b/gitweb/static/git-favicon.png differ
diff --git a/gitweb/static/git-logo.png b/gitweb/static/git-logo.png
new file mode 100644 (file)
index 0000000..f4ede2e
Binary files /dev/null and b/gitweb/static/git-logo.png differ
diff --git a/gitweb/static/gitweb.css b/gitweb/static/gitweb.css
new file mode 100644 (file)
index 0000000..50067f2
--- /dev/null
@@ -0,0 +1,574 @@
+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;
+}
diff --git a/gitweb/static/gitweb.js b/gitweb/static/gitweb.js
new file mode 100644 (file)
index 0000000..9c66928
--- /dev/null
@@ -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&#39;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&#39;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
index 5a734b1b7b2df4a5c5c35f5347c618f3735317ac..b70b891b628d1e5d7fe68b4d303c17fdd0416981 100644 (file)
@@ -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/gitweb.css');
-our \$logo = 'file:///$TEST_DIRECTORY/../gitweb/git-logo.png';
-our \$favicon = 'file:///$TEST_DIRECTORY/../gitweb/git-favicon.png';
+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 \$projects_list = '';
 our \$export_ok = '';
 our \$strict_export = '';