Bug 294800 - Beautify FTP/File/Jar/Gopher dir listings (CSS, icons, sortable columns) so that they don't look like they're from 1995. (Ooh, shiny!) Patch by Dao Gottwald <dao@design-noir.de>, r+sr=bz, r=mano, a=dsicore
authorjwalden@mit.edu
Fri, 17 Aug 2007 15:57:36 -0700
changeset 4764 a2b95187929bc707b5b8ac2a71033011d8b9570a
parent 4763 99735fc9b7a5f86c55edf52324ce4658ab69bd11
child 4765 efb8ffa885f97fd44a6da9670d80ffb3f120c722
push idunknown
push userunknown
push dateunknown
reviewersmano, dsicore
bugs294800
milestone1.9a8pre
Bug 294800 - Beautify FTP/File/Jar/Gopher dir listings (CSS, icons, sortable columns) so that they don't look like they're from 1995. (Ooh, shiny!) Patch by Dao Gottwald <dao@design-noir.de>, r+sr=bz, r=mano, a=dsicore
embedding/config/basebrowser-installer-win.pkg
embedding/config/basebrowser-win
layout/build/layout.pkg
layout/generic/Makefile.in
layout/generic/folder.png
netwerk/locales/en-US/necko.properties
netwerk/streamconv/converters/nsIndexedToHTML.cpp
toolkit/themes/pinstripe/global/dirListing/dirListing.css
toolkit/themes/pinstripe/global/dirListing/folder.png
toolkit/themes/pinstripe/global/dirListing/local.png
toolkit/themes/pinstripe/global/dirListing/remote.png
toolkit/themes/pinstripe/global/dirListing/up.png
toolkit/themes/pinstripe/global/jar.mn
toolkit/themes/winstripe/global/dirListing/dirListing.css
toolkit/themes/winstripe/global/dirListing/local.png
toolkit/themes/winstripe/global/dirListing/remote.png
toolkit/themes/winstripe/global/dirListing/up.png
toolkit/themes/winstripe/global/jar.mn
--- a/embedding/config/basebrowser-installer-win.pkg
+++ b/embedding/config/basebrowser-installer-win.pkg
@@ -252,16 +252,17 @@ res\broken-image.gif
 res\entityTables\html40Special.properties
 res\entityTables\htmlEntityVersions.properties
 res\entityTables\html40Latin1.properties
 res\entityTables\html40Symbols.properties
 res\entityTables\transliterate.properties
 res\fonts\fontEncoding.properties
 
 ; needed for ftp:// dir listings etc
+res\html\folder.png
 res\html\gopher-audio.gif
 res\html\gopher-binary.gif
 res\html\gopher-find.gif
 res\html\gopher-image.gif
 res\html\gopher-menu.gif
 res\html\gopher-movie.gif
 res\html\gopher-sound.gif
 res\html\gopher-telnet.gif
--- a/embedding/config/basebrowser-win
+++ b/embedding/config/basebrowser-win
@@ -268,16 +268,17 @@ res\broken-image.gif
 res\entityTables\html40Special.properties
 res\entityTables\htmlEntityVersions.properties
 res\entityTables\html40Latin1.properties
 res\entityTables\html40Symbols.properties
 res\entityTables\transliterate.properties
 res\fonts\fontEncoding.properties
 
 ; needed for ftp:// dir listings etc
+res\html\folder.png
 res\html\gopher-audio.gif
 res\html\gopher-binary.gif
 res\html\gopher-find.gif
 res\html\gopher-image.gif
 res\html\gopher-menu.gif
 res\html\gopher-movie.gif
 res\html\gopher-sound.gif
 res\html\gopher-telnet.gif
--- a/layout/build/layout.pkg
+++ b/layout/build/layout.pkg
@@ -37,16 +37,17 @@ dist/bin/res/viewsource.css
 dist/bin/res/forms.css
 dist/bin/res/contenteditable.css
 dist/bin/res/designmode.css
 dist/bin/res/arrow.gif
 dist/bin/res/arrowd.gif
 dist/bin/res/ua.css
 dist/bin/res/broken-image.gif
 dist/bin/res/loading-image.gif
+dist/bin/res/html/folder.png
 dist/bin/res/html/gopher-audio.gif
 dist/bin/res/html/gopher-binary.gif
 dist/bin/res/html/gopher-find.gif
 dist/bin/res/html/gopher-image.gif
 dist/bin/res/html/gopher-menu.gif
 dist/bin/res/html/gopher-movie.gif
 dist/bin/res/html/gopher-sound.gif
 dist/bin/res/html/gopher-telnet.gif
--- a/layout/generic/Makefile.in
+++ b/layout/generic/Makefile.in
@@ -165,16 +165,17 @@ CPPSRCS		= \
 
 ifdef IBMBIDI
 CPPSRCS		+= \
 		nsBidiFrames.cpp \
 		$(NULL)
 endif
 
 RESOURCES_HTML = \
+		$(srcdir)/folder.png \
 		$(srcdir)/gopher-audio.gif \
 		$(srcdir)/gopher-binary.gif \
 		$(srcdir)/gopher-find.gif \
 		$(srcdir)/gopher-image.gif \
 		$(srcdir)/gopher-menu.gif \
 		$(srcdir)/gopher-movie.gif \
 		$(srcdir)/gopher-sound.gif \
 		$(srcdir)/gopher-telnet.gif \
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6fa6c1590501c6daa40f25e016b158842581d163
GIT binary patch
literal 619
zc$@)i0+juUP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00007bV*G`2iFG?
z5D*~r;QKTH000SaNLh0L03N{r03N{s!)a7g00004XF*Lt006O%3;baP0005{Nkl<Z
zc-qBNL2DC16#ga|6KT_?(r9bFsd!N=<d9#W;L+YZNX3HS$(z5xA7BpBf}WIu*Mb*s
zLMf<0u%ecNSQ?v((Zp<GlFjby%=*oeB}q}yle2uhw=?hi-kUcw!2ceiw1R@t$tC6K
zP-{#D0pKf?X}1>cV3jfEj{+~2@%Ze*lPj6o!pOqY;)S(V^{qyTEQLcWtQ0;H+c)py
z9z(Q^lLDAdW=}J1aYW$Kt>w!|oH>~A;@#^rYqXDumK6~jMeOI7Ud@%)7tyNhAU!n;
z&1?bn^>6T_?x0zBnm1OElP1JmyY>aW`e)>?eLymug5U?%J{Ykt=_z;}H(b4aGRuh>
zso5g8S;bf`51H;VcJmj+*p9;l-yu`^I3Q&!K(FzR0_PdmV9%QeNU=`{)*lK~cQ)br
zDA`GASV8COa~vxyl3XF2Q2}E&-lO#?Fpj{VM6JAwo{ufA`jLR@>>)LIicYCdVi&!(
zT_D+`R=)z7gE7<Cd;iP|FdI~~g`m5S!xP83ml_-5lI#vhVZRb<jfce83AF2<#J5&d
zK@bT{97!NF31+woWH^z*fHd3*aR^;Uqur=rV>=R1lIQxSRyFf4ADn}|Z87Y55C0Ft
z>EPk(UD#$R5gjgYlt|mF{g-dZz7IACjhG<+fjlgte*!(!49c_mkdXiY002ovPDHLk
FV1n6y8D;<g
--- a/netwerk/locales/en-US/necko.properties
+++ b/netwerk/locales/en-US/necko.properties
@@ -53,16 +53,21 @@ 27=Beginning FTP transaction...
 28=Finished FTP transaction
 
 UnsupportedFTPServer=The FTP server %1$S is currently unsupported.
 RepostFormData=This web page is being redirected to a new location. Would you like to resend the form data you have typed to the new location?
 
 # Directory listing strings
 DirTitle=Index of %1$S
 DirGoUp=Up to higher level directory
+ShowHidden=Show hidden objects
+DirColName=Name
+DirColSize=Size
+DirColMTime=Last Modified
+DirFileLabel=File: 
 
 #Gopher Search Prompt
 GopherPromptTitle=Search
 GopherPromptText=Enter a search term:
 
 PhishingAuth=You are about to visit "%1$S". This site may be attempting to trick you into thinking you are visiting a different site. Use extreme caution.
 PhishingAuthAccept=I understand and will be very careful
 SuperfluousAuth=You are about to log in to the site "%1$S" with the username "%2$S", but the website does not require authentication. This may be an attempt to trick you.\n\nIs "%1$S" the site you want to visit?
--- a/netwerk/streamconv/converters/nsIndexedToHTML.cpp
+++ b/netwerk/streamconv/converters/nsIndexedToHTML.cpp
@@ -17,16 +17,17 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Bradley Baetz <bbaetz@cs.mcgill.ca>
  *   Christopher A. Aillon <christopher@aillon.com>
+ *   Dão Gottwald <dao@design-noir.de>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -44,33 +45,30 @@
 #include "nsIFileURL.h"
 #include "nsEscape.h"
 #include "nsIDirIndex.h"
 #include "prtime.h"
 #include "nsDateTimeFormatCID.h"
 #include "nsURLHelper.h"
 #include "nsCRT.h"
 #include "nsIPlatformCharset.h"
-#include "nsInt64.h"
 
 NS_IMPL_ISUPPORTS4(nsIndexedToHTML,
                    nsIDirIndexListener,
                    nsIStreamConverter,
                    nsIRequestObserver,
                    nsIStreamListener)
 
-static void ConvertNonAsciiToNCR(const nsAString& in, nsAFlatString& out)
+static void AppendNonAsciiToNCR(const nsAString& in, nsAFlatString& out)
 {
   nsAString::const_iterator start, end;
 
   in.BeginReading(start);
   in.EndReading(end);
 
-  out.Truncate();
-
   while (start != end) {
     if (*start < 128) {
       out.Append(*start++);
     } else {
       out.AppendLiteral("&#x");
       nsAutoString hex;
       hex.AppendInt(*start++, 16);
       out.Append(hex);
@@ -143,33 +141,34 @@ nsIndexedToHTML::OnStartRequest(nsIReque
     if (NS_FAILED(rv)) return rv;
 
     rv = mParser->SetListener(this);
     if (NS_FAILED(rv)) return rv;
     
     rv = mParser->OnStartRequest(request, aContext);
     if (NS_FAILED(rv)) return rv;
 
-    nsCAutoString baseUri,titleUri;
+    nsCAutoString baseUri, titleUri;
     rv = uri->GetAsciiSpec(baseUri);
     if (NS_FAILED(rv)) return rv;
     titleUri = baseUri;
 
     nsCString parentStr;
 
     // XXX - should be using the 300: line from the parser.
     // We can't guarantee that that comes before any entry, so we'd have to
     // buffer, and do other painful stuff.
     // I'll deal with this when I make the changes to handle welcome messages
     // The .. stuff should also come from the lower level protocols, but that
     // would muck up the XUL display
     // - bbaetz
 
     PRBool isScheme = PR_FALSE;
     PRBool isSchemeFile = PR_FALSE;
+    PRBool isSchemeGopher = PR_FALSE;
     if (NS_SUCCEEDED(uri->SchemeIs("ftp", &isScheme)) && isScheme) {
 
         // ftp urls don't always end in a /
         // make sure they do
         // but look out for /%2F as path
         nsCAutoString path;
         rv = uri->GetPath(path);
         if (NS_FAILED(rv)) return rv;
@@ -224,17 +223,17 @@ nsIndexedToHTML::OnStartRequest(nsIReque
             if (NS_FAILED(rv)) return rv;
             parentStr.Assign(url);
         }
 
         // Directory index will be always encoded in UTF-8 if this is file url
         rv = mParser->SetEncoding("UTF-8");
         NS_ENSURE_SUCCESS(rv, rv);
 
-    } else if (NS_SUCCEEDED(uri->SchemeIs("gopher", &isScheme)) && isScheme) {
+    } else if (NS_SUCCEEDED(uri->SchemeIs("gopher", &isSchemeGopher)) && isSchemeGopher) {
         mExpectAbsLoc = PR_TRUE;
     } else if (NS_SUCCEEDED(uri->SchemeIs("jar", &isScheme)) && isScheme) {
         nsCAutoString path;
         rv = uri->GetPath(path);
         if (NS_FAILED(rv)) return rv;
 
         // a top-level jar directory URL is of the form jar:foo.zip!/
         // path will be of the form foo.zip!/, and its last two characters
@@ -260,41 +259,244 @@ nsIndexedToHTML::OnStartRequest(nsIReque
         }
         if (!path.EqualsLiteral("/")) {
             rv = uri->Resolve(NS_LITERAL_CSTRING(".."), parentStr);
             if (NS_FAILED(rv)) return rv;
         }
     }
 
     nsString buffer;
-    buffer.AssignLiteral("<?xml version=\"1.0\" encoding=\"");
+    buffer.AppendLiteral("<!DOCTYPE html>\n"
+                         "<html>\n<head>\n"
+                         "<meta http-equiv=\"content-type\" content=\"text/html; charset=");
     
     // Get the encoding from the parser
     // XXX - this won't work for any encoding set via a 301: line in the
     // format - this output stuff would need to move to OnDataAvailable
-    // for that. However, currently only file:// sends that, and file's HTML
-    // index mode isn't enabled yet (bug 102812)
+    // for that.
 
     nsXPIDLCString encoding;
     rv = mParser->GetEncoding(getter_Copies(encoding));
     if (NS_FAILED(rv)) return rv;
 
     AppendASCIItoUTF16(encoding, buffer);
+    buffer.AppendLiteral("\">\n"
+                         "<style type=\"text/css\">\n"
+                         ":root {\n"
+                         "  font-family: sans-serif;\n"
+                         "}\n"
+                         "img {\n"
+                         "  border: 0;\n"
+                         "}\n"
+                         "th {\n"
+                         "  text-align: left;\n"
+                         "  white-space: nowrap;\n"
+                         "}\n"
+                         "table[order] th {\n"
+                         "  cursor: pointer;\n"
+                         "}\n"
+                         "table[order] th::after {\n"
+                         "  display: none;\n"
+                         "  width: .8em;\n"
+                         "  margin-right: -.8em;\n"
+                         "  text-align: right;\n"
+                         "}\n"
+                         "table[order=\"asc\"] th::after {\n"
+                         "  content: \"\\2193\"; /* DOWNWARDS ARROW (U+2193) */\n"
+                         "}\n"
+                         "table[order=\"desc\"] th::after {\n"
+                         "  content: \"\\2191\"; /* UPWARDS ARROW (U+2191) */\n"
+                         "}\n"
+                         "table[order][order-by=\"0\"] th:first-child ,\n"
+                         "table[order][order-by=\"1\"] th:first-child + th ,\n"
+                         "table[order][order-by=\"2\"] th:first-child + th + th {\n"
+                         "  text-decoration: underline;\n"
+                         "}\n"
+                         "table[order][order-by=\"0\"] th:first-child::after ,\n"
+                         "table[order][order-by=\"1\"] th:first-child + th::after ,\n"
+                         "table[order][order-by=\"2\"] th:first-child + th + th::after {\n"
+                         "  display: inline-block;\n"
+                         "}\n"
+                         "table.remove-hidden > tbody > tr.hidden-object {\n"
+                         "  display: none;\n"
+                         "}\n"
+                         "td {\n"
+                         "  white-space: nowrap;\n"
+                         "}\n"
+                         "/* size */\n"
+                         "td:first-child + td {\n"
+                         "  text-align: right;\n"
+                         "  padding-right: 2em;\n"
+                         "  white-space: nowrap;\n"
+                         "}\n"
+                         "/* date */\n"
+                         "td:first-child + td + td {\n"
+                         "  padding-right: 1em;\n"
+                         "  white-space: nowrap;\n"
+                         "}\n"
+                         "/* time */\n"
+                         "td:last-child {\n"
+                         "  white-space: nowrap;\n"
+                         "}\n"
+                         "@-moz-document url-prefix(gopher://) {\n"
+                         "  td {\n"
+                         "    white-space: pre !important;\n"
+                         "    font-family: monospace;\n"
+                         "  }\n"
+                         "}\n"
+                         ".symlink {\n"
+                         "  font-style: italic;\n"
+                         "}\n"
+                         ".dir ,\n"
+                         ".symlink ,\n"
+                         ".file {\n"
+                         "  padding: 0 .5em;\n"
+                         "  margin-left: 20px;\n"
+                         "}\n"
+                         ".dir::before ,\n"
+                         ".file > img {\n"
+                         "  margin-right: 4px;\n"
+                         "  margin-left: -20px;\n"
+                         "  vertical-align: middle;\n"
+                         "}\n"
+                         ".dir::before {\n"
+                         "  content: url(resource://gre/res/html/folder.png);\n"
+                         "}\n"
+                         "</style>\n"
+                         "<link rel=\"stylesheet\" media=\"screen, projection\" type=\"text/css\""
+                         " href=\"chrome://global/skin/dirListing/dirListing.css\">\n");
 
-    buffer.AppendLiteral("\"?>\n"
-                         "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
-                         "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n");
+    if (!isSchemeGopher) {
+        buffer.AppendLiteral("<script type=\"application/javascript\">\n"
+                             "var gTable, gOrderBy, gTBody, gRows, gUI_showHidden;\n"
+                             "document.addEventListener(\"DOMContentLoaded\", function() {\n"
+                             "  gTable = document.getElementsByTagName(\"table\")[0];\n"
+                             "  gUI_showHidden = document.getElementById(\"UI_showHidden\");\n"
+                             "  var headCells = gTable.tHead.rows[0].cells,\n"
+                             "      hiddenObjects = false;\n"
+                             "  function rowAction(i) {\n"
+                             "    return function() {\n"
+                             "      orderBy(i);\n"
+                             "    }\n"
+                             "  }\n"
+                             "  for (var i = headCells.length - 1; i >= 0; i--)\n"
+                             "    headCells[i].addEventListener(\"click\", rowAction(i), false);\n"
+                             "  gOrderBy = gTable.getAttribute(\"order-by\");\n"
+                             "  gTBody = gTable.tBodies[0];\n"
+                             "  gRows = [];\n"
+                             "  for (var row, i = gTBody.rows.length - 1; i >= 0; i--) {\n"
+                             "    row = gTBody.rows[i];\n"
+                             "    gRows[i] = row;\n"
+                             "    if (gUI_showHidden && !hiddenObjects)\n"
+                             "      hiddenObjects = (row.className == \"hidden-object\");\n"
+                             "  }\n"
+                             "  gRows.sort(compareRows);\n"
+                             "  orderBy(gOrderBy);\n"
+                             "  if (hiddenObjects) {\n"
+                             "    gUI_showHidden.style.display = \"block\";\n"
+                             "    updateHidden();\n"
+                             "  }\n"
+                             "}, \"false\");\n"
+                             "function compareRows(rowA, rowB) {\n"
+                             "  var a = rowA.cells[gOrderBy].getAttribute(\"sortable-data\") || \"\";\n"
+                             "  var b = rowB.cells[gOrderBy].getAttribute(\"sortable-data\") || \"\";\n"
+                             "  var intA = +a;\n"
+                             "  var intB = +b;\n"
+                             "  if (a == intA && b == intB) {\n"
+                             "    a = intA;\n"
+                             "    b = intB;\n"
+                             "  } else {\n"
+                             "    a = a.toLowerCase();\n"
+                             "    b = b.toLowerCase();\n"
+                             "  }\n"
+                             "  if (a < b)\n"
+                             "    return -1;\n"
+                             "  if (a > b)\n"
+                             "    return 1;\n"
+                             "  return 0;\n"
+                             "}\n"
+                             "function orderBy(column) {\n"
+                             "  var order;\n"
+                             "  if (gOrderBy == column) {\n"
+                             "    order = gTable.getAttribute(\"order\") == \"asc\" ? \"desc\" : \"asc\";\n"
+                             "  } else {\n"
+                             "    order = \"asc\";\n"
+                             "    gOrderBy = column;\n"
+                             "    gTable.setAttribute(\"order-by\", column);\n"
+                             "    gRows.sort(compareRows);\n"
+                             "  }\n"
+                             "  gTable.setAttribute(\"order\", order);\n"
+                             "  if (order == \"asc\")\n"
+                             "    for (var i = 0; i < gRows.length; i++)\n"
+                             "      gTBody.appendChild(gRows[i]);\n"
+                             "  else\n"
+                             "    for (var i = gRows.length - 1; i >= 0; i--)\n"
+                             "      gTBody.appendChild(gRows[i]);\n"
+                             "}\n"
+                             "function updateHidden() {\n"
+                             "  gTable.className = gUI_showHidden.getElementsByTagName(\"input\")[0].checked ?\n"
+                             "                     \"\" :\n"
+                             "                     \"remove-hidden\";\n"
+                             "}\n"
+                             "</script>\n");
+    }
+    buffer.AppendLiteral("<link rel=\"icon\" type=\"image/png\" href=\"");
+    nsCOMPtr<nsIURI> innerUri = NS_GetInnermostURI(uri);
+    if (!innerUri)
+        return NS_ERROR_UNEXPECTED;
+    nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(innerUri));
+    //XXX bug 388553: can't use skinnable icons here due to security restrictions
+    if (fileURL) {
+        //buffer.AppendLiteral("chrome://global/skin/dirListing/local.png");
+        buffer.AppendLiteral("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB"
+                             "AAAAAQCAYAAAAf8/9hAAAABGd BTUEAANbY1E9YMgAAAfRJR"
+                             "EFUeNrFUk1IVFEU/t7MfU2pMRiGLVxYhGCgEoIbyZVGtFJXt"
+                             "hIDQ7BlgtvQpQs1NWgTA5YbscjZZLQNZkRpnEBFRR0sf9FG5"
+                             "zne9969z/PuvAHHEN114Xv33nfP+c453znA/15a9C1qhPS3c"
+                             "S4cYaPQtgHCmmlhvqkHo2QjLyP4WN44+azgTk3Ow9Rg/URyK"
+                             "y7hIOiRwrawTMSLHe/wJkvMHAdF/uB9wOzPIXj8cqQZvrLzA"
+                             "RsGnhdP0P6ekHJJmGGgIcB8kKaZa2p9/jffay9Q+QDNdOokG"
+                             "CoD109a9EnzKyhmwotzneAjCEUgrBOAp5GIRZD6Sy8sCEEVC"
+                             "pGBdHd17wArrMXUkLaaTu1id30RHgHHn1gUvhsVePjU1Sd5Q"
+                             "Qp+wLFI1zxsLU3jS1/jBuOU+fHhAZI7e6hq6aVwUTK0LyghA"
+                             "Meh0rVqzIZ7EE+gW2WwGQ+htPYVmJ4ggt+5TlKJRJGFapxEC"
+                             "ZZnx5yVXzPfh7/iB9N1qtlewK17r0n5cdVsUEng1CXBM47Zx"
+                             "Ypw4q9D5FP70bc5ULo4ZjfzgbuPuqDxeaJ/kjHUPZxbUhj4G"
+                             "R7G5s5hKDyDVfp1xKisWGS0tSqge9PmwVX/7D2L7X2Euj+g3"
+                             "5sDrrmJEW4TAq5Mlw+DGmHDa5WVdWBXdD5LosQ5BeW364651"
+                             "CZwAAAAAElFTkSuQmCC");
+    } else {
+        //buffer.AppendLiteral("chrome://global/skin/dirListing/remote.png");
+        buffer.AppendLiteral("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB"
+                             "AAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAohJRE"
+                             "FUeNqFU0tPE2EUPTMtr5G2DBCNYrVKxAXgKwgLNlYCiWGhG3"
+                             "eICxNZuXBl/AEQggsNO4Jxb0gwokYxGmNgIRuMSRcGbMAoVV"
+                             "NgBqSveX3e+01LwEicyZ37Te/cc859VMF/rrm5uWvkOm3bhu"
+                             "M4YM9mWZaRyWTeKXslJhKJi5FIpL1QKMQqKjQUKAmeB8FBIa"
+                             "DrNZiefmkE90i+Qq6DGPVwOIyl5RXJ7nkCnvAISMAlMALXgz"
+                             "MzM1fpY42smixEFjEMQ+eEVCq1U7L06+sGAXno7rkkfwum0+"
+                             "lMPN7VZZobkl3wLVilkMYvxIlaPYJnU0/R3HJWsnOMFIBLqO"
+                             "LkOw/n6ahAoa4o/kN6tt+bmxi5eV4yfpz/ANd1cbD3sq+gxM"
+                             "of6rV1UFUVCplaND4zgPB8xpZTbfIs/B5A5frpnQBUBAKBXa"
+                             "YWPV/cPGZMh5bwyHwgyyopqODxKKqCQDC4zS49l6Cqfm8I4P"
+                             "uhqYHlRWrmVppVjDEAR3VuCJfAjMcP7ENsv4aj9ZWI1lVKMF"
+                             "8Br4GN7ubryFsFCchTYQWeWqyTLbnw78UKqAFYngOXS/EsOa"
+                             "lSCfmysiCGb5yR47FtB9msz1BeXkZlCLl9qkKJtBuu5yLvWH"
+                             "KMUoGu6yvJ5KJGi9PI4zFNkwCycvPW1tbkyNLHpgfyjo2G2h"
+                             "PgZW6sb8attxcGclEqfafM0dHRjqamprYqrbo1FKrBi+dPkM"
+                             "vlJil0OnlkciRadxKthzvx/ssbpMxfOPejt//v/0K8oSEaqw"
+                             "6FSIGLvr5+jI+PxYeGhu5S7F7PfVNsWTnMfp7FwmBWeYVP2A"
+                             "Wwurr6bWLicay0/1SGoWna11L89e2fSvvwhlgYzG0r/wN/4X"
+                             "tnm2x4eQAAAABJRU5ErkJggg==");
+    }
+    buffer.AppendLiteral("\">\n<title>");
 
     // Anything but a gopher url needs to end in a /,
     // otherwise we end up linking to file:///foo/dirfile
 
-    buffer.AppendLiteral("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head><title>");
-
-    nsXPIDLString title;
-
     if (!mTextToSubURI) {
         mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
         if (NS_FAILED(rv)) return rv;
     }
 
     nsXPIDLString unEscapeSpec;
     rv = mTextToSubURI->UnEscapeAndConvert(encoding, titleUri.get(),
                                            getter_Copies(unEscapeSpec));
@@ -313,33 +515,32 @@ nsIndexedToHTML::OnStartRequest(nsIReque
                                                getter_Copies(unEscapeSpec));
     }
     if (NS_FAILED(rv)) return rv;
 
     nsXPIDLString htmlEscSpec;
     htmlEscSpec.Adopt(nsEscapeHTML2(unEscapeSpec.get(),
                                     unEscapeSpec.Length()));
 
+    nsXPIDLString title;
     const PRUnichar* formatTitle[] = {
         htmlEscSpec.get()
     };
 
     rv = mBundle->FormatStringFromName(NS_LITERAL_STRING("DirTitle").get(),
                                        formatTitle,
                                        sizeof(formatTitle)/sizeof(PRUnichar*),
                                        getter_Copies(title));
     if (NS_FAILED(rv)) return rv;
 
     // we want to convert string bundle to NCR
     // to ensure they're shown in any charsets
-    nsAutoString strNCR;
-    ConvertNonAsciiToNCR(title, strNCR);
-    buffer.Append(strNCR);
+    AppendNonAsciiToNCR(title, buffer);
 
-    buffer.AppendLiteral("</title>");    
+    buffer.AppendLiteral("</title>\n");    
 
     // If there is a quote character in the baseUri, then
     // lets not add a base URL.  The reason for this is that
     // if we stick baseUri containing a quote into a quoted
     // string, the quote character will prematurely close
     // the base href string.  This is a fall-back check;
     // that's why it is OK to not use a base rather than
     // trying to play nice and escaping the quotes.  See bug
@@ -347,62 +548,97 @@ nsIndexedToHTML::OnStartRequest(nsIReque
 
     if (baseUri.FindChar('"') == kNotFound)
     {
         // Great, the baseUri does not contain a char that
         // will prematurely close the string.  Go ahead an
         // add a base href.
         buffer.AppendLiteral("<base href=\"");
         AppendASCIItoUTF16(baseUri, buffer);
-        buffer.AppendLiteral("\"/>\n");
+        buffer.AppendLiteral("\">\n");
     }
     else
     {
         NS_ERROR("broken protocol handler didn't escape double-quote.");
     }
 
-    buffer.AppendLiteral("<style type=\"text/css\">\n"
-                         "img { border: 0; padding: 0 2px; vertical-align: text-bottom; }\n"
-                         "td  { font-family: monospace; padding: 2px 3px; text-align: right; vertical-align: bottom; white-space: pre; }\n"
-                         "td:first-child { text-align: left; padding: 2px 10px 2px 3px; }\n"
-                         "table { border: 0; }\n"
-                         "a.symlink { font-style: italic; }\n"
-                         "</style>\n"
-                         "</head>\n<body>\n<h1>");
+    buffer.AppendLiteral("</head>\n<body>\n<h1>");
     
     const PRUnichar* formatHeading[] = {
         htmlEscSpec.get()
     };
 
     rv = mBundle->FormatStringFromName(NS_LITERAL_STRING("DirTitle").get(),
                                        formatHeading,
                                        sizeof(formatHeading)/sizeof(PRUnichar*),
                                        getter_Copies(title));
     if (NS_FAILED(rv)) return rv;
     
-    ConvertNonAsciiToNCR(title, strNCR);
-    buffer.Append(strNCR);
-    buffer.AppendLiteral("</h1>\n<hr/><table>\n");
-
-    //buffer.AppendLiteral("<tr><th>Name</th><th>Size</th><th>Last modified</th></tr>\n");
+    AppendNonAsciiToNCR(title, buffer);
+    buffer.AppendLiteral("</h1>\n");
 
     if (!parentStr.IsEmpty()) {
         nsXPIDLString parentText;
         rv = mBundle->GetStringFromName(NS_LITERAL_STRING("DirGoUp").get(),
                                         getter_Copies(parentText));
         if (NS_FAILED(rv)) return rv;
-        
-        ConvertNonAsciiToNCR(parentText, strNCR);
-        buffer.AppendLiteral("<tr><td colspan=\"3\"><a href=\"");
+
+        buffer.AppendLiteral("<p id=\"UI_goUp\"><a class=\"up\" href=\"");
         AppendASCIItoUTF16(parentStr, buffer);
         buffer.AppendLiteral("\">");
-        buffer.Append(strNCR);
-        buffer.AppendLiteral("</a></td></tr>\n");
+        AppendNonAsciiToNCR(parentText, buffer);
+        buffer.AppendLiteral("</a></p>\n");
+    }
+
+    if (isSchemeFile) {
+        nsXPIDLString showHiddenText;
+        rv = mBundle->GetStringFromName(NS_LITERAL_STRING("ShowHidden").get(),
+                                        getter_Copies(showHiddenText));
+        if (NS_FAILED(rv)) return rv;
+
+        buffer.AppendLiteral("<p id=\"UI_showHidden\" style=\"display:none\"><label><input type=\"checkbox\" checked onchange=\"updateHidden()\">");
+        AppendNonAsciiToNCR(showHiddenText, buffer);
+        buffer.AppendLiteral("</label></p>\n");
     }
 
+    if (!isSchemeGopher) {
+        buffer.AppendLiteral("<table order-by=\"0\">\n");
+
+        nsXPIDLString columnText;
+
+        buffer.AppendLiteral(" <thead>\n"
+                             "  <tr>\n"
+                             "   <th>");
+
+        rv = mBundle->GetStringFromName(NS_LITERAL_STRING("DirColName").get(),
+                                        getter_Copies(columnText));
+        if (NS_FAILED(rv)) return rv;
+        AppendNonAsciiToNCR(columnText, buffer);
+        buffer.AppendLiteral("</th>\n"
+                             "   <th>");
+
+        rv = mBundle->GetStringFromName(NS_LITERAL_STRING("DirColSize").get(),
+                                        getter_Copies(columnText));
+        if (NS_FAILED(rv)) return rv;
+        AppendNonAsciiToNCR(columnText, buffer);
+        buffer.AppendLiteral("</th>\n"
+                             "   <th colspan=\"2\">");
+
+        rv = mBundle->GetStringFromName(NS_LITERAL_STRING("DirColMTime").get(),
+                                        getter_Copies(columnText));
+        if (NS_FAILED(rv)) return rv;
+        AppendNonAsciiToNCR(columnText, buffer);
+        buffer.AppendLiteral("</th>\n"
+                             "  </tr>\n"
+                             " </thead>\n");
+    } else {
+        buffer.AppendLiteral("<table>\n");
+    }
+    buffer.AppendLiteral(" <tbody>\n");
+
     // Push buffer to the listener now, so the initial HTML will not
     // be parsed in OnDataAvailable().
 
     rv = mListener->OnStartRequest(request, aContext);
     if (NS_FAILED(rv)) return rv;
 
     // The request may have been canceled, and if that happens, we want to
     // suppress calls to OnDataAvailable.
@@ -413,17 +649,17 @@ nsIndexedToHTML::OnStartRequest(nsIReque
     return rv;
 }
 
 NS_IMETHODIMP
 nsIndexedToHTML::OnStopRequest(nsIRequest* request, nsISupports *aContext,
                                nsresult aStatus) {
     if (NS_SUCCEEDED(aStatus)) {
         nsString buffer;
-        buffer.AssignLiteral("</table><hr/></body></html>\n");
+        buffer.AssignLiteral("</tbody></table></body></html>\n");
 
         aStatus = FormatInputStream(request, aContext, buffer);
     }
 
     mParser->OnStopRequest(request, aContext, aStatus);
     mParser = 0;
     
     return mListener->OnStopRequest(request, aContext, aStatus);
@@ -511,26 +747,89 @@ NS_IMETHODIMP
 nsIndexedToHTML::OnIndexAvailable(nsIRequest *aRequest,
                                   nsISupports *aCtxt,
                                   nsIDirIndex *aIndex) {
     nsresult rv;
     if (!aIndex)
         return NS_ERROR_NULL_POINTER;
 
     nsString pushBuffer;
-    pushBuffer.AppendLiteral("<tr>\n <td><a");
+    pushBuffer.AppendLiteral("<tr");
 
+    nsXPIDLString description;
+    aIndex->GetDescription(getter_Copies(description));
+    if (description.First() == PRUnichar('.'))
+        pushBuffer.AppendLiteral(" class=\"hidden-object\"");
+
+    pushBuffer.AppendLiteral(">\n <td sortable-data=\"");
+
+    // The sort key is the name of the item, prepended by either 0, 1 or 2
+    // in order to group items.
     PRUint32 type;
     aIndex->GetType(&type);
-    if (type == nsIDirIndex::TYPE_SYMLINK) {
-        pushBuffer.AppendLiteral(" class=\"symlink\"");
+    switch (type) {
+        case nsIDirIndex::TYPE_SYMLINK:
+            pushBuffer.AppendInt(0);
+            break;
+        case nsIDirIndex::TYPE_DIRECTORY:
+            pushBuffer.AppendInt(1);
+            break;
+        case nsIDirIndex::TYPE_FILE:
+        case nsIDirIndex::TYPE_UNKNOWN:
+            pushBuffer.AppendInt(2);
+            break;
+    }
+    PRUnichar* escaped = nsEscapeHTML2(description.get(), description.Length());
+    pushBuffer.Append(escaped);
+
+    pushBuffer.AppendLiteral("\"><a class=\"");
+    switch (type) {
+        case nsIDirIndex::TYPE_DIRECTORY:
+            pushBuffer.AppendLiteral("dir");
+            break;
+        case nsIDirIndex::TYPE_SYMLINK:
+            pushBuffer.AppendLiteral("symlink");
+            break;
+        case nsIDirIndex::TYPE_FILE:
+        case nsIDirIndex::TYPE_UNKNOWN:
+            pushBuffer.AppendLiteral("file");
+            break;
     }
+    pushBuffer.AppendLiteral("\"");
+
+    // Truncate long names to not stretch the table
+    //XXX this should be left to the stylesheet (bug 391471)
+    nsString escapedShort;
+    if (description.Length() > 31) {
+        nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
+        nsCOMPtr<nsIURI> uri;
+        rv = channel->GetURI(getter_AddRefs(uri));
+        if (NS_FAILED(rv)) return rv;
+
+        // No need to do this for Gopher, as the table has only one column in that case
+        PRBool isSchemeGopher = PR_FALSE;
+        if (!(NS_SUCCEEDED(uri->SchemeIs("gopher", &isSchemeGopher)) && isSchemeGopher)) {
+            //XXX this potentially truncates after a combining char (bug 391472)
+            description.Truncate(30);
+            if (NS_IS_HIGH_SURROGATE(description.Last()))
+                description.Truncate(description.Length()-1);
+
+            escapedShort.Adopt(nsEscapeHTML2(description.get(), description.Length()));
+            // add HORIZONTAL ELLIPSIS (U+2026)
+            escapedShort.AppendLiteral("&#8230;");
+            pushBuffer.AppendLiteral(" title=\"");
+            pushBuffer.Append(escaped);
+            pushBuffer.AppendLiteral("\"");
+        }
+    }
+    if (escapedShort.IsEmpty())
+        escapedShort.Assign(escaped);
+    nsMemory::Free(escaped);
 
     pushBuffer.AppendLiteral(" href=\"");
-
     nsXPIDLCString loc;
     aIndex->GetLocation(getter_Copies(loc));
 
     if (!mTextToSubURI) {
         mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
         if (NS_FAILED(rv)) return rv;
     }
 
@@ -565,77 +864,80 @@ nsIndexedToHTML::OnIndexAvailable(nsIReq
         // trailing '/' -- without it, the trailing '/' will be escaped, and
         // links from within that directory will be incorrect
         escFlags = esc_Forced | esc_OnlyASCII | esc_AlwaysCopy | esc_FileBaseName | esc_Colon | esc_Directory;
     }
     NS_EscapeURL(utf8UnEscapeSpec.get(), utf8UnEscapeSpec.Length(), escFlags, escapeBuf);
 
     AppendUTF8toUTF16(escapeBuf, pushBuffer);
 
-    pushBuffer.AppendLiteral("\"><img src=\"");
+    pushBuffer.AppendLiteral("\">");
 
-    switch (type) {
-    case nsIDirIndex::TYPE_DIRECTORY:
-    case nsIDirIndex::TYPE_SYMLINK:
-        pushBuffer.AppendLiteral("resource://gre/res/html/gopher-menu.gif\" alt=\"Directory: ");
-        break;
-    case nsIDirIndex::TYPE_FILE:
-    case nsIDirIndex::TYPE_UNKNOWN:
-        pushBuffer.AppendLiteral("resource://gre/res/html/gopher-unknown.gif\" alt=\"File: ");
-        break;
-    }
-    pushBuffer.AppendLiteral("\"/>");
+    if (type == nsIDirIndex::TYPE_FILE || type == nsIDirIndex::TYPE_UNKNOWN) {
+        pushBuffer.AppendLiteral("<img src=\"moz-icon://");
+        AppendUTF8toUTF16(escapeBuf, pushBuffer);
+        pushBuffer.AppendLiteral("?size=16\" alt=\"");
 
-    nsXPIDLString tmp;
-    aIndex->GetDescription(getter_Copies(tmp));
-    PRUnichar* escaped = nsEscapeHTML2(tmp.get(), tmp.Length());
-    pushBuffer.Append(escaped);
-    nsMemory::Free(escaped);
-
-    pushBuffer.AppendLiteral("</a></td>\n <td>");
-
-    PRInt64 size;
-    aIndex->GetSize(&size);
-    
-    if (nsUint64(PRUint64(size)) != nsUint64(LL_MAXUINT) &&
-        type != nsIDirIndex::TYPE_DIRECTORY &&
-        type != nsIDirIndex::TYPE_SYMLINK) {
-        nsAutoString  sizeString;
-        FormatSizeString(size, sizeString);
-        pushBuffer.Append(sizeString);
+        nsXPIDLString altText;
+        rv = mBundle->GetStringFromName(NS_LITERAL_STRING("DirFileLabel").get(),
+                                        getter_Copies(altText));
+        if (NS_FAILED(rv)) return rv;
+        AppendNonAsciiToNCR(altText, pushBuffer);
+        pushBuffer.AppendLiteral("\">");
     }
 
-    pushBuffer.AppendLiteral("</td>\n <td>");
+    pushBuffer.Append(escapedShort);
+    pushBuffer.AppendLiteral("</a></td>\n <td");
+
+    if (type == nsIDirIndex::TYPE_DIRECTORY || type == nsIDirIndex::TYPE_SYMLINK) {
+        pushBuffer.AppendLiteral(">");
+    } else {
+        PRInt64 size;
+        aIndex->GetSize(&size);
+
+        if (PRUint64(size) != LL_MAXUINT) {
+            pushBuffer.AppendLiteral(" sortable-data=\"");
+            pushBuffer.AppendInt(size);
+            pushBuffer.AppendLiteral("\">");
+            nsAutoString  sizeString;
+            FormatSizeString(size, sizeString);
+            pushBuffer.Append(sizeString);
+        } else {
+            pushBuffer.AppendLiteral(">");
+        }
+    }
+    pushBuffer.AppendLiteral("</td>\n <td");
 
     PRTime t;
     aIndex->GetLastModified(&t);
 
     if (t == -1) {
-        pushBuffer.AppendLiteral("</td>\n <td>");
+        pushBuffer.AppendLiteral("></td>\n <td>");
     } else {
+        pushBuffer.AppendLiteral(" sortable-data=\"");
+        pushBuffer.AppendInt(t);
+        pushBuffer.AppendLiteral("\">");
         nsAutoString formatted;
-        nsAutoString strNCR;    // use NCR to show date in any doc charset
         mDateTime->FormatPRTime(nsnull,
                                 kDateFormatShort,
                                 kTimeFormatNone,
                                 t,
                                 formatted);
-        ConvertNonAsciiToNCR(formatted, strNCR);
-        pushBuffer.Append(strNCR);
+        AppendNonAsciiToNCR(formatted, pushBuffer);
         pushBuffer.AppendLiteral("</td>\n <td>");
         mDateTime->FormatPRTime(nsnull,
                                 kDateFormatNone,
                                 kTimeFormatSeconds,
                                 t,
                                 formatted);
-        ConvertNonAsciiToNCR(formatted, strNCR);
-        pushBuffer.Append(strNCR);
+        // use NCR to show date in any doc charset
+        AppendNonAsciiToNCR(formatted, pushBuffer);
     }
 
-    pushBuffer.AppendLiteral("</td>\n</tr>\n");
+    pushBuffer.AppendLiteral("</td>\n</tr>");
 
     return FormatInputStream(aRequest, aCtxt, pushBuffer);
 }
 
 NS_IMETHODIMP
 nsIndexedToHTML::OnInformationAvailable(nsIRequest *aRequest,
                                         nsISupports *aCtxt,
                                         const nsAString& aInfo) {
@@ -648,21 +950,20 @@ nsIndexedToHTML::OnInformationAvailable(
     nsMemory::Free(escaped);
     pushBuffer.AppendLiteral("</td>\n <td></td>\n <td></td>\n <td></td>\n</tr>\n");
     
     return FormatInputStream(aRequest, aCtxt, pushBuffer);
 }
 
 void nsIndexedToHTML::FormatSizeString(PRInt64 inSize, nsString& outSizeString)
 {
-    nsInt64 size(inSize);
     outSizeString.Truncate();
-    if (size > nsInt64(0)) {
+    if (inSize > PRInt64(0)) {
         // round up to the nearest Kilobyte
-        PRInt64  upperSize = (size + nsInt64(1023)) / nsInt64(1024);
+        PRInt64  upperSize = (inSize + PRInt64(1023)) / PRInt64(1024);
         outSizeString.AppendInt(upperSize);
         outSizeString.AppendLiteral(" KB");
     }
 }
 
 nsIndexedToHTML::nsIndexedToHTML() {
 }
 
new file mode 100755
--- /dev/null
+++ b/toolkit/themes/pinstripe/global/dirListing/dirListing.css
@@ -0,0 +1,114 @@
+:root {
+  background-color: -moz-dialog;
+  color: -moz-dialogtext;
+  font: message-box;
+}
+
+body {
+  border: 1px solid ThreeDShadow;
+  -moz-border-radius: 10px;
+  padding: 3em;
+  min-width: 13em;
+  max-width: 52em;
+  margin: 4em auto;
+  background-color: -moz-field;
+  color: -moz-fieldtext;
+}
+
+h1 {
+  font-size: 160%;
+  margin: 0 0 .6em;
+  border-bottom: 1px solid ThreeDLightShadow;
+  font-weight: normal;
+}
+
+a {
+  text-decoration: none;
+}
+
+a:hover {
+  text-decoration: underline;
+}
+
+p {
+  font-size: 110%;
+}
+
+#UI_goUp {
+  margin-top: 0;
+  float: left;
+}
+
+#UI_showHidden {
+  margin-top: 0;
+  float: right;
+}
+
+#UI_showHidden:not(:hover) {
+  color: graytext;
+}
+
+table {
+  clear: both;
+  width: 90%;
+  margin: 0 auto;
+}
+
+thead {
+  font-size: 130%;
+}
+
+th {
+  font-weight: normal;
+}
+
+th:first-child ,
+th:first-child + th {
+  padding-right: 2em;
+}
+
+table[order] th:hover {
+  text-decoration: underline;
+}
+
+tbody > tr:not(:hover) > td:not(:first-child) {
+  color: graytext;
+}
+
+/* let 'Size' and 'Last Modified' take only as much space as they need and 'Name' all the rest */
+td:first-child + td ,
+td:first-child + td + td ,
+td:last-child {
+  width: 0;
+}
+
+.up ,
+.dir ,
+.symlink ,
+.file {
+  padding: 0 .5em;
+  margin-left: 20px;
+}
+
+.up::before ,
+.dir::before ,
+.file > img {
+  margin-right: 4px;
+  margin-left: -20px;
+  opacity: .6;
+  vertical-align: middle;
+}
+
+.up::before {
+  content: url(chrome://global/skin/dirListing/up.png);
+}
+
+.dir::before {
+  content: url(chrome://global/skin/dirListing/folder.png);
+}
+
+.up:hover::before ,
+tr:hover > td > a::before ,
+tr:hover > td > .file > img {
+  opacity: 1;
+}
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b11a80bb90f21e7176e4e4f0135f1862fd034d9c
GIT binary patch
literal 801
zc$@(t1K#|JP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00007bV*G`2iFG?
z5D+FEgI)mu000SaNLh0L01FcU01FcV0GgZ_00004XF*Lt006O%3;baP00088Nkl<Z
zc-oDV&1w@-6vzKFNhgyuHQ#9)f}%neA-K?rA1@%{1NZ{PW!FA|Zy>lR>Q*=I6kNEJ
zE`&k}{h+osCAMjrWWHza%)K+?nJA@|E_&c_FNb@6|Nr6ME8)M`*w|3h>2#^xZXe^4
z*xK5v&~hV{N)21BR$oer-EQ~U_V)HW-}j5TTyBN{tXM2QQWRy5azO}joiTRDw(TX?
zb=%Em^G&H#`bvOL=>)L5yZg4&>C_sH1|&%W9aaZ}!8)xl3<IjFqE@S+TCHNQcZ%;j
z*2BZe@If5MU(%bKo5i)YwOYMipEieKI9-zlQpUltiT=dGk6sVI4GnfM17ylA(=r)p
zi!{xuudc32oO8H-i2hK6rfYC*4X64TsX_snN)@$c3yu6d9G=C&{vh`CkxN2iIs&Oi
zJBK6rXs=5)E2xvz{Ot~A=jUOk(y)09!v`#vB)u4}=RgWmcG5cqkk!!jx!kyQ6Ze+x
zBZy-p{@fS{LfQua^FnA7fs>(!quvpeFdm%&q9{rjGd!ojjAD==d`gF!N2b8o2w=D&
zEGHsR0Kt5@kWt1L00EC6rLxdPjDR3IHRzTAqq^fq@B^yTJ_yMb<MLcJdvXDg9E@q+
zfg|8JAp!#VRAXevBRh;BJouYJ1jx_Mo}K|HxJ#;zCqZZ&g7$&{TqKQ@EQH6%MFJrx
z_XD|J$ox73(1Y*|mmzZKVX6^A0)*n9WwP!#9NKUUZ8U*x>XD#p%V(8u=N$;s6G$-$
zGR-YG%|Fp#j43rOW~LbzW>vkaX4lJ=;)l#a`Q!5^ca8H70^8;A`XkuJPk5FQmsEw7
z^O^lxDf^xmuDyQs;<0zx=b8d!SvIZFgypmLcyUhsyjU<_E-x=naD|ux=xaXh6vpPt
f$_l?q)A{%V8D6yK^+~lw00000NkvXXu0mjf4k>BU
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2d1332eda3e8c1db8c3c6bcdeb5934f7bf481817
GIT binary patch
literal 939
zc$@*N162HpP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00007bV*G`2iFG?
z5Dp|K%mDHL000SaNLh0L03N{r03N{s!)a7g00004XF*Lt006O%3;baP0009zNkl<Z
zc-oayOKclO82)xVyBj}ZJMoK{*l`O9h=_;^1Xa~47m&)011f?mx1Oqs3qn=kfT%=y
zC{k2$LL3mH7U88l3y2~SXjNKOp^jplrgjtCYp-|LUcYuW-eqkh)B_+fr_t#9X6AeR
z!2ek1&wmtnZ+`yi`_Eke2EMSckXT<{ZuIxBzkT7k<Ig^SIx!x4t<&v1;TD9;Gcz-0
zCX=zb`$_Ly{5aLsl;fj8|BTP=2^A~SRx}cQX(ACnayXT=W8pAe_~LT$`qF2|78e)u
zeGWG_cS(>(FdG-TvyZ0YuS_LlvBda;B)d~6j|ALfvFMm+6A!9&hM=3_;&+=kcj`p=
zO#12}75vN8J2~>=GY`i<c<P~u*Xs><b%S7EHE?+Hu@qxH<ZBifN8sY!Al3nFLBv~M
zUE3H6hNg6-1?m^r*<;fa(W(X%>!xE$4}{p*lL1P3bZiT`N)@tJ1#BBf4#h!w=9DRV
zk;xZUs9&Uh7c3ae0`FK#sDN&dLs4sBuco4Hv=9_IOveI<N1{-)rh~EZ>5VN``+4a@
z%4{-uU;&okhSFx(y(fXO76i^jD&$2fl7t}o&|oh7UMQnlYk(IC?p2iU?aYrkN(l!O
z92gOhRTV^s7#>N5FcuyL=lrHn=N)N16!yv}lvRiaGPWBG*3R{LA(CiP!%=NJ!0oDn
zskjSIJ}}`Bd9+M|zAwAw4(>?WfDE$*S5t;cyf=sQzh;#lU#EuA0fT^DsfrVcC@fw?
zr3vIp79`Dpq^f9W5<F&YAWil~8{DlQ-Y`9*`f56D&~}$$tE6K(8NiT#1Urt|Wv72y
zrws}nKB6M8J1Mj+=$0URnf5Nddu{9Uuh*1*k!Wdn0(!QL7ak9w*0s@LHh8WDO|N0Q
zT*qBWMZMNo6`Q4%@XDKudz*@k+1Wm~H@LtQhLMbq!W9T2Tk0SuHyzD&6icP6-AaDV
zcl+BfPp8wHO920g<HCS=<;vgnr-n@|CjoNlhK&7+{6|aLUn9F4-)z1=_fx=0*FJfY
zocimv-aic;?Ha~!>l-(3d#c&>U(UU{d<W2v9vv5RfH6R<uKwqU{|N}ugwci;rs)6x
N002ovPDHLkV1hM(r*QxP
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..85d931ddaa5b1e36f7a1109491e7080e042bd3f5
GIT binary patch
literal 721
zc$@*z0xtcDP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006O%
z3;baP0007rNkl<Zc-n<iOHUJF6g@L7uaUM45RGEBO2h@=D+miVRsxA(p&NII3lmwn
zaAo`f5P}O0JA!d<NHC&CF&blFAsdWI7Y1y=C{<Hn2Bfcfect;`OTb8+$({R6@7#0F
zeN@4JuDQ9nYvej@+lJ#fV9#b*mXXP1-YI(}CK8E@kw~PyP$<MIDl`-*37!YRK_Q^)
zHJF}$X$1F3zCx~p81-;CjHTrj$?kaqp701rz$GvO*Ml=NGgs+jjjWn1L>4g&L+6B4
zDz#Ix^y}*e0eR@|xg>uJrqk(6Jl@r1nj4Z`@GV%Skj5{>iCR5^XH!qn+;Ud3bBq*#
zOQ_=HI}hjSs6e5vDE>oww%?nZ7`b^~GJc%@0M~VKu=ldBpv1}_>a}%HRTT=ES~Na0
zfbe|AmQ!u=Ec_lo<@)KJ08|75fnBB+Jzv~BW=w~c@W^~1%PJ|T;PEJ`f<Q31%`QEc
zpsIdv2;lpnse$E1YUWm&Rg5tJM|Expm%xn259~v1zlNjrm5A0=N-$pmuYry3=Ih8?
z1qsMgVFjLAtdlLd@bAS6r~z1>1D8wjEIFxC3Hh?JAck+8k>jy#2idI8P+nd}WeB-_
zszQmh8?NUf?^tq-Qh~1PE6L=dMvK$P<1tN>0J3uP*4EbK$kNBA2l9@MhT0S0Wp1o*
z#;vy(269m<eW%RP(b0~krlz(kt-3W7s=<rrPms&yCMk3}d1P`VT6Yqyhdc59%NwN3
zUpV)pxBu_|LcF0N8mkV4NP&yKzJ834kHv?EhVD}AUeA3~Y*{(XexAj`U{-mBPuK;p
zy1M#pV&ZYEwEt9wp=sLJQvCJppGy1ihFBQPZ7cr+f8l#)n{0S_00000NkvXXu0mjf
D$7fR2
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3ab5987572b54775e4a093c9fceecac582c9d848
GIT binary patch
literal 964
zc$@*m13UbQP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00007bV*G`2iFG?
z5Dpj!qkMG$000SaNLh0L03N{r03N{s!)a7g00004XF*Lt006O%3;baP000A1Nkl<Z
zc-noFPi)&{7{;I2pY4!1cCw|}lF)XDtaMBh1tvOe&<ZBTq+Jj~NDK}uy&)l?i38Ha
z3KD_?5};n-1{^?Qk;>oEb`oeqP*~|Upk1qG-O{98<0Ouq#LgeviH(y9#9{EBpP%0E
zd7tO=;6G+;Y-}<fkG~|#G6*3_$8mmZwOZ$U;_>pEr%zw|Tj#kQJU%|Y$M5$qClUz=
zf&f)jVVWkEmX;6__~p#z)*+T<wPZ5crv44S{lQ1OKK%Hz=e=I<PlJPl2#3Q61OgZu
z8iFKA7(VzIqDNl1m!@g419uoQF>!{KLl}**&C!AW*l`xtjx^8vYBe1^&m$NN!nW;>
z4cFFjOwRs^si`Ub<>bZvDwt=9e|PBV;Y94c{df1cuNM8MUVR0XY85^{gpG|2M59rN
zybq31M_xBzIS$_Va(>Pm+&-WwH4uR{PafRcA1RiBt%`-jo(C}e@L}xe>&06qPhezZ
z1e*;S+`hy3b|HiN?}~wHTLTv7$8sh+O$3ezG;A2A4Tc7udhP@Ys)5CH0m6NcV?pyl
z^m%dQ&_jrbB9yWYia7Z6@`_pd`Rx0|bg11e8?f0spwvyw|Gw^Cyav`|;n)+8Vkggn
z<#<$08cSIT#ZnavM`5F&eD5ruUn7L_z;e?xDHbVJLBwm~o?Y7!4F}*MEV32Gwbn*<
zQ$ki!!L?+pR!!K~7be-BUY!`A;kd%pqJn`KjR$x3yC8#_MWJ(-wA8?je7Ot5s)5#J
zsFeRoAoFWVX)_gK7!8<Uk<J(KNN)r-!=a!9YdIVFvVpu?qG~x0pH=Ewlle&1^T!XT
zEZ;V5CYdxyy=h`4r(tiO2(J*r^&%iufpVh`0u4N+BBK={*KKGvEBnpzJ7j%+<@2v*
zm2Q!8fqrNy2~X}5QEED9m<||E4P~u_RjGpYyoySxI>YI?>G1UHQ=5y5jM32!d#i~S
z8$e%d8)z|zRIY(FS$92Gu$9YQY!))J{MB#1crlq=JPR<NxL4?c7cTr$e_}Y4?Iu8-
zxh&&mLB3YY-<+k=b6+pMJMp9Frt2I%N<DLHTl;n&k2DSA(z&@SSAE6QxnEuz|Lz8$
m9XN0&w+0wp#mo%;Z~g*-Lx}j`o=sZ-0000<MNUMnLSTaCDY&Bm
--- a/toolkit/themes/pinstripe/global/jar.mn
+++ b/toolkit/themes/pinstripe/global/jar.mn
@@ -103,16 +103,21 @@ classic.jar:
 +  skin/classic/global/arrow/arrow-up-sharp.gif                       (arrow/arrow-up-sharp.gif)
 +  skin/classic/global/arrow/arrow-up.gif                             (arrow/arrow-up.gif)
 +  skin/classic/global/arrow/arrow-up.png                             (arrow/arrow-up.png)
 +  skin/classic/global/console/console-toolbar.png                    (console/console-toolbar.png)
 +  skin/classic/global/console/console-bullets.png                    (console/console-bullets.png)
 +  skin/classic/global/console/console-error-caret.gif                (console/console-error-caret.gif)
 +  skin/classic/global/console/console-error-dash.gif                 (console/console-error-dash.gif)
 +  skin/classic/global/console/console.css                            (console/console.css)
++  skin/classic/global/dirListing/dirListing.css                      (dirListing/dirListing.css)
++  skin/classic/global/dirListing/folder.png                          (dirListing/folder.png)
++  skin/classic/global/dirListing/local.png                           (dirListing/local.png)
++  skin/classic/global/dirListing/remote.png                          (dirListing/remote.png)
++  skin/classic/global/dirListing/up.png                              (dirListing/up.png)
 +  skin/classic/global/icons/alltabs.png                              (icons/alltabs.png)
 +  skin/classic/global/icons/alert-error.gif                          (icons/alert-error.gif)
 +  skin/classic/global/icons/alert-message.gif                        (icons/alert-message.gif)
 +  skin/classic/global/icons/alert-question.gif                       (icons/alert-question.gif)
 +  skin/classic/global/icons/autocomplete-dropmarker.png              (icons/autocomplete-dropmarker.png)
 +  skin/classic/global/icons/autoscroll.png                           (icons/autoscroll.png)
 +  skin/classic/global/icons/blacklist_favicon.png                    (icons/blacklist_favicon.png)
 +  skin/classic/global/icons/blacklist_large.png                      (icons/blacklist_large.png)
new file mode 100755
--- /dev/null
+++ b/toolkit/themes/winstripe/global/dirListing/dirListing.css
@@ -0,0 +1,110 @@
+:root {
+  background-color: -moz-dialog;
+  color: -moz-dialogtext;
+  font: message-box;
+}
+
+body {
+  border: 1px solid ThreeDShadow;
+  -moz-border-radius: 10px;
+  padding: 3em;
+  min-width: 13em;
+  max-width: 52em;
+  margin: 4em auto;
+  background-color: -moz-field;
+  color: -moz-fieldtext;
+}
+
+h1 {
+  font-size: 160%;
+  margin: 0 0 .6em;
+  border-bottom: 1px solid ThreeDLightShadow;
+  font-weight: normal;
+}
+
+a {
+  text-decoration: none;
+}
+
+a:hover {
+  text-decoration: underline;
+}
+
+p {
+  font-size: 110%;
+}
+
+#UI_goUp {
+  margin-top: 0;
+  float: left;
+}
+
+#UI_showHidden {
+  margin-top: 0;
+  float: right;
+}
+
+#UI_showHidden:not(:hover) {
+  color: graytext;
+}
+
+table {
+  clear: both;
+  width: 90%;
+  margin: 0 auto;
+}
+
+thead {
+  font-size: 130%;
+}
+
+th {
+  font-weight: normal;
+}
+
+th:first-child ,
+th:first-child + th {
+  padding-right: 2em;
+}
+
+table[order] th:hover {
+  text-decoration: underline;
+}
+
+tbody > tr:not(:hover) > td:not(:first-child) {
+  color: graytext;
+}
+
+/* let 'Size' and 'Last Modified' take only as much space as they need and 'Name' all the rest */
+td:first-child + td ,
+td:first-child + td + td ,
+td:last-child {
+  width: 0;
+}
+
+.up ,
+.dir ,
+.symlink ,
+.file {
+  padding: 0 .5em;
+  margin-left: 20px;
+}
+
+.up::before ,
+.dir::before ,
+.file > img {
+  margin-right: 4px;
+  margin-left: -20px;
+  opacity: .6;
+  vertical-align: middle;
+}
+
+.up::before {
+  content: url(chrome://global/skin/dirListing/up.png);
+}
+
+.up:hover::before ,
+tr:hover > td > a::before ,
+tr:hover > td > .file > img {
+  opacity: 1;
+}
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..44c305a290f793d4ac5b7527a7d268a0d7e98508
GIT binary patch
literal 573
zc$@(}0>b@?P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt007q5
z)K6G40005>Nkl<Zc-qBMO-NKx6#m}KeNCw`7=|reScG7p5`r7al}5BuSGE!ZL$GCn
z+t8&8H8p4x1C|@H$k}AH4Q51XoIpiI9V~y*M&~)+_ujqF^X|L>#}M6h;d}SqchC9G
zIo~<J|6W@3Eoy}Hw{b2UVWZHt0m7PTVZNycqhup5BluX}IQgvLPEF3k)L{KYaw{(3
zAn1|8wy;dZiyiOqCQHm52SxtieZcI`A$a_9q#3@l^8p(Mo)=Hh{+^I>Ntj`vA;5f)
zrkQJMef~G!YcEjw0L^sjBp50K*H2pXN%JcxX2Oeeo!}z~MIfvbfTxj&MUeVSFDwW_
z6$+7oba!>{04uD;)R4BCPVHiMeGwi3$Dddfz8e*I_|(-Wc|i((z_CczJZvpZ<4a%T
z2IG|Z@!<iIJA0^V>7{T{GPEx!Appmr(zR;LhI<fCpj&0I84sbf_7#|(AcEhyPEv_P
zk%elUL<yE>$DEa4Gv9~5;s?`ps@Yz^t$VLY`Ek{3P)Xp_CBZX}*~N-*;;%#GQ~S}k
zIZ(PdW;gSJyN|k{@p+<uk}=dhoLf>D_!%C?=FVX#JcCvGb;PKwSY))dDxiDQ=D}6}
z>^+O^eT2F{px>JVuDOX3ZW98oOqUOX8ezk0m6dg1S9Cs0qQp4`<+tmOxzr|b00000
LNkvXXu0mjfxJV3O
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..85d931ddaa5b1e36f7a1109491e7080e042bd3f5
GIT binary patch
literal 721
zc$@*z0xtcDP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006O%
z3;baP0007rNkl<Zc-n<iOHUJF6g@L7uaUM45RGEBO2h@=D+miVRsxA(p&NII3lmwn
zaAo`f5P}O0JA!d<NHC&CF&blFAsdWI7Y1y=C{<Hn2Bfcfect;`OTb8+$({R6@7#0F
zeN@4JuDQ9nYvej@+lJ#fV9#b*mXXP1-YI(}CK8E@kw~PyP$<MIDl`-*37!YRK_Q^)
zHJF}$X$1F3zCx~p81-;CjHTrj$?kaqp701rz$GvO*Ml=NGgs+jjjWn1L>4g&L+6B4
zDz#Ix^y}*e0eR@|xg>uJrqk(6Jl@r1nj4Z`@GV%Skj5{>iCR5^XH!qn+;Ud3bBq*#
zOQ_=HI}hjSs6e5vDE>oww%?nZ7`b^~GJc%@0M~VKu=ldBpv1}_>a}%HRTT=ES~Na0
zfbe|AmQ!u=Ec_lo<@)KJ08|75fnBB+Jzv~BW=w~c@W^~1%PJ|T;PEJ`f<Q31%`QEc
zpsIdv2;lpnse$E1YUWm&Rg5tJM|Expm%xn259~v1zlNjrm5A0=N-$pmuYry3=Ih8?
z1qsMgVFjLAtdlLd@bAS6r~z1>1D8wjEIFxC3Hh?JAck+8k>jy#2idI8P+nd}WeB-_
zszQmh8?NUf?^tq-Qh~1PE6L=dMvK$P<1tN>0J3uP*4EbK$kNBA2l9@MhT0S0Wp1o*
z#;vy(269m<eW%RP(b0~krlz(kt-3W7s=<rrPms&yCMk3}d1P`VT6Yqyhdc59%NwN3
zUpV)pxBu_|LcF0N8mkV4NP&yKzJ834kHv?EhVD}AUeA3~Y*{(XexAj`U{-mBPuK;p
zy1M#pV&ZYEwEt9wp=sLJQvCJppGy1ihFBQPZ7cr+f8l#)n{0S_00000NkvXXu0mjf
D$7fR2
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c6786a1e7f2c64a9f5f949a28aa0856381b03e9d
GIT binary patch
literal 727
zc$@*(0x127P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00007bV*G`2iFG?
z5D*ErQe#*E000SaNLh0L03N{r03N{s!)a7g00004XF*Lt006O%3;baP0007JNkl<Z
zc-oCpT}V@57=F(7&9gI?&gsw#VJn3w43WSa(M3^IbP-+IRdmr!H~o<0g%FW9VUZz{
zx1*wqf<gu%VW3d7$;4&Wq$FA^OJ&o!zjJnede7OkRjzvBIUnD5-skzA_kBO0Ojs|o
zZts9stLYP3@Ru-`A$QT@&(yELln~BV?9;T|q&%@zE*HFmc11Ox7DYu<WYkP%IoDm;
zb3kf}qoLLg2jlTMl7uzch-iM^o9NF@mI^S!`IZw;PTCvVje}R?w~(9}f~VF2m(7MM
zo<~!s6LWLR$cE&Jj-HCAF9xJzl&Ts6nua=abu%Ch8UlR}ucOjgfrUUE)onZ+ZYwMn
z3t|xtLKVYX;0UGJ2`OEKrPDabGZR!vG6dwC7dP$g9`RvUb3Ft>fZOTD^K)aExV;nm
z0UP~J8xC}ynx{`z{G&mM)to`L2{tHF%*ZR=V<ngf3O9NM+Mx?mWM~A@Z~&=Q`opTB
zP=$(8fU2*hdzC{rwT$IY^92V=Uc}dM5GG*{+Kvv9@LKt)Yk6o?!MFEQ7`<^k#zb<S
zNhYwiw1U>|ev%LBo!FYs@z69Xo!g6P|251;(Q7zZob|!eaS6;4C4n!$l2oHfbhBa%
zPDLX=Oh3>T-h{@7$MBNTgkX{*aPGJY<R8)HluRW-q$w$4fw=i<>X0*cA@KOj`m@&{
zyU4I@mB9AS9&qA2l0RHXv=s4Ms7e|${$VUGC4K%7KGM-Tqq4$*d#74?BFOSj=-n>e
zZ{T|zzTW#7EWQJgD?Vozf!EuFe}`Hm>!ZqV5ZHf`OGS+4`~W;y3qL;H(J}x4002ov
JPDHLkV1j{PMs)xH
--- a/toolkit/themes/winstripe/global/jar.mn
+++ b/toolkit/themes/winstripe/global/jar.mn
@@ -57,17 +57,21 @@ classic.jar:
         skin/classic/global/arrow/arrow-rit-hov.gif                 (arrow/arrow-rit-hov.gif)
         skin/classic/global/arrow/arrow-rit-sharp.gif               (arrow/arrow-rit-sharp.gif)
         skin/classic/global/arrow/arrow-rit-sharp-end.gif           (arrow/arrow-rit-sharp-end.gif)
         skin/classic/global/arrow/arrow-up.gif                      (arrow/arrow-up.gif)
         skin/classic/global/arrow/arrow-up-dis.gif                  (arrow/arrow-up-dis.gif)
         skin/classic/global/arrow/arrow-up-hov.gif                  (arrow/arrow-up-hov.gif)
         skin/classic/global/arrow/arrow-up-sharp.gif                (arrow/arrow-up-sharp.gif)
         skin/classic/global/checkbox/cbox-check.gif                 (checkbox/cbox-check.gif)
-        skin/classic/global/checkbox/cbox-check-dis.gif             (checkbox/cbox-check-dis.gif) 
+        skin/classic/global/checkbox/cbox-check-dis.gif             (checkbox/cbox-check-dis.gif)
+        skin/classic/global/dirListing/dirListing.css               (dirListing/dirListing.css)
+        skin/classic/global/dirListing/local.png                    (dirListing/local.png)
+        skin/classic/global/dirListing/remote.png                   (dirListing/remote.png)
+        skin/classic/global/dirListing/up.png                       (dirListing/up.png)
         skin/classic/global/Filepicker.png                          (filepicker/Filepicker.png)
 	skin/classic/global/icons/alltabs-box-overflow-end-bkgnd-hover.png (icons/alltabs-box-overflow-end-bkgnd-hover.png)
 	skin/classic/global/icons/alltabs-box-overflow-start-bkgnd-hover.png (icons/alltabs-box-overflow-start-bkgnd-hover.png)
 	skin/classic/global/icons/alltabs-box-overflow-end-bkgnd.png   (icons/alltabs-box-overflow-end-bkgnd.png)
     skin/classic/global/icons/alltabs-box-overflow-start-bkgnd-animate.png   (icons/alltabs-box-overflow-start-bkgnd-animate.png)
 	skin/classic/global/icons/alltabs-box-overflow-end-bkgnd-animate.png   (icons/alltabs-box-overflow-end-bkgnd-animate.png)
 	skin/classic/global/icons/alltabs-box-overflow-start-bkgnd.png (icons/alltabs-box-overflow-start-bkgnd.png)
         skin/classic/global/icons/autocomplete-dropmark-arrow.png   (icons/autocomplete-dropmark-arrow.png)