API Docs for: 0.2.0
Show:

File: lib/middleware.js

/*
 * Copyright (c) 2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint node:true, nomen: true */

/**
Provides some basic features to expose yui configurations information through `app.expose()`
that could be used to boot `YUI` in the client runtime. It also provide some sugar to
expose static assests that are YUI related.

@module express-yui/lib/middleware
**/

'use strict';

var client = require('./client'),
    utils = require('./utils');

/**
Exports few middleware.

@class middleware
@static
@uses client, utils, *debug, *express, *yui
@extensionfor express-yui
*/
module.exports = {

    /**
    Exposes the yui configuration into `app.locals.state`. It also
    exposes the `express-yui` wrapper for YUI on the client so you can
    access `app.yui.*` on the client side just like you do on the server
    side. The client wrapper includes `app.yui.ready()` and `app.yui.use()`
    with the corresponding bootstraping code to inject YUI into the page.
    This middleware will be invoked by `expyui.expose()` middleware
    automatically, which means you do not need to call it directly.

    @method exposeConfig
    @protected
    @return {function} express middleware
    **/
    exposeConfig: function () {

        var configCache;

        return function (req, res, next) {

            var yui_config = configCache;

            // if app.yui exists, we can expose the configuration
            if (!yui_config && req.app && req.app.yui) {
                // one time operation to compute the initial configuration
                yui_config = configCache = req.app.yui.config();

                // exposing the `YUI_config`
                req.app.expose(yui_config, 'window.YUI_config', {cache: true});
                req.app.expose(client, 'window.app.yui', {cache: true});
            }

            next();

        };

    },

    /**
    Expose the seed information into `app.locals.state`. This seed is
    an array of urls based on the call to `app.yui.seed()`, which is
    going to be used by the client bootstrap code to inject YUI into
    the page.
    This middleware will be invoked by `expyui.expose()` middleware
    automatically, which means you do not need to call it directly.

    @method exposeSeed
    @protected
    @return {function} express middleware
    **/
    exposeSeed: function () {

        var configCache,
            seedCache;

        return function (req, res, next) {

            var yui_config = configCache,
                yui_seed   = seedCache;

            // if app.yui exists, we can expose the configuration
            if (!(yui_config || yui_seed) && req.app && req.app.yui) {
                // one time operation to compute the initial configuration and seed.
                yui_config = configCache = req.app.yui.config();
                yui_seed = seedCache = req.app.yui.getSeedUrls();

                req.app.expose(yui_seed, 'window.YUI_config.seed', {cache: true});
            }

            next();

        };

    },

    /**
    Exposes YUI into the client side. This middleware bundles
    `expyui.exposeConfig()` and `expyui.exposeSeed()` middleware.

        var express = require('express'),
            expyui = require('express-yui'),
            app = express();

        expyui.extend(app);

        // using it for a mounted middleware for all requests
        app.use(expyui.expose());

    In the example above, the `state` of the app will be serialized *once*, on
    the first request, and can be used in the template to set up the client
    side to run YUI with the same configuration used on the server side.
    Here is an example of a handlebars template:

        <script>
        {{{state}}}
        app.yui.use('node', function (Y) {
            Y.one('#content').setContent('<p>Ready!</p>');
        });
        </script>

    @method expose
    @public
    @return {function} express middleware
    **/
    expose: function () {

        var handlers = [this.exposeConfig(), this.exposeSeed()];

        return function (req, res, next) {

            function run(index) {
                if (index < handlers.length) {
                    handlers[index](req, res, function (err) {
                        if (err) {
                            return next(err);
                        }
                        index += 1;
                        run(index);
                    });
                } else {
                    next();
                }
            }

            run(0);

        };

    },

    /**
    Forces a request to use yui in debug mode with combine disabled. This exposes
    YUI configuration overrides per request on `res.locals.state` (which inherits
    from `app.locals.state`.)

        // exposing yui into the client side through `state` object
        app.use(expyui.expose());
        // using yui in debug mode when node runs in debug mode with custom filter
        if (app.get('env') === 'development') {
            app.use(expyui.debug({filter: 'raw'}));
        }

    More details about the yui debug mode settings
    [in the YUI API Docs](http://yuilibrary.com/yui/docs/api/classes/config.html).

    @method debug
    @public
    @param {Object} config optional debug settings
        @param {boolean} config.combine default to `false`
        @param {string} config.logLevel default to `"debug"`
        @param {string} config.filter default to `"debug"`
        @param {boolean} config.useBrowserConsole optional debug settings
    @return {function} express middleware
    **/
    debug: function (config) {

        config = config || {};

        var filter = config.filter || 'debug',
            combine = config.combine || false,
            logLevel = config.logLevel || 'debug',
            useBrowserConsole = config.hasOwnProperty('useBrowserConsole') ? config.useBrowserConsole : true;

        return function debug(req, res, next) {
            res.expose(filter, 'window.YUI_config.filter');
            res.expose(combine || false, 'window.YUI_config.combine');
            res.expose(true, 'window.YUI_config.debug');
            res.expose(logLevel, 'window.YUI_config.logLevel');
            res.expose(useBrowserConsole, 'window.YUI_config.useBrowserConsole');
            res.expose(req.app.yui.getSeedUrls({
                filter: filter,
                combine: combine
            }), 'window.YUI_config.seed');
            next();
        };

    },

    /**
    Serves YUI Modules as static assets. All registered groups and core will be
    served from app origin.

        app.use(expyui.static(__dirname + '/build'));

    The example above behaves very similar to `express.static()` middleware, but
    it adds some sugar to also server YUI core modules as synthetic files, so you
    can combine yui core modules with app specific modules for better performance.
    If also adds some extra headers to avoid caching static files in a browser
    when nodejs is running in debug mode to facilitate development.

    @method static
    @public
    @param {string} buildDirectory fullpath to locator build directory
    @param {Object} options express static handler options
    @return {Object} express app that can be mounted into another express app.
    **/
    'static': function (buildDirectory, options) {
        var express = require('express'),
            YUI = require('yui'),
            version = YUI.YUI.version,
            path = YUI.path(),
            app;

        options = options || {};

        // Disable HTTP caching when in dev and no maxAge option is set
        if (!options.maxAge && utils.debugMode) {
            options.maxAge = 0;
        }

        // creating an internal express app for static assets and
        app = express();
        // registering yui as the first entry mounted under the yui version
        app.use('/yui-' + version, express['static'](path, options));
        // now registering the build directory from locator
        app.use(express['static'](buildDirectory, options));

        // returning the app that can be mounted as an express middleware
        return app;
    }

};