mirror of
https://github.com/zebrajr/express.git
synced 2025-12-06 12:19:51 +01:00
parent
0e5f2f84ea
commit
6614352563
|
|
@ -1,6 +1,8 @@
|
|||
unreleased
|
||||
==========
|
||||
|
||||
* Add support for `app.set('views', array)`
|
||||
- Views are looked up in sequence in array of directories
|
||||
* Fix `res.send(status)` to mention `res.sendStatus(status)`
|
||||
* Use `content-disposition` module for `res.attachment`/`res.download`
|
||||
- Sends standards-compliant `Content-Disposition` header
|
||||
|
|
|
|||
|
|
@ -513,7 +513,10 @@ app.render = function(name, options, fn){
|
|||
});
|
||||
|
||||
if (!view.path) {
|
||||
var err = new Error('Failed to lookup view "' + name + '" in views directory "' + view.root + '"');
|
||||
var dirs = Array.isArray(view.root) && view.root.length > 1
|
||||
? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"'
|
||||
: 'directory "' + view.root + '"'
|
||||
var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
|
||||
err.view = view;
|
||||
return fn(err);
|
||||
}
|
||||
|
|
|
|||
79
lib/view.js
79
lib/view.js
|
|
@ -15,7 +15,6 @@ var utils = require('./utils');
|
|||
var dirname = path.dirname;
|
||||
var basename = path.basename;
|
||||
var extname = path.extname;
|
||||
var exists = fs.existsSync || path.existsSync;
|
||||
var join = path.join;
|
||||
var resolve = path.resolve;
|
||||
|
||||
|
|
@ -53,28 +52,32 @@ function View(name, options) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Lookup view by the given `path`
|
||||
* Lookup view by the given `name`
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {String} name
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
View.prototype.lookup = function lookup(path) {
|
||||
var ext = this.ext;
|
||||
var root = this.root;
|
||||
View.prototype.lookup = function lookup(name) {
|
||||
var path;
|
||||
var roots = [].concat(this.root);
|
||||
|
||||
debug('lookup "%s"', path);
|
||||
debug('lookup "%s"', name);
|
||||
|
||||
// resolve the path
|
||||
path = resolve(root, path);
|
||||
for (var i = 0; i < roots.length && !path; i++) {
|
||||
var root = roots[i];
|
||||
|
||||
// <path>.<engine>
|
||||
if (exists(path)) return path;
|
||||
// resolve the path
|
||||
var loc = resolve(root, name);
|
||||
var dir = dirname(loc);
|
||||
var file = basename(loc);
|
||||
|
||||
// <path>/index.<engine>
|
||||
path = join(dirname(path), basename(path, ext), 'index' + ext);
|
||||
if (exists(path)) return path;
|
||||
// resolve the file
|
||||
path = this.resolve(dir, file);
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -89,3 +92,51 @@ View.prototype.render = function render(options, fn) {
|
|||
debug('render "%s"', this.path);
|
||||
this.engine(this.path, options, fn);
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve the file within the given directory.
|
||||
*
|
||||
* @param {string} dir
|
||||
* @param {string} file
|
||||
* @private
|
||||
*/
|
||||
|
||||
View.prototype.resolve = function resolve(dir, file) {
|
||||
var ext = this.ext;
|
||||
var path;
|
||||
var stat;
|
||||
|
||||
// <path>.<ext>
|
||||
path = join(dir, file);
|
||||
stat = tryStat(path);
|
||||
|
||||
if (stat && stat.isFile()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// <path>/index.<ext>
|
||||
path = join(dir, basename(file, ext), 'index' + ext);
|
||||
stat = tryStat(path);
|
||||
|
||||
if (stat && stat.isFile()) {
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a stat, maybe.
|
||||
*
|
||||
* @param {string} path
|
||||
* @return {fs.Stats}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function tryStat(path) {
|
||||
debug('stat "%s"', path);
|
||||
|
||||
try {
|
||||
return fs.statSync(path);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,6 +131,64 @@ describe('app', function(){
|
|||
})
|
||||
})
|
||||
|
||||
describe('when "views" is given', function(){
|
||||
it('should lookup the file in the path', function(done){
|
||||
var app = express();
|
||||
|
||||
app.set('views', __dirname + '/fixtures/default_layout');
|
||||
app.locals.user = { name: 'tobi' };
|
||||
|
||||
app.render('user.jade', function(err, str){
|
||||
if (err) return done(err);
|
||||
str.should.equal('<p>tobi</p>');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
describe('when array of paths', function(){
|
||||
it('should lookup the file in the path', function(done){
|
||||
var app = express();
|
||||
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
|
||||
|
||||
app.set('views', views);
|
||||
app.locals.user = { name: 'tobi' };
|
||||
|
||||
app.render('user.jade', function(err, str){
|
||||
if (err) return done(err);
|
||||
str.should.equal('<span>tobi</span>');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should lookup in later paths until found', function(done){
|
||||
var app = express();
|
||||
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
|
||||
|
||||
app.set('views', views);
|
||||
app.locals.name = 'tobi';
|
||||
|
||||
app.render('name.jade', function(err, str){
|
||||
if (err) return done(err);
|
||||
str.should.equal('<p>tobi</p>');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should error if file does not exist', function(done){
|
||||
var app = express();
|
||||
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
|
||||
|
||||
app.set('views', views);
|
||||
app.locals.name = 'tobi';
|
||||
|
||||
app.render('pet.jade', function(err, str){
|
||||
err.message.should.equal('Failed to lookup view "pet.jade" in views directories "' + __dirname + '/fixtures/local_layout" or "' + __dirname + '/fixtures/default_layout"');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a "view" constructor is given', function(){
|
||||
it('should create an instance of it', function(done){
|
||||
var app = express();
|
||||
|
|
|
|||
1
test/fixtures/default_layout/name.jade
vendored
Normal file
1
test/fixtures/default_layout/name.jade
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
p= name
|
||||
1
test/fixtures/default_layout/user.jade
vendored
Normal file
1
test/fixtures/default_layout/user.jade
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
p= user.name
|
||||
1
test/fixtures/local_layout/user.jade
vendored
Normal file
1
test/fixtures/local_layout/user.jade
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
span= user.name
|
||||
|
|
@ -114,6 +114,54 @@ describe('res', function(){
|
|||
.expect('<p>This is an email</p>', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "views" is given', function(){
|
||||
it('should lookup the file in the path', function(done){
|
||||
var app = express();
|
||||
|
||||
app.set('views', __dirname + '/fixtures/default_layout');
|
||||
|
||||
app.use(function(req, res){
|
||||
res.render('user.jade', { user: { name: 'tobi' } });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('<p>tobi</p>', done);
|
||||
})
|
||||
|
||||
describe('when array of paths', function(){
|
||||
it('should lookup the file in the path', function(done){
|
||||
var app = express();
|
||||
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
|
||||
|
||||
app.set('views', views);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.render('user.jade', { user: { name: 'tobi' } });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('<span>tobi</span>', done);
|
||||
})
|
||||
|
||||
it('should lookup in later paths until found', function(done){
|
||||
var app = express();
|
||||
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
|
||||
|
||||
app.set('views', views);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.render('name.jade', { name: 'tobi' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('<p>tobi</p>', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.render(name, option)', function(){
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user