diff --git a/README.md b/README.md index 5dde8372..88da5f3e 100644 --- a/README.md +++ b/README.md @@ -80,11 +80,16 @@ provided locals: * `path` is the full filesystem path to `directory`. * `style` is the default stylesheet or the contents of the `stylesheet` option. * `viewName` is the view name provided by the `view` option. + * `sorting` is the function to be used for custom sorting, provided by the `sorting` option ##### view Display mode. `tiles` and `details` are available. Defaults to `tiles`. +##### sorting + +Optional sorting of the files in the listing. To apply custom sorting pass a function for handling the sorting. If nothing is passed, files will be sortted on name. + ## Examples ### Serve directory indexes with vanilla node.js http server diff --git a/index.js b/index.js index 7b9d856c..9270b292 100644 --- a/index.js +++ b/index.js @@ -97,6 +97,7 @@ function serveIndex(root, options) { var stylesheet = opts.stylesheet || defaultStylesheet; var template = opts.template || defaultTemplate; var view = opts.view || 'tiles'; + var sorting = opts.sorting; return function (req, res, next) { if (req.method !== 'GET' && req.method !== 'HEAD') { @@ -160,7 +161,7 @@ function serveIndex(root, options) { // not acceptable if (!type) return next(createError(406)); - serveIndex[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view, template, stylesheet); + serveIndex[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view, template, stylesheet, sorting); }); }); }; @@ -170,7 +171,7 @@ function serveIndex(root, options) { * Respond with text/html. */ -serveIndex.html = function _html(req, res, files, next, dir, showUp, icons, path, view, template, stylesheet) { +serveIndex.html = function _html(req, res, files, next, dir, showUp, icons, path, view, template, stylesheet, sorting) { var render = typeof template !== 'function' ? createHtmlRender(template) : template @@ -189,7 +190,7 @@ serveIndex.html = function _html(req, res, files, next, dir, showUp, icons, path }); // sort file list - fileList.sort(fileSort); + fileList.sort(fileSort(sorting)); // read stylesheet fs.readFile(stylesheet, 'utf8', function (err, style) { @@ -330,15 +331,18 @@ function createHtmlRender(template) { * Sort function for with directories first. */ -function fileSort(a, b) { - // sort ".." to the top - if (a.name === '..' || b.name === '..') { - return a.name === b.name ? 0 - : a.name === '..' ? -1 : 1; - } +function fileSort(sortFn) { + return function (a, b) { + // sort ".." to the top + if (a.name === '..' || b.name === '..') { + return a.name === b.name ? 0 + : a.name === '..' ? -1 : 1; + } - return Number(b.stat && b.stat.isDirectory()) - Number(a.stat && a.stat.isDirectory()) || - String(a.name).toLocaleLowerCase().localeCompare(String(b.name).toLocaleLowerCase()); + return sortFn ? sortFn(a, b) + : Number(b.stat && b.stat.isDirectory()) - Number(a.stat && a.stat.isDirectory()) || + String(a).toLocaleLowerCase().localeCompare(String(b).toLocaleLowerCase()) + } } /** diff --git a/test/test.js b/test/test.js index 408ba92d..bddb7e41 100644 --- a/test/test.js +++ b/test/test.js @@ -286,6 +286,39 @@ describe('serveIndex(root)', function () { }); }); + describe('with "sorting" option', function () { + it('should sort files on name by default', function (done) { + var server = createServer(fixtures); + + request(server) + .get('/') + .expect(function (res) { + if (res.text.indexOf('todo.txt') > res.text.indexOf('file #1.txt')){ + return; + } + throw new Error('default sorting is not by name'); + }) + .expect(200, done); + }); + + it('should use options.sorting when being passed a function', function (done) { + var server = createServer(fixtures, {sorting: function sortByFilesize(a, b) { + return a.stat.size < b.stat.size ? 1 : -1; + }}); + + request(server) + .get('/') + .expect(function (res) { + if (res.text.indexOf('todo.txt') < res.text.indexOf('file #1.txt')){ + return; + } + throw new Error('sorting function not applied'); + }) + .expect(200, done); + }); + + }); + describe('with "icons" option', function () { it('should include icons for html', function (done) { var server = createServer(fixtures, {'icons': true})