{"thread":{"id":"8328","subject":"GitWeb: Adding fork visualization based on objects/info/alternates","startedAt":"2007-05-26T18:31:01Z","lastAt":"2007-05-28T13:00:38Z","messageCount":2,"participants":["Marius Storm-Olsen","Petr Baudis"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"43357","messageId":"46587CE5.1030501@trolltech.com","threadId":"8328","inReplyTo":null,"subject":"GitWeb: Adding fork visualization based on objects/info/alternates","fromName":"Marius Storm-Olsen","fromEmail":"marius@trolltech.com","sentAt":"2007-05-26T18:31:01Z","receivedAt":"2007-05-26T18:31:01Z","isPatch":false,"sender":{"key":"marius@trolltech.com","avatar":"https://gravatar.com/avatar/a40071d8f651862c6ab10bd7996f0ad84d94f06c0399de9e3fa4f06beb390a71?d=mp&s=160"},"body":"Hi,\n\nIn an effort to tidy up the project list, and given that the\ncurrent fork support in GitWeb doesn't exactly fit my\nstructure (where forks are in subdirs of parent repo, and has\nto be first level down; alas no seek unlike when not showing\nforks), I set out to add fork support based on\n    objects/info/alternates\nof each repo. The result can be seen here:\n    http://chaos.troll.no/~marius/git/forks_collapsed.png\n    http://chaos.troll.no/~marius/git/forks_expanded.png\n\nI doubt you'd want it in the mainline, as you can't turn the\nfeature off; it's just like another column which you can sort\nby. If you do not sort by the 'fork' column, the forks will\nstill be colored with the first level color, but not ordered\nunder it's parent repo.\n\nJust wanted to feed back what I did so others can get\ninspiration, tweak it, and add it to their own gitwebs.\n\nIt cleans up the project list real nicely though.\n\nLater!\n\n--\n.marius\n\n--------------------------------------------------------------\n\n>From a3659e21447181717b8b9edec319fe78f5643bdd Mon Sep 17 00:00:00 2001\nFrom: Marius Storm-Olsen <marius@devil.troll.no>\nDate: Sat, 26 May 2007 18:25:41 +0200\nSubject: [PATCH] Adding fork visualization based on objects/info/alternates.\n  1) All projects which have alternates are colorized\n  2) When sorting based on forks, the forks are shown in\n     a tree-like structure, which is collapsed by default.\n     The user can expand each node to see the fork projects.\n---\n gitweb/closed.png        |  Bin 0 -> 496 bytes\n gitweb/gitweb.css        |   23 ++++++++\n gitweb/gitweb.perl       |  137 +++++++++++++++++++++++++++++++++++----------\n gitweb/gitweb_scripts.js |   55 ++++++++++++++++++\n gitweb/open.png          |  Bin 0 -> 497 bytes\n 5 files changed, 184 insertions(+), 31 deletions(-)\n create mode 100644 gitweb/closed.png\n create mode 100644 gitweb/gitweb_scripts.js\n create mode 100644 gitweb/open.png\n\ndiff --git a/gitweb/closed.png b/gitweb/closed.png\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..ae630014d068e541f2b4d6b24617a4d6c896bd62\nGIT binary patch\nliteral 496\nzcmV<M0T2F(P)<h;3K|Lk000e1NJLTq000gE000gM1^@s6A4o0H00006VoOIv0RI60\nz0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru*995~FB_u49)$n^0ewkC\nzK~#9!y^_yL8(|d1&!n>$0-=kVw~$cm3%Km_NZqH<g<E|G%~;xkwuTxKIwpgOAeeL#\nzu&vPPBF2yih0dREa_@IP7eb%}T1D`z?&fz6oO6MP$aO1TskFR$Z!iphn(=sScHg>p\nzH?VEn>Gis1FzB0$iyvk<9GacVwzu-)`OANCmg6{2eZTeF%H;q6ni(R3LZN_8r+u`!\nzwN?Jw3%mu;vMl@Lq(cBOBSMnIP^m(aBp@a@j)Q(bXt?ff`P=z-e-7sJ`DdQ@Whx>_\nzRSK0VL~(>9Nf5^|q9}q=DYVuI!(V>wu=aX1x~ki=Sr!9;7=dODB7$ZOCIT~qnUQ4~\nzqCXKvqf1swDFCnmKtw<@0&4~lftWyidovS)AZWCYI~$Y9v_3C2mwRH*6SamIxium}\nzw|jP4t$tp+o?f>W))3JwMqtFufoAilvA_56uY?6qYheJ$vJ3|YpBnGqeRwmOOuhd;\nmfMr?stMxU%SX^4gW9SCp%l`C>LXp`30000<MNUMnLSTX$t<ll|\n\nliteral 0\nHcmV?d00001\n\ndiff --git a/gitweb/gitweb.css b/gitweb/gitweb.css\nindex 9f0822f..ca9a77a 100644\n--- a/gitweb/gitweb.css\n+++ b/gitweb/gitweb.css\n@@ -214,6 +214,29 @@ th {\n \ttext-align: left;\n }\n\n+.folder {\n+\tbackground: url(closed.png) no-repeat;\n+\tfloat: left;\n+\theight: 14px;\n+\twidth: 10px;\n+\tpadding-right: 3px;\n+}\n+\n+tr.fork, /* All forks higher than 10 will use this one */\n+tr.fork1 { background-color: #ffffc0; }\n+tr.fork2 { background-color: #ffffa0; }\n+tr.fork3 { background-color: #ffff80; }\n+tr.fork4 { background-color: #ffff60; }\n+tr.fork5 { background-color: #ffff40; }\n+tr.fork6 { background-color: #ffff20; }\n+tr.fork7 { background-color: #ffff00; }\n+tr.fork8 { background-color: #ffc000; }\n+tr.fork9 { background-color: #ffa000; }\n+\n+tr.alternates {\n+\tcolor: #a0a0a0;\n+}\n+\n tr.light:hover {\n \tbackground-color: #edece6;\n }\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex c3921cb..65984dc 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -72,7 +72,7 @@ our $logo_label = \"git homepage\";\n our $projects_list = \"++GITWEB_LIST++\";\n\n # default order of projects list\n-# valid values are none, project, descr, owner, and age\n+# valid values are none, fork, project, descr, owner, and age\n our $default_projects_order = \"project\";\n\n # show repository only if this file exists\n@@ -1282,6 +1282,16 @@ sub git_get_project_owner {\n \treturn $owner;\n }\n\n+sub git_get_project_alternates_list {\n+\tmy $path = shift;\n+\n+\topen my $fd, \"$projectroot/$path/objects/info/alternates\" or return;\n+\tmy @git_project_alternates_list = map { chomp; $_ } <$fd>;\n+\tclose $fd;\n+\n+\treturn wantarray ? @git_project_alternates_list : \\@git_project_alternates_list;\n+}\n+\n sub git_get_last_activity {\n \tmy ($path) = @_;\n \tmy $fd;\n@@ -1909,8 +1919,9 @@ EOF\n \t\tprint qq(<link rel=\"shortcut icon\" href=\"$favicon\" type=\"image/png\"/>\\n);\n \t}\n\n+\tprint \"<script src=\\\"gitweb_scripts.js\\\" type=\\\"text/javascript\\\"></script>\\n\";\n \tprint \"</head>\\n\" .\n-\t      \"<body>\\n\";\n+\t      \"<body onload=\\\"collapseAllRows();\\\">\\n\";\n\n \tif (-f $site_header) {\n \t\topen (my $fd, $site_header);\n@@ -2928,6 +2939,7 @@ sub git_project_list_body {\n \tmy ($check_forks) = gitweb_check_feature('forks');\n\n \tmy @projects;\n+\tmy %forkProjects = ();\n \tforeach my $pr (@$projlist) {\n \t\tmy (@aa) = git_get_last_activity($pr->{'path'});\n \t\tunless (@aa) {\n@@ -2942,6 +2954,12 @@ sub git_project_list_body {\n \t\tif (!defined $pr->{'owner'}) {\n \t\t\t$pr->{'owner'} = get_file_owner(\"$projectroot/$pr->{'path'}\") || \"\";\n \t\t}\n+\t\tmy @altPaths = map { $_ =~ s=\\/objects$==g; $_ }\n+\t\t\t\t   git_get_project_alternates_list($pr->{'path'});\n+\t\tif (!defined $pr->{'alternates'}) {\n+\t\t\t$pr->{'alternates'} = join(\":\",  @altPaths);\n+\t\t}\n+\n \t\tif ($check_forks) {\n \t\t\tmy $pname = $pr->{'path'};\n \t\t\tif (($pname =~ s/\\.git$//) &&\n@@ -2954,6 +2972,12 @@ sub git_project_list_body {\n \t\t\t}\n \t\t}\n \t\tpush @projects, $pr;\n+\n+\t\tif ($#altPaths + 1) {\n+                    foreach my $altPath (@altPaths) {\n+\t\t        $forkProjects{$altPath}{\"$projectroot/$pr->{'path'}\"} = $pr;\n+\t\t    }\n+\t\t}\n \t}\n\n \t$order ||= $default_projects_order;\n@@ -2966,6 +2990,15 @@ sub git_project_list_body {\n \t\tif ($check_forks) {\n \t\t\tprint \"<th></th>\\n\";\n \t\t}\n+\t\tif ($order eq \"fork\") {\n+\t\t\t@projects = sort {$a->{'path'} cmp $b->{'path'}} @projects;\n+\t\t\tprint \"<th>+</th>\\n\";\n+\t\t} else {\n+\t\t\tprint \"<th>\" .\n+\t\t\t      $cgi->a({-href => href(project=>undef, order=>'fork'),\n+\t\t\t               -class => \"header\"}, \"+\") .\n+\t\t\t      \"</th>\\n\";\n+\t\t}\n \t\tif ($order eq \"project\") {\n \t\t\t@projects = sort {$a->{'path'} cmp $b->{'path'}} @projects;\n \t\t\tprint \"<th>Project</th>\\n\";\n@@ -3006,38 +3039,21 @@ sub git_project_list_body {\n \t\t      \"</tr>\\n\";\n \t}\n \tmy $alternate = 1;\n+\tmy $isForkOrder = ($order eq \"fork\");\n \tfor (my $i = $from; $i <= $to; $i++) {\n \t\tmy $pr = $projects[$i];\n-\t\tif ($alternate) {\n-\t\t\tprint \"<tr class=\\\"dark\\\">\\n\";\n-\t\t} else {\n-\t\t\tprint \"<tr class=\\\"light\\\">\\n\";\n+\t\tmy $isFork = ($pr->{'alternates'} ne \"\");\n+\t\tmy $rowColor = \"light\";\n+\t\t$rowColor = \"dark\" if ($alternate);\n+\t\t$rowColor = \"fork\" if ($isFork);\n+\n+\t\t# If we're in fork ordering and this is a fork, we will not output this node\n+\t\t# since it has/will be outputted as a fork (child node) of another project.\n+\t\tif (!($isForkOrder && $isFork)) {\n+\t\t\tgit_project_body($pr, $isForkOrder, $rowColor, \"$i\", $check_forks, \\%forkProjects, \"\", 0);\n \t\t}\n+\n \t\t$alternate ^= 1;\n-\t\tif ($check_forks) {\n-\t\t\tprint \"<td>\";\n-\t\t\tif ($pr->{'forks'}) {\n-\t\t\t\tprint \"<!-- $pr->{'forks'} -->\\n\";\n-\t\t\t\tprint $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"forks\")}, \"+\");\n-\t\t\t}\n-\t\t\tprint \"</td>\\n\";\n-\t\t}\n-\t\tprint \"<td>\" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"summary\"),\n-\t\t                        -class => \"list\"}, esc_html($pr->{'path'})) . \"</td>\\n\" .\n-\t\t      \"<td>\" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"summary\"),\n-\t\t                        -class => \"list\", -title => $pr->{'descr_long'}},\n-\t\t                        esc_html($pr->{'descr'})) . \"</td>\\n\" .\n-\t\t      \"<td><i>\" . chop_str($pr->{'owner'}, 15) . \"</i></td>\\n\";\n-\t\tprint \"<td class=\\\"\". age_class($pr->{'age'}) . \"\\\">\" .\n-\t\t      (defined $pr->{'age_string'} ? $pr->{'age_string'} : \"No commits\") . \"</td>\\n\" .\n-\t\t      \"<td class=\\\"link\\\">\" .\n-\t\t      $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"summary\")}, \"summary\")   . \" | \" .\n-\t\t      $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"shortlog\")}, \"shortlog\") . \" | \" .\n-\t\t      $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"log\")}, \"log\") . \" | \" .\n-\t\t      $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"tree\")}, \"tree\") .\n-\t\t      ($pr->{'forks'} ? \" | \" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"forks\")}, \"forks\") : '') .\n-\t\t      \"</td>\\n\" .\n-\t\t      \"</tr>\\n\";\n \t}\n \tif (defined $extra) {\n \t\tprint \"<tr>\\n\";\n@@ -3050,6 +3066,58 @@ sub git_project_list_body {\n \tprint \"</table>\\n\";\n }\n\n+sub git_project_body {\n+\tmy ($pr, $isForkOrder, $rowColor, $parentNode, $check_forks, $forkProjectsRef, $indent, $indentLevel) = @_;\n+\n+\t# Get the forks keys for this project\n+\tmy $forkHash = $forkProjectsRef->{\"$projectroot/$pr->{'path'}\"};\n+\tmy @forkKeys = sort keys (%$forkHash);\n+\tmy $forkLevel = \"\";\n+\t$forkLevel = \"$indentLevel\" if ($indentLevel && $indentLevel < 10);\n+\tprint \"<tr class=\\\"$rowColor$forkLevel\\\" id=\\\"$parentNode\\\">\\n\";\n+\n+\tif ($check_forks) {\n+\t\tprint \"<td>\";\n+\t\tif ($pr->{'forks'}) {\n+\t\t\tprint \"<!-- $pr->{'forks'} -->\\n\";\n+\t\t\tprint $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"forks\")}, \"+\");\n+\t\t}\n+\t\tprint \"</td>\\n\";\n+\t}\n+\n+\t# Add a folder anchor if this project has forks and we're in fork order\n+\tmy $forkToggle = \">\";\n+\tif ($#forkKeys + 1 && $isForkOrder) {\n+\t    $forkToggle = \" onclick=\\\"toggleRows(this)\\\" class=\\\"folder\\\">\";\n+\t}\n+\tprint \"<td><div class=\\\"tier\\\"><a href=\\\"#\\\"$forkToggle</a></div></td>\";\n+\n+\tprint \"<td>$indent\" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"summary\"),\n+\t                        -class => \"list\"}, esc_html($pr->{'path'})) . \"</td>\\n\" .\n+\t      \"<td>\" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"summary\"),\n+\t                        -class => \"list\", -title => $pr->{'descr_long'}},\n+\t                        esc_html($pr->{'descr'})) . \"</td>\\n\" .\n+\t      \"<td><i>\" . chop_str($pr->{'owner'}, 15) . \"</i></td>\\n\";\n+\tprint \"<td class=\\\"\". age_class($pr->{'age'}) . \"\\\">\" .\n+\t      (defined $pr->{'age_string'} ? $pr->{'age_string'} : \"No commits\") . \"</td>\\n\" .\n+\t      \"<td class=\\\"link\\\">\" .\n+\t      $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"summary\")}, \"summary\")   . \" | \" .\n+\t      $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"shortlog\")}, \"shortlog\") . \" | \" .\n+\t      $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"log\")}, \"log\") . \" | \" .\n+\t      $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"tree\")}, \"tree\") .\n+\t      ($pr->{'forks'} ? \" | \" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>\"forks\")}, \"forks\") : '') .\n+\t      \"</td>\\n\" .\n+\t      \"</tr>\\n\";\n+\n+\treturn if (!$isForkOrder || !($#forkKeys + 1));\n+\tmy $siblingCount = 0;\n+\tfor my $key (@forkKeys) {\n+\t\tmy $forkProject = ${$forkHash}{$key};\n+\t\t$siblingCount++;\n+\t\tgit_project_body($forkProject, $isForkOrder, \"fork\", $parentNode.\"-$siblingCount\", $check_forks, $forkProjectsRef, $indent.\"&nbsp;&nbsp;\", $indentLevel+1);\n+\t}\n+}\n+\n sub git_shortlog_body {\n \t# uses global variable $project\n \tmy ($commitlist, $from, $to, $refs, $extra) = @_;\n@@ -3315,7 +3383,7 @@ sub git_search_grep_body {\n\n sub git_project_list {\n \tmy $order = $cgi->param('o');\n-\tif (defined $order && $order !~ m/none|project|descr|owner|age/) {\n+\tif (defined $order && $order !~ m/none|fork|project|descr|owner|age/) {\n \t\tdie_error(undef, \"Unknown order parameter\");\n \t}\n\n@@ -3419,6 +3487,13 @@ sub git_summary {\n \t\tprint \"<tr><td>$url_tag</td><td>$git_url</td></tr>\\n\";\n \t\t$url_tag = \"\";\n \t}\n+\tmy $alternates_tag = \"ALT\";\n+\tmy @alternates_list = git_get_project_alternates_list($project);\n+\tforeach my $alternate (@alternates_list) {\n+\t\tnext unless $alternate;\n+\t\tprint \"<tr class=\\\"alternates\\\"><td>$alternates_tag</td><td>$alternate</td></tr>\\n\";\n+\t\t$alternates_tag = \"\";\n+\t}\n \tprint \"</table>\\n\";\n\n \tif (-s \"$projectroot/$project/README.html\") {\ndiff --git a/gitweb/gitweb_scripts.js b/gitweb/gitweb_scripts.js\nnew file mode 100644\nindex 0000000..79f43dc\n--- /dev/null\n+++ b/gitweb/gitweb_scripts.js\n@@ -0,0 +1,55 @@\n+// Javascript based on the SSTree project\n+// http://sstree.tigris.org/\n+\n+function toggleRows(elm) {\n+    var rows = document.getElementsByTagName(\"tr\");\n+    elm.style.backgroundImage = \"url(closed.png)\";\n+    var newDisplay = \"none\";\n+    var thisID = elm.parentNode.parentNode.parentNode.id + \"-\";\n+    // Are we expanding or contracting? If the first child is hidden, we expand\n+    for (var i = 0; i < rows.length; i++) {\n+        var r = rows[i];\n+        if (matchStart(r.id, thisID, true)) {\n+            if (r.style.display == \"none\") {\n+                if (document.all) newDisplay = \"block\";     // IE4+ specific code\n+                else newDisplay = \"table-row\";              // Netscape and Mozilla\n+                elm.style.backgroundImage = \"url(open.png)\";\n+            }\n+            break;\n+        }\n+    }\n+\n+    // When expanding, only expand one level.  Collapse all desendants.\n+    var matchDirectChildrenOnly = (newDisplay != \"none\");\n+\n+    for (var j = 0; j < rows.length; j++) {\n+        var s = rows[j];\n+        if (matchStart(s.id, thisID, matchDirectChildrenOnly)) {\n+            s.style.display = newDisplay;\n+            var cell = s.getElementsByTagName(\"td\")[0];\n+            var tier = cell.getElementsByTagName(\"div\")[0];\n+            var folder = tier.getElementsByTagName(\"a\")[0];\n+            if (folder.getAttribute(\"onclick\") != null) {\n+                folder.style.backgroundImage = \"url(closed.png)\";\n+            }\n+        }\n+    }\n+}\n+\n+function matchStart(target, pattern, matchDirectChildrenOnly) {\n+    var pos = target.indexOf(pattern);\n+    if (pos != 0) return false;\n+    if (!matchDirectChildrenOnly) return true;\n+    if (target.slice(pos + pattern.length, target.length).indexOf(\"-\") >= 0) return false;\n+    return true;\n+}\n+\n+function collapseAllRows() {\n+    var rows = document.getElementsByTagName(\"tr\");\n+    for (var j = 0; j < rows.length; j++) {\n+        var r = rows[j];\n+        if (r.id.indexOf(\"-\") >= 0) {\n+            r.style.display = \"none\";\n+        }\n+    }\n+}\ndiff --git a/gitweb/open.png b/gitweb/open.png\nnew file mode 100644\nindex 0000000000000000000000000000000000000000..ea1f3a0d4affc87d570d36a960479efd07105c9c\nGIT binary patch\nliteral 497\nzcmV<N0S^9&P)<h;3K|Lk000e1NJLTq000gE000gM1^@s6A4o0H0005FNkl<Zc-pOx\nzziU%b7>1v7?hmhtH#axwVB=!*Z)l)Y7mHI}>ehm!d(q7yItA=v(a_>Q(CVZ@aj-%_\nz+HC3^2uX49c8vF)4n60@!A8>9Mev1h_+Flm_x&6IA%rW0kgn_auImLtAf=RU5L}M5\nz)~7)bgn+QtYR)789zI(CytH)h27nY204e2|K}w0|c|=h}r_*UKFW;Yc0J`07Z}HCJ\nz3M0@)V~s^f!C4!m<KX)~QB<T}f3TV)$9)GtDb)`P`P%ilxvJJ0V+}?dj5UD3^E~qT\nzJcpfw_RANo27oiJGZ+kx7H%!9SZmRz8fz^hJHi;vCEur1Dzmm$UrmzZ{<%Y?RKFNU\nzwMyk$bzD~)4I{|qa(w;vrQK?6HU9j~gx<Y<-y9ByWLZX*r6{FPN)d)38ynA>ldLnj\nzD5ZKcGo`!ba=Bux#TbL@xeNyV_V(7R$CK>2M1Z}$59?W$lBT~W2m+pOZZ@VlXWBSX\nzCr4r7N-d7#DvU^yAN#L&-#ne>{z?QmJm@sjpDD%|c6N3f7ctI7rc$aG6$|sm*zfxv\nnKRw}J6vxGzv$I!k^S|{A;Yhe4$I~??00000NkvXXu0mjf*^uU~\n\nliteral 0\nHcmV?d00001\n\n--\n1.5.2.58.g98ee\n"},{"id":"43490","messageId":"20070528130038.GR4489@pasky.or.cz","threadId":"8328","inReplyTo":"46587CE5.1030501@trolltech.com","subject":"Re: GitWeb: Adding fork visualization based on objects/info/alternates","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2007-05-28T13:00:38Z","receivedAt":"2007-05-28T13:00:38Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"  Hi,\n\nOn Sat, May 26, 2007 at 08:31:01PM CEST, Marius Storm-Olsen wrote:\n> In an effort to tidy up the project list, and given that the\n> current fork support in GitWeb doesn't exactly fit my\n> structure (where forks are in subdirs of parent repo, and has\n> to be first level down; alas no seek unlike when not showing\n> forks), I set out to add fork support based on\n>     objects/info/alternates\n> of each repo. The result can be seen here:\n>     http://chaos.troll.no/~marius/git/forks_collapsed.png\n>     http://chaos.troll.no/~marius/git/forks_expanded.png\n> \n> I doubt you'd want it in the mainline, as you can't turn the\n> feature off; it's just like another column which you can sort\n> by. If you do not sort by the 'fork' column, the forks will\n> still be colored with the first level color, but not ordered\n> under it's parent repo.\n> \n> Just wanted to feed back what I did so others can get\n> inspiration, tweak it, and add it to their own gitwebs.\n> \n> It cleans up the project list real nicely though.\n\n  I think this patch is quite an interesting idea, and I kind of like\nthe possibility to show forks in the summary project list, if it's\noptional (I actually don't think if I would enable this say at\nrepo.or.cz - some projects have quite a lot of forks and it would\nclutter it up a lot e.g. for text-mode browsers that don't grok\nenough javascript). OTOH, taking fork info from alternates is more\ncontroversial; I don't want to force the repo.or.cz forks model on\neveryone but having $proj in alternates may not mean it is a fork... but\nif more people think it's a reasonable heuristic, we might optionally\nsupport it too.\n\n  If you would be willing to split this patch to two and make both\nfeatures optional (and sign off the patch), I think at least the\nforks-in-summary part might be quite a worthy addition.\n\n> @@ -1909,8 +1919,9 @@ EOF\n>  \t\tprint qq(<link rel=\"shortcut icon\" href=\"$favicon\" type=\"image/png\"/>\\n);\n>  \t}\n> \n> +\tprint \"<script src=\\\"gitweb_scripts.js\\\" type=\\\"text/javascript\\\"></script>\\n\";\n>  \tprint \"</head>\\n\" .\n> -\t      \"<body>\\n\";\n> +\t      \"<body onload=\\\"collapseAllRows();\\\">\\n\";\n> \n>  \tif (-f $site_header) {\n>  \t\topen (my $fd, $site_header);\n\nWould it be more reasonable to just set the style for these rows by\ndefault to display: none?\n\n> --- /dev/null\n> +++ b/gitweb/gitweb_scripts.js\n\nWe have other patch introducing blame.js, so maybe call this forks.js?\nOr do we have a strong reason to prefer a single .js file with all the\nlot?\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nEver try. Ever fail. No matter. // Try again. Fail again. Fail better.\n\t\t-- Samuel Beckett\n"}]}