directoryListing method

Future<Response> directoryListing(
  1. Request req,
  2. Directory dir, {
  3. required bool linkToParent,
})

Method used to generate a directory listing.

This method is invoked by the handler if the request is for a directory, the directory exists, the directory does not have any of the default files, and allowDirectoryListing is true.

It is passed the Request, Directory. If linkToParent is true, if a link to the parent directory is permitted (i.e. this is not the directory registered with the StaticFiles).

Applications can create a subclass of StaticFiles and implement their own directory listing method, if they want to create a custom directory listings.

Null-safety breaking change: linkToParent is required.

Implementation

Future<Response> directoryListing(Request req, Directory dir,
    {required bool linkToParent}) async {
  final components = dir.path.split('/');
  String title;
  if (2 <= components.length &&
      components[components.length - 2].isNotEmpty &&
      components.last.isEmpty) {
    title = components[components.length - 2];
  } else {
    title = 'Listing';
  }

  final buf = StringBuffer('''
<!doctype html>
<html>
<head>
  <title>${HEsc.text(title)}</title>
  <style type="text/css">
  body { font-family: sans-serif; }
  ul { font-family: monospace; font-size: larger; list-style-type: none; }
  a { text-decoration: none; display: inline-block; padding: 0.5ex 0.75em; }
  a.parent { border-radius: 0 0 2ex 2ex; }
  a.dir { border-radius: 2ex 2ex 0 0; }
  a.file { border-radius: 2ex; }
  a:hover { text-decoration: underline; }
  a.parent:hover { background: #ddd; }
  a.dir:hover { background: #ddd; }
  a.file:hover { background: #eee; }
  </style>
</head>
<body>
<h1>${HEsc.text(title)}</h1>
<ul>
''');

  if (linkToParent) {
    buf.write(
        '<li><a href=".." title="Parent" class="parent">&#x2191;</a></li>\n');
  }

  await for (var entity in dir.list()) {
    String n;
    String cl;
    if (entity is Directory) {
      n = '${entity.uri.pathSegments[entity.uri.pathSegments.length - 2]}/';
      cl = 'class="dir"';
    } else {
      n = entity.uri.pathSegments.last;
      cl = 'class="file"';
    }
    buf.write('<li><a href="${HEsc.attr(n)}" $cl>${HEsc.text(n)}</a></li>\n');
  }

  buf.write('''
</ul>
</body>
</html>
''');

  final resp = ResponseBuffered(ContentType.html)
    ..headerAddDate('Date', DateTime.now())
    ..write(buf.toString());
  return resp;
}