Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Directory Middleware Improvements: #968

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
70 changes: 60 additions & 10 deletions lib/middleware/directory.js
Expand Up @@ -70,6 +70,7 @@ exports = module.exports = function directory(root, options){
if (!root) throw new Error('directory() root path required');
var hidden = options.hidden
, icons = options.icons
, view = options.view || 'tiles'
, filter = options.filter
, root = normalize(root + sep);

Expand Down Expand Up @@ -109,7 +110,7 @@ exports = module.exports = function directory(root, options){

// not acceptable
if (!type) return next(utils.error(406));
exports[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path);
exports[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow. lol

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from being a function with 9 parameters, what's wrong with this line?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol that's it. we need to refactor that eventually

});
});
};
Expand All @@ -119,7 +120,7 @@ exports = module.exports = function directory(root, options){
* Respond with text/html.
*/

exports.html = function(req, res, files, next, dir, showUp, icons, path){
exports.html = function(req, res, files, next, dir, showUp, icons, path, view){
fs.readFile(__dirname + '/../public/directory.html', 'utf8', function(err, str){
if (err) return next(err);
fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){
Expand All @@ -131,7 +132,8 @@ exports.html = function(req, res, files, next, dir, showUp, icons, path){
if (showUp) files.unshift({ name: '..' });
str = str
.replace('{style}', style)
.replace('{files}', html(files, dir, icons))
.replace('{iconstyle}', iconStyle(files, icons))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add {iconstyle}? Can you just concat the icon style with the regular style (putting icon style first)?

.replace('{files}', html(files, dir, icons, view))
.replace('{directory}', dir)
.replace('{linked-path}', htmlPath(dir));
res.setHeader('Content-Type', 'text/html');
Expand Down Expand Up @@ -185,32 +187,80 @@ function htmlPath(dir) {
}).join(' / ');
}

/**
* Load icon images, return css string.
*/

function iconStyle (files, useIcons) {
if (!useIcons) return '';
var data = {};
var views = { tiles: [], details: [], mobile: [] };

for (var i=0; i < files.length; i++) {
var file = files[i];
if (file.name == '..') continue;

var isDir = '..' == file.name || (file.stat && file.stat.isDirectory());
var icon = isDir ? icons.folder : icons[extname(file.name)] || icons.default;

var ext = extname(file.name);
ext = isDir ? '.directory' : (icons[ext] ? ext : '.default');

if (data[icon]) continue;
data[icon] = ext + ' .name{background-image: url(data:image/png;base64,' + load(icon)+');}';
views.tiles.push('.view-tiles ' + data[icon]);
views.details.push('.view-details ' + data[icon]);
views.mobile.push('#files ' + data[icon]);
}

var style = views.tiles.join('\n')
+ '\n'+views.details.join('\n')
+ '\n@media (max-width: 768px) {\n\t'
+ views.mobile.join('\n\t')
+ '\n}';
return style;
}

/**
* Map html `files`, returning an html unordered list.
*/

function html(files, dir, useIcons) {
return '<ul id="files">' + files.map(function(file){
var icon = ''
, isDir
function html(files, dir, useIcons, view) {
return '<ul id="files" class="view-'+view+'">'
+ (view == 'details' ? (
'<li class="header">'
+ '<span class="name">Name</span>'
+ '<span class="size">Size</span>'
+ '<span class="date">Modified</span>'
+ '</li>') : '')
+ files.map(function(file){
var isDir
, classes = []
, path = dir.split('/').map(function (c) { return encodeURIComponent(c); });

if (useIcons) {
var ext = extname(file.name);
isDir = '..' == file.name || (file.stat && file.stat.isDirectory());
icon = isDir ? icons.folder : icons[extname(file.name)] || icons.default;
icon = '<img src="data:image/png;base64,' + load(icon) + '" />';
ext = isDir ? '.directory' : (icons[ext] ? ext : '.default');
classes.push('icon');
classes.push(ext.replace('.',''));
}

path.push(encodeURIComponent(file.name));

var date = file.name == '..' ? ''
: file.stat.mtime.toDateString()+' '+file.stat.mtime.toLocaleTimeString();
var size = file.name == '..' ? '' : file.stat.size;

return '<li><a href="'
+ utils.normalizeSlashes(normalize(path.join('/')))
+ '" class="'
+ classes.join(' ') + '"'
+ ' title="' + file.name + '">'
+ icon + file.name + '</a></li>';
+ '<span class="name">'+file.name+'</span>'
+ '<span class="size">'+size+'</span>'
+ '<span class="date">'+date+'</span>'
+ '</a></li>';

}).join('\n') + '</ul>';
}
Expand Down
4 changes: 3 additions & 1 deletion lib/public/directory.html
Expand Up @@ -2,8 +2,10 @@
<html>
<head>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>listing directory {directory}</title>
<style>{style}</style>
<style>{iconstyle}</style>
<script>
function $(id){
var el = 'string' == typeof id
Expand Down Expand Up @@ -44,7 +46,7 @@
var classes = this.getClasses().filter(function(curr){
return curr != name;
});
this.setAttribute('class', classes);
this.setAttribute('class', classes.join(' '));
};

return el;
Expand Down
123 changes: 95 additions & 28 deletions lib/public/style.css
@@ -1,5 +1,6 @@
* { margin: 0; padding: 0; outline: 0; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no single line CSS selector/rules, please.


body {
margin: 0;
padding: 80px 100px;
font: 13px "Helvetica Neue", "Lucida Grande", "Arial";
background: #ECE9E9 -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9));
Expand All @@ -9,7 +10,6 @@ body {
-webkit-font-smoothing: antialiased;
}
h1, h2, h3 {
margin: 0;
font-size: 22px;
color: #343434;
}
Expand All @@ -21,21 +21,15 @@ h1 {
font-size: 60px;
}
h2 {
margin-top: 10px;
margin-top: 10px;
}
h3 {
margin: 5px 0 10px 0;
padding-bottom: 5px;
border-bottom: 1px solid #eee;
font-size: 18px;
}
ul {
margin: 0;
padding: 0;
}
ul li {
margin: 5px 0;
padding: 3px 8px;
list-style: none;
}
ul li:hover {
Expand Down Expand Up @@ -64,46 +58,35 @@ a:hover {
color: #303030;
}
#stacktrace {
margin-top: 15px;
margin-top: 15px;
}
.directory h1 {
margin-bottom: 15px;
font-size: 18px;
}
ul#files {
width: 100%;
height: 500px;
height: 100%;
overflow: hidden;
}
ul#files li {
padding: 0;
}
ul#files li img {
position: absolute;
top: 5px;
left: 5px;
float: left;
width: 30%;
line-height: 25px;
margin: 1px;
}
ul#files li a {
position: relative;
display: block;
margin: 1px;
width: 30%;
height: 25px;
line-height: 25px;
text-indent: 8px;
float: left;
border: 1px solid transparent;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
overflow: hidden;
text-overflow: ellipsis;
}
ul#files li a.icon {
text-indent: 25px;
white-space: nowrap;
}
ul#files li a:focus,
ul#files li a:hover {
outline: none;
background: rgba(255,255,255,0.65);
border: 1px solid #ececec;
}
Expand Down Expand Up @@ -139,3 +122,87 @@ ul#files li a.highlight {
width: 120px;
opacity: 1.0;
}

/*views*/
#files span { display: inline-block; overflow: hidden; text-overflow: ellipsis; text-indent: 10px; }
#files .name { background-repeat: no-repeat; }
#files .icon .name { text-indent: 28px; }

/*tiles*/
.view-tiles .name { width: 100%; background-position: 8px 5px; }
.view-tiles .size,
.view-tiles .date { display: none; }

/*details*/
ul#files.view-details li { float: none; display: block; width: 90%; }
ul#files.view-details li.header { height: 25px; background: #000; color: #fff; font-weight: bold; }
.view-details .header { border-radius: 5px; }

.view-details .name { width: 60%; background-position: 8px 5px; }
.view-details .size { width: 10%; }
.view-details .date { width: 30%; }
.view-details .size,
.view-details .date { text-align: right; direction: rtl; }

@media (max-width: 768px) {
body {
font-size: 13px;
line-height: 16px;
padding: 0;
}
#search {
position: static;
width: 100%;
font-size: 2em;
line-height: 1.8em;
text-indent: 10px;
border: 0;
border-radius: 0;
padding: 10px 0;
margin: 0;
}
#search:focus {
width: 100%;
border: 0;
opacity: 1;
}
.directory h1 {
font-size: 2em;
line-height: 1.5em;
color: #fff;
background: #000;
padding: 15px 10px;
margin: 0;
}
ul#files {
border-top: 1px solid #cacaca;
}
ul#files li {
float: none;
width: auto !important;
display: block;
border-bottom: 1px solid #cacaca;
font-size: 2em;
line-height: 1.2em;
text-indent: 0;
margin: 0;
}
ul#files li:nth-child(odd) {
background: #e0e0e0;
}
ul#files li a {
height: auto;
border: 0;
border-radius: 0;
padding: 15px 10px;
}
ul#files li a:focus,
ul#files li a:hover {
border: 0;
}
#files .header,
#files .size,
#files .date { display: none !important; }
#files .name { float: none; display: inline-block; width: 100%; text-indent: 0; background-position: 0 0; }
#files .icon .name { text-indent: 41px; }
}