From 0af0592d83b08fecf8d2fee1a41f7009f63dd85f Mon Sep 17 00:00:00 2001 From: Dav Glass Date: Mon, 1 Nov 2010 08:42:28 -0500 Subject: [PATCH] Added express middleware for pre-rendering layouts as well as support for UA based partials --- lib/express.js | 109 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 99 insertions(+), 10 deletions(-) diff --git a/lib/express.js b/lib/express.js index 6be11af..2e53aea 100644 --- a/lib/express.js +++ b/lib/express.js @@ -4,11 +4,75 @@ */ YUI.add('express', function(Y) { + if (YUI.express) { + //Catch double loading of YUI().use('*'); + return; + } + var path = YUI.require('path'), fs = YUI.require('fs'), sys = YUI.require('sys'), DEBUG = false; + /** + * The default content holder for partials, if one is not given this one is used. + * @property defaultContent + * @static + */ + YUI.defaultContent = '#content'; + /** + * Express middleware to "pre-parse" the layout and add it to a YUI instance + * that is then bound to the req as req.Y. Calling res.send() will automatically call + * Y.config.doc.outerHTML and echo to the response. + * The middleware can be used like this: http://gist.github.com/657453 + * @static + * @method express + */ + YUI.express = function(req, res, next) { + var fn = function(req, res, next, yConfig) { + if (!req.Y) { + var ua = req.headers['user-agent']; + YUI({ debug: DEBUG, UA: ua }).use('*', function(Y) { + Y.config.win.location.href = req.originalUrl; + Y.express = yConfig; + req.Y = res.Y = Y; + if (yConfig.render) { + res._ySend = res.send; + res.sub = function(sub) { + var html = this.Y.config.doc.outerHTML; + html = this.Y.substitute(html, sub); + this.Y.config.doc.innerHTML = html; + }; + res.send = function(str) { + Y.config.doc.innerHTML = str; + this.send = function() { + this._ySend.call(this, Y.config.doc.outerHTML); + req.Y = res.Y = null; + YUI._express[Y.id] = Y; + YUI.cleanExpress(); + }; + next(); + }; + var c = {}; + if (yConfig.locals) { + c.locals = yConfig.locals; + } + res.render(yConfig.render, c); + } + }); + } else { + next(); + } + }; + if (req && res && next) { + return fn.call(this, req, res, next); + } else { + return function(req2, res2, next2) { + fn.call(this, req2, res2, next2, req); + }; + } + }; + /** * Hash of all YUI instances uses in the course of rendering the pages. * So they can be blown away after they are used. @@ -64,9 +128,11 @@ YUI.add('express', function(Y) { * { * name: 'header', //Name of the /views/partial/{name}.html file to load * method: 'append', //append,prepend,appendChild - * node: '#conent', //Any valid selector + * node: '#content', //Any valid selector * enum: 'one', //one,all - * fn: function //The callback function to run after the action. + * fn: function, //The callback function to run after the action. + * ua: 'webkit', //Any truthy value from Y.UA + * test: function(Y, options) //Test function passed Y instance and render options. Return true to include this partial. * } * @property partials * @static @@ -141,7 +207,10 @@ YUI.add('express', function(Y) { YUI.render = function(content, options) { var eY, locals = options.locals, ua = options.scope.headers['user-agent']; - + + if (options.scope.res.Y && !options.partial) { + locals.instance = options.scope.res.Y; + } if (locals.instance) { eY = locals.instance; eY.UA = YUI.Env.parseUA(ua); @@ -185,16 +254,34 @@ YUI.add('express', function(Y) { } if (parts && parts.length) { eY.each(parts, function(p) { - var str = locals.partial(p.name); - var enum = p.enum || 'one'; - var method = p.method || 'append'; - eY[enum](p.node)[method](str); - if (p.fn) { - p.fn(eY, options, p); + var run = true; + if (p.test && eY.Lang.isFunction(p.test)) { + run = false; + if (p.test(eY, options)) { + run = true; + } + } + if (p.ua) { + run = false; + if (eY.UA[p.ua]) { + run = true; + } + } + if (run) { + var str = locals.partial(p.name); + var enum = p.enum || 'one'; + var method = p.method || 'append'; + eY[enum](p.node)[method](str); + if (p.fn) { + p.fn(eY, options, p); + } } }); } var html = docType + "\n"; + if (!locals.content) { + locals.content = YUI.defaultContent; + } var content = eY.one(locals.content); if (content && locals.body) { content.prepend(locals.body); @@ -209,7 +296,9 @@ YUI.add('express', function(Y) { if (locals.sub) { html = eY.substitute(html, locals.sub); } - YUI._express[eY.id] = eY; + if (!options.scope.res.Y) { + YUI._express[eY.id] = eY; + } YUI.cleanExpress(); return html; } else {