Node Roundup: Browserify, NowJS, Vogue
Browserify

Browserify (GitHub: substack / node-browserify) by James Halliday makes CommonJS packages work in browsers by bundling up modules into a monolithic file. I know we’ve had a lot of script loaders on DailyJS, and detailed discussions about monolithic files vs. loading scripts on demand, but I assume James has structured Browserify this way to make the require syntax easy to support.
The package includes Connect middleware:
var connect = require('connect');
var server = connect.createServer();
server.use(connect.static(__dirname));
server.use(require('browserify')(__dirname + '/js'));
server.listen(9797);
The dependency support is interesting as well:
If the npm modules have dependencies, those dependencies will get bundled along recursively!
It’s also possible to run modules through minifiers, using post-filters.
I think this must be the most convenient way to share code between Node and browsers that I’ve seen so far.
I also seem to remember writing about Nodules which is similar to this project, and brequire.
NowJS
NowJS (GitHub: Flotype / now) aims to make real-time applications easier to develop by synchronising functions and variables in a namespace between clients and a server.
It can be set up with an Express app like this:
var app = express.createServer();
app.listen(3000);
var everyone = require("now").initialize(app);
The authors have already written a NowJS Coding Patterns and Best Practices guide, which explains how to filter messages at the client-side (for creating rooms in a chat application), and tips for keeping things efficient.
Vogue
Vogue (GitHub: andrewdavey / vogue, License) by Andrew Davey automatically reloads stylesheets whenever they’re saved. It uses Socket.IO so it feels pretty responsive. It’s a great idea for use during development, and I imagine it would blow your design team’s collective minds.
jQuery Roundup: 1.5.2, Kern.js, Zoomooz, Amplify
jQuery 1.5.2 RC 1
jQuery 1.5.2 RC 1 has been released, and the final version of 1.5.2 should be out on March 31st.
Kern.js

Kern.js (GitHub: bstrom87 / kern.js, WTFPL) by Brendan Stromberger helps generate styles for more refined kerning using Lettering.js.
Lettering.js has recently added a gallery of sites that use their styles; it’s worth checking out, too.
Zoomooz

Zoomooz (GitHub: jaukia / zoomooz) by Janne Aukia makes elements on a page “zoomable” — the page apparently zooms into a smaller slice of content. The example on the project’s homepage consists of small tiles which zoom in when clicked.
Amplify

Amplify (GitHub: appendto / amplify, MIT/GPL) provides a unified API for data sources. A set of components are provided for managing data-related tasks: the store component manages client-side data, a request component provides enhancements to jQuery’s Ajax library, and there’s also a pub/sub system. It’s like a Swiss Army knife for data.
The author has already written up full documentation for Amplify.
Node Tutorial Part 18: Full Text Search
Welcome to part 18 of Let’s Make a Web App, a tutorial series about building a web app with Node. This series will walk you through the major areas you’ll need to face when building your own applications. These tutorials are tagged with lmawa.
Click to show previous tutorials.
Full Text Search
Given that we’re making a document-based system, wouldn’t it be nice if we had full text search? Mongo doesn’t explicitly support full text search, but simply saving a list of keywords will work.
The list of keywords can be modeled as an array of strings:
Document = new Schema({
'title': { type: String, index: true },
'data': String,
'tags': [String],
'keywords': [String],
'user_id': ObjectId
});
Next we need to extract the strings from the document’s content. Mongoose middleware is the perfect way to do this:
Document.pre('save', function(next) {
this.keywords = extractKeywords(this.data);
next();
});
The question is, how should extractKeywords work? I’d usually rely on a full text indexer or a stemming library, but a simple function will be easier for now. Let’s use the following algorithm:
- Split on white space
- Find words longer than two characters
- Remove duplicates
Implementing this is fairly easy with the filter iterator:
function extractKeywords(text) {
if (!text) return [];
return text.
split(/\s+/).
filter(function(v) { return v.length > 2; }).
filter(function(v, i, a) { return a.lastIndexOf(v) === i; });
}
The regular expression matches white space, and the last filter will remove duplicates by checking if the index of the current value is the same as the last position that it appears. This is a quick and dirty solution, you’d want to spend more time on this for a production system.
Express Action
I’ve added routes for /search and /documents/titles. The titles route will just return a list of all titles with IDs, because the document index method returns documents with all their content.
app.get('/documents/titles.json', loadUser, function(req, res) {
Document.find({ user_id: req.currentUser.id },
[], { sort: ['title', 'descending'] },
function(err, documents) {
res.send(documents.map(function(d) {
return { title: d.title, _id: d._id };
}));
});
});
// Search
app.post('/search.:format?', loadUser, function(req, res) {
Document.find({ user_id: req.currentUser.id, keywords: req.body.s ? req.body.s : null },
[], { sort: ['title', 'descending'] },
function(err, documents) {
switch (req.params.format) {
case 'json':
res.send(documents.map(function(d) {
return { title: d.title, _id: d._id };
}));
break;
}
});
});
The search method expects a post with a s parameter to search on.
Interface

I’ve added a search bar on the top-right. It was a little bit of Jade added to the views/layout.jade file:
#container
#header
ul
li
h1
a(href='/') #{nameAndVersion(appName, version)}
- if (typeof currentUser !== 'undefined')
li.right
a#logout(href='/sessions') Log Out
li.right
form.search(action='/search')
input(name='s', value='Search')
With some Stylus:
form.users input[type=submit]
margin-left 140px
clear both
form.search
margin-right 10px
#show-all
color medium-grey
Now, this is where I start wishing we were already using Backbone.js. I’ve created a function for inserting documents into the list, and one to call the search method:
// Search bar
function showDocuments(results) {
for (var i = 0; i < results.length; i++) {
$('#document-list').append('<li><a id="document-title-' + results[i]._id + '" href="/documents/' + results[i]._id + '">' + results[i].title + '</a></li>');
}
}
function search(value) {
$.post('/search.json', { s: value }, function(results) {
$('#document-list').html('');
$('#document-list').append('<li><a id="show-all" href="#">Show All</a></li>');
if (results.length === 0) {
alert('No results found');
} else {
showDocuments(results);
}
}, 'json');
}
This will automatically show and hide the “Search” text in the input:
$('input[name="s"]').focus(function() {
var element = $(this);
if (element.val() === 'Search')
element.val('');
});
$('input[name="s"]').blur(function() {
var element = $(this);
if (element.val().length === 0)
element.val('Search');
});
$('form.search').submit(function(e) {
search($('input[name="s"]').val());
e.preventDefault();
});
$('#show-all').live('click', function(e) {
$.get('/documents/titles.json', function(results) {
$('#document-list').html('');
showDocuments(results);
if (results.length > 0)
$('#document-title-' + results[0]._id).click();
});
e.preventDefault();
});
It also inserts a document with the title “Show All”. This is styled a little bit differently and will call /documents/titles.json to fetch all the titles.
Indexing
I’ve added a Jake task that can be run with jake index. It’ll force all documents to save. This is just for the reader’s convenience to make existing documents get their keywords generated.
Conclusion
Full text search with Mongo is fairly easy, but this implementation is far from perfect. The keyword extraction algorithm could do with stemming, and the interface isn’t as intuitive as I’d like.
This week’s code was commit ceb9b32.
Data.js, context-blender, JavaScript Timeline, JSBeautify for Chrome, Mappa
Data.js
Data.js (GitHub: michael / data, License) by Michael Aufreiter is a data manipulation and persistence framework for JavaScript that works in the browser and Node.
It comes with Data.CouchAdapter for saving data to CouchDB, and uses Underscore so the enumeration-based API should be immediately familiar to you if you’re already using Underscore. For example:
var selectedItems = items.select(function(value, key, index) {
return value >= 10000000;
}).toJSON();
Everything in Data.js is based on these generic data formats:
Data.Hash: A sortable hash data structureData.Graph: A data abstraction for linked dataData.Collection: Tabular data (uses a Data.Graph internally)
What interests me about this project is the API really suits JavaScript, and it works in both browsers and server-side code. The fact the persistence layer is configurable makes me hope other databases will be supported.
context-blender
context-blender (License) by Gavin Kistner attempts to implement Photoshop’s RGBA compositing blend modes in JavaScript using Canvas. It’s been put in use by GitHub for their Difference image view mode, which you can read more about in Behold: Image view modes.
JavaScript Timeline

This JavaScript timeline by Michael Richardson presents an interactive view of the main events in JavaScript’s history. You can read more about this subject in my History of JavaScript series.
JSBeautify for Chrome
JSBeautify for Chrome by Tom R makes it easy to reformat minified JavaScript in Chrome. Install it:
Then view something like jquery.min.js. It’ll display a message saying “This looks like a JavaScript file. Click this bar to format it.” Handy!
Mappa
Mappa by Oliver Caldwell is a little library for creating aliases to functions, making it easy to map function names and create customised APIs. The example given by the author is with the JSON object:
Mappa.addMap('encodeJSON', JSON.stringify);
This will work in Node as well as browsers.
Let's Make a Framework: DOM Manipulation
Welcome to part 55 of Let’s Make a Framework, the ongoing series about building a JavaScript framework.
If you haven’t been following along, these articles are tagged with lmaf. The project we’re creating is called Turing. Documentation is available at turingjs.com.
The previous tutorials have looked at how jQuery implements .html() and .css() for cross-browser HTML and CSS manipulation. In this week’s post I’ll start implementing .html() for our framework.
API and Tests
The method turing.dom.html(element, html) should be available, along with the chained version, turing(selector).html(html).
A test like this should pass with the new method:
'test HTML can be written': function() {
var element = turing.dom.get('#dom-html-tests')[0];
turing.dom.html(element, '<p><a href="#">This is a link</a>');
assert.equal(turing.dom.get('#dom-html-tests p').length, 1);
assert.equal(turing.dom.get('#dom-html-tests a').length, 1);
}
And this should pass, too:
'test chained HTML works on multiple elements': function() {
turing('#dom-html-chain-test p').html('<a href="#">Link</a>');
assert.equal(turing.dom.get('#dom-html-chain-test p a').length, 4);
}
The quickest route to implementing this is to use innerHTML:
/**
* DOM manipulation
*
* @param {Object} element A DOM element
* @param {String} html A string containing HTML
*/
dom.html = function(element, html) {
element.innerHTML = html;
};
// ...
turing.domChain = {
init: function(selector) {
// ...
/**
* Chained DOM manipulation. Applied to every element.
*
* @param {String} html A string containing HTML
* @returns {Object} `this`
*/
html: function(html) {
for (var i = 0; i < this.elements.length; i++) {
dom.html(this[i], html);
}
return this;
},
Browser Support
This will work with simple tests in IE, Firefox, Chrome, etc. It’ll fail on the edge cases supported by jQuery. In particular, this won’t work:
// Given a simple table (in test/dom_test.html):
'test manipulating table rows': function() {
turing('#dom-html-table-test').html('<tr><td>1</td></tr><tr><td>2</td></tr>');
assert.equal(turing.dom.get('#dom-html-table-test tr').length, 2);
}
To make this work we need to trick IE into writing to what it considers “read only” elements. Microsoft’s innerHTML documentation says the following:
The property is read/write for all objects except the following, for which it is read-only: COL, COLGROUP, FRAMESET, HEAD, HTML, STYLE, TABLE, TBODY, TFOOT, THEAD, TITLE, TR.
I’ve written a basic way around this. It works by creating a temporary div which is populated with a table, and then the lastChild is extracted, and the contents of the original table replaced.
/**
* Replaces the content of an element.
*
* @param {Object} element A DOM element
* @param {String} html A string containing HTML
*/
dom.replace = function(element, html) {
var context = document,
isTable = element.nodeName === 'TABLE',
insert,
div;
div = context.createElement('div');
div.innerHTML = '<' + element.nodeName + '>' + html + '</' + element.nodeName + '>';
insert = isTable ? div.lastChild.lastChild : div.lastChild;
element.replaceChild(insert, element.firstChild);
div = null;
};
IE automatically inserts tbody tags so I’ve tried to deal with that. Dealing with this is actually quite complicated, and I’ll expand on this more next week.
This gets triggered based on an exception handler:
dom.html = function(element, html) {
try {
element.innerHTML = html;
} catch (e) {
dom.replace(element, html);
}
};
The latest commit was 73a3fac.
Node Roundup: Node 0.4.3, npm 1.0, Geo, MicroEvent
Node 0.4.3
Node 0.4.3 is out, which has some interesting changes:
- Start up memory footprint improvement
- HTTP Agent bugs
- Upgrade V8 to 3.1.8.3
npm 1.0
Isaac Schlueter has been working on npm 1.0, and I noticed he’s written an interesting about about 1.0’s ls command for the Node blog: npm 1.0: The New ls. It’s now at release candidate stage, and there’s a lot of activity going on over at isaacs/npm on GitHub.
Geo
Geo for Node.js (GitHub: feliperazeek/geonode) by Felipe Oliveira is a geocoding library that uses Google’s Geocode API for geocoding, and GeoHash for GeoSpatial support.
var geo = require('geo'),
sensor = false,
address = '221B Baker Street, London, UK';
geo.geocoder(geo.google, address, sensor, function(formattedAddress, latitude, longitude) {
console.log("Formatted Address: " + formattedAddress);
console.log("Latitude: " + latitude);
console.log("Longitude: " + longitude);
});
// Output:
// Formatted Address: 221 Baker St, Paddington, Greater London NW1 5, UK
// Latitude: 51.5231225
// Longitude: -0.1580078
Seems incredibly useful to me, assuming Google’s terms let us use this for something interesting!
MicroEvent.js
MicroEvent.js by Jerome Etienne (GitHub: jeromeetienne / microevent.js) is a tiny event emitter library for client-side code and Node. It uses the observer pattern, like this:
var Ticker = function() {
var self = this;
setInterval(function() {
// 'trigger' is provided by MicroEvent
self.trigger('tick', new Date());
}, 1000);
};
// You have to use this method to make your class MicroEvent-enabled:
MicroEvent.mixin(Ticker);
var ticker = new Ticker();
// Now we can observe when the event fires
ticker.bind('tick', function(date) {
console.log('notified date', date);
});
jQuery Roundup: jQuery UI 1.8.11, jCheck, TufteGraph, Firefox 4
jQuery UI 1.8.11
jQuery UI 1.8.11 is out, and it’s a maintenance release. There are fixes for Accordion, Autocomplete, Button, Datepicker, Draggable, Droppable, Mouse, Sortable, and Effects.
Read the 1.8.11 summary.
jCheck
jCheck (GitHub: wilkerlucio / jcheck, Apache 2.0 License) by Wilker Lúcio is a jQuery validation library that is modelled on the standard Rails validators: validates_acceptance_of, validates_confirmation_of, validates_presence_of and others are available. The author has also created jcheck_rails which adds support to Rails 3.
The client-side API looks like this:
$(function() {
var v = $('#contact-form').jcheck();
v.validates('name', 'message', { presence: true });
v.validates('email', { format: { 'with': 'email', message: 'is not a valid email address' }});
v.validates('message', { length: { minimum: 20, maximum: 255 }});
});
Even if you’re not using Rails I think the API is friendly and worth trying.
TufteGraph

TufteGraph (GitHub: xaviershay / tufte-graph, MIT License) by Xavier Shay is a great charting library which uses functions for configuration options and CSS for styling.
It requires the jQuery enumerable plugin and Raphael. There are some integration tests which demonstrate the library’s potential.
Firefox 4

Meanwhile, Firefox 4 is out today, which has a more refined interface, better JavaScript performance with JägerMonkey, and hardware acceleration. Mozilla also posted Glow, a visualistion of Firefox 4’s downloads.
Node Tutorial Part 17: UI Improvements
Welcome to part 17 of Let’s Make a Web App, a tutorial series about building a web app with Node. This series will walk you through the major areas you’ll need to face when building your own applications. These tutorials are tagged with lmawa.
Click to show previous tutorials.
Interface Improvements
I’ve neglected to work on Nodepad’s interface for quite a few weeks now. I’d really like it to have a more usable interface before proceeding on more features.
The areas that need improving are:
- Login form
- Registration form
- Add new document
- Rename document
Forms
I put a class on the registration and login forms and wrote the following Stylus:
form.users
background-color faded-white
border 1px solid medium-grey
float left
padding 0 10px 10px 10px
form.users div
padding 10px 0 0 0
float left
clear left
form.users label
width 140px
float left
clear right
color dark-grey
font-weight bold
form.users input[type=submit]
margin-left 140px
clear both
This just makes the forms feel a bit more substantial and easier to read. As you can see, I’m using the Stylus variables to keep the colours consistent.
Document Rename
I’ve added an input field to the document index so documents can be renamed. The Ajax save code now updates the document title in the left-hand-side navigation when the save returns:
$('#save-button').click(function() {
var id = $('#document-list .selected').itemID(),
params = { d: { data: $('#editor').val(), id: id, title: $('input.title').val() } };
$.put('/documents/' + id + '.json', params, function(data) {
// Saved, will return JSON
$('#document-title-' + id).html(data.title);
});
});
I added some styles to make the title input sit next to the main textarea. It looks a bit like Apple’s iOS Mail fields (no boxes around the fields, just single grey lines).
New Document
I added a new server-side method that just returns document titles: document/titles.json.
When the new document link is pressed (the “+” button), it creates a new document using Ajax, then selects the new one:
$('#create-document').click(function(e) {
$.post('/documents.json', { d: { data: '', title: 'Untitled Document' } }, function(new_doc) {
$('#document-list').append('<li><a id="document-title-' + new_doc._id + '" href="/documents/' + new_doc._id + '">' + new_doc.title + '</a></li>');
$('#document-title-' + new_doc._id).click();
});
e.preventDefault();
});
This could be changed to sort the documents as well.
Sorting Documents
A few weeks ago we switched to Mongoose’s new API. The documentation is still a bit lacking, so I’m not convinced that this is the best way to sort documents:
app.get('/documents.:format?', loadUser, function(req, res) {
Document.find({ user_id: req.currentUser.id },
[], { sort: ['title', 'descending'] },
function(err, documents) {
The old API was Document.find().sort() which made more sense to me, but now we have to do it like this.
Buttons
I added some styles to make the buttons feel like they’re being pressed:
ul.toolbar a:active
background-color dark-grey
color white
Conclusion
Now Nodepad better to use in Firefox and Chrome/Safari. It’s not quite professional quality yet, and would need more browser testing, but it’s closer to something I’d actually want to use.
This week’s code is commit 5c5fb5c
Jade Browser, iScroll, VM Form Validator
Jade Browser
Jade Browser by Jonah Fox is an attempt to get Jade templates to work in browsers. The same author wrote brequire which helps load CommonJS modules in browsers, so it seems like Jade Browser wraps around the standard Jade library rather than reimplementing it.
iScroll

Hugh Fraser sent us a link to iScroll by Matteo Spinelli, which is a WebKit library for creating iOS native styled tables with correct scrolling behaviour. It has quite a lot of features, including pinch to zoom gesture support, custom scrollbars, pull to refresh, and a paginated carousel.
It doesn’t depend on jQuery, so you could use it with your favourite mobile framework.
Given a few divs and an unordered list, it can be used like this:
myScroll = new iScroll('wrapper');
VM Form Validator

VM Form Validator by Benjamin Kuker is a new form validation library for MooTools 1.3. All of the VM Form Validator demos are created with jsFiddle, so it’s easy to see how it works.
Basic usage is like many form libraries out there:
var form1 = new VMFormValidator('register');
form1.required('username', 'You must enter a username');
form1.minLength('username', 5);
form1.required('email');
form1.email('email');
form1.noMatches('password', 'username');
form1.required('confirmPassword');
form1.matches('confirmPassword', 'password');
We don’t usually feature many non-jQuery libraries here, but I am interested in them so please share your stuff!
Let's Make a Framework: CSS Manipulation
Welcome to part 54 of Let’s Make a Framework, the ongoing series about building a JavaScript framework.
If you haven’t been following along, these articles are tagged with lmaf. The project we’re creating is called Turing. Documentation is available at turingjs.com.
Last week I took a look at how jQuery manipulates the DOM using $.html(). This week I’m going to discuss how jQuery lets us get and set CSS properties with .css.
jQuery’s .css() Method
The .css() method can both get and set CSS values on attributes. The reason why this is useful is — you’ve guessed it — browser incompatibilities. Standards-compliant browsers provide the getComputedStyle method, while Internet Explorer uses currentStyle and runtimeStyle.
jQuery also returns the correct value for both CSS and DOM naming schemes: .css('background-color') will return the same value as .css('backgroundColor').
Even though accessing an element’s style property, jQuery’s API provides a more consistent and less error-prone way of programming.
Internals
jQuery groups this functionality into css.js. Getting values uses jQuery.css(elem, name), while setting uses jQuery.style(elem, name, value).
jQuery.css
The first thing to note is the camelCase method, which is used quite early on:
css: function( elem, name, extra ) {
// Make sure that we're working with the right name
var ret, origName = jQuery.camelCase( name ),
hooks = jQuery.cssHooks[ origName ];
This is a very simple method that uses a regular expression to transform dashed strings to DOM properties:
// rdashAlpha = /-([a-z])/ig
// fcamelCase = function( all, letter ) {
// return letter.toUpperCase();
// };
camelCase: function( string ) {
return string.replace( rdashAlpha, fcamelCase );
}
Which works like this:
'background-color'.replace(/-([a-z])/ig, function(all, letter) { return letter.toUpperCase(); })
>> 'backgroundColor'
This value is kept and referred to as originName. This is then used with cssProps which helps deal with special cases. The “hooks” refer to CSS hooks, which is jQuery’s way of making CSS getting and setting more extensible.
// cssProps: {
// "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
// },
// Back in the CSS function:
name = jQuery.cssProps[ origName ] || origName;
// If a hook was provided get the computed value from there
if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
return ret;
// Otherwise, if a way to get the computed value exists, use that
} else if ( curCSS ) {
return curCSS( elem, name, origName );
}
If none of the hooks match, curCSS is called. This is actually a reference to the getComputedStyle or currentStyle method used to extract CSS values. jQuery wraps these methods with its own functions to make them behave more consistently. For example, the currentStyle function converts sizes to pixels based on a hack written by Dean Edwards in 2007.
Both of the calculated names are passed to getComputedStyle and used to extracted the value from a query against document.defaultView.getComputedStyle (or IE’s equivalent).
jQuery.style
The .style method sets style properties, and works with various signatures:
$('selector').css({ 'background-color': 'blue' });
$('selector').css('background-color', 'blue');
The first thing it does is checks the element is valid for this type of operation:
// Don't set styles on text and comment nodes
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
return;
}
We’ve seen nodeType used like this frequently in this series. The next part looks a lot like .css():
// Make sure that we're working with the right name
var ret, origName = jQuery.camelCase( name ),
style = elem.style, hooks = jQuery.cssHooks[ origName ];
name = jQuery.cssProps[ origName ] || origName;
When a value to set is present, some interesting checks are performed:
// Make sure that NaN and null values aren't set. See: #7116
if ( typeof value === "number" && isNaN( value ) || value == null ) {
return;
}
// If a number was passed in, add 'px' to the (except for certain CSS properties)
if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) {
value += "px";
}
// If a hook was provided, use that value, otherwise just set the specified value
if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
// Fixes bug #5509
try {
style[ name ] = value;
} catch(e) {}
}
Other than the weird bugs worked around with the if statements, writing styles simply boils down to mapping to a camel case name then writing the element’s property.
Conclusion
jQuery, and frameworks like it, give us a seamless way of getting and setting style properties. It would be a fairly simple task if it wasn’t for those pesky browser bugs and incompatibilities.
Node Roundup: Express 2 Blowout
Express 2 and New Express Modules
As noted in Monday’s Node tutorial, Express 2 is getting close to release. The current version in npm is express@2.0.0rc, so get ready!
There’s an Express 1.x to 2.x migration guide to help you update your apps. I don’t think the changes are too drastic, but it’s worth being aware of them before migrating. To summarise:
- The HTTP referrer can be accessed with
req.header('Referrer') - Local variables can be exposed to views using
res.local('name', variable), rather than just withres.render req.paramnow takes an additional default value parameter to avoid having to do this:var id = req.param('id') || req.user.idapp.locals()is now an alias ofapp.helpers()- Cookies now take a
maxAgeparameter which is relative to the current date - Static file handling has been ported to Connect from Express, and
res.download’s callback method gets an error parameter res.renderwill treat unrecognised parameters as local variables for templatesres.partialhas been added, which is useful for Ajax response methods- View partial lookup is now relative to the current template’s path
- Express and Connect now use the
mimemodule (available from npm)
Express Resource
TJ is also working on several new modules that make working with Express potentially more convenient. If you want to work with REST resources, take a look at express-resource.
exports.index = function(req, res){
res.send('forum index');
};
exports.new = function(req, res){
res.send('new forum');
};
exports.create = function(req, res){
res.send('create forum');
};
exports.show = function(req, res){
res.send('show forum ' + req.params.id);
};
exports.edit = function(req, res){
res.send('edit forum ' + req.params.id);
};
exports.update = function(req, res){
res.send('update forum ' + req.params.id);
};
exports.destroy = function(req, res){
res.send('destroy forum ' + req.params.id);
};
Express Namespace
Sometimes it’s useful to hang routes or resources off a prefix — imagine a blog or CMS with an administration area. A neat way of handling this is through express-namespace, which looks like this:
app.namespace('/forum/:id', function(){
app.get('/(view)?', function(req, res){
res.send('GET forum ' + req.params.id);
});
app.get('/edit', function(req, res){
res.send('GET forum ' + req.params.id + ' edit page');
});
app.namespace('/thread', function(){
app.get('/:tid', function(req, res){
res.send('GET forum ' + req.params.id + ' thread ' + req.params.tid);
});
});
app.del('/', function(req, res){
res.send('DELETE forum ' + req.params.id);
});
});
Express Messages
Every web app I’ve ever worked on has had flash messages, so why not use express-messages to do it? It’s loaded as a dynamic helper, and just needs a call to messages() in a view.
Express Configuration
Express Configuration is an asynchronous configuration module for Express. That means you could use a database to store your app’s configuration:
app.configure(function(done){
redis.hmget('settings', function(err, obj){
for (var key in obj) app.set(key, obj[key]);
done();
});
});
app.listen(3000);
jQuery Roundup: Screencasts, $.data() Tutorial, Rails Switching to jQuery
More jQuery Screencasts

I’ve previously mentioned Josh Timonen’s awesome screencasts, and he sent us two more jQuery-focused tutorials:
- Improving the Delicious Bookmark Button with jQuery
- Building a Simple AJAX Website with Sinatra & jQuery
Linking JavaScript Objects to HTML Elements
In Linking JavaScript Objects to HTML Elements, Tait Brown discusses using the $.data() function to maintain relationships between markup and server-side data. It’s written from a designer’s perspective, which was interesting to me (as a predominantly server-side developer).
Rails 3.1 Shipping with jQuery
David Heinemeier Hansson announced that Rails 3.1 is moving to jQuery as the built-in JavaScript library. Rails had previously bundled Prototype and had tight integration with script.aculo.us.
Node Tutorial Part 16: Updating to Node 0.4.2 and Express 2
Welcome to part 16 of Let’s Make a Web App, a tutorial series about building a web app with Node. This series will walk you through the major areas you’ll need to face when building your own applications. These tutorials are tagged with lmawa.
Click to show previous tutorials.
Switching to Node 0.4.2
I can tell you’re all desperate to get Nodepad on Node 0.4.x, so let’s do it! Node and even libraries like Express are still volatile, so expect things to break. If you’re running production Node apps, you’ll need to factor in some time to update Node and your dependencies as part of your project management. It’s just a fact of life at the moment.
Back in tutorial 15 I demonstrated how to switch between Node versions using n. Make sure you’ve got n installed:
npm install n
Then switch to 0.4.2:
n 0.4.2
Express 2
I haven’t seen TJ say too much about Express 2 yet, but I’ve noticed he’s added some interesting new projects to his visionmedia GitHub account (express-resource and express-namespace look interesting).
So it seems like although Express 2 is fairly similar to Express 1, the project will get new supporting modules that you can use if you want. It’s almost like an anti-Rails or Django. So let’s take a look at the API changes that affect our app.
To install the Express 2 I’ve got, just type npm install express@2.0.0beta3. I’ve updated app.js and package.json with the other library versions I’m using.
Express 2 API Changes
Some of the middleware has been renamed. So cookieDecoder and bodyDecoder are now cookieParser and bodyParser. The staticProvider middleware has been changed to static. I’ve made these changes in our app.
The view partial rendering is also slightly different. Before a views/partials directory was the default location for partials, but now it’s relative to the current template’s directory. That means using partial('fields') in views/users/new.jade will look for views/users/fields.jade. This seems more consistent to me so I didn’t mind the change.
From the documentation:
View lookup is performed relative to the parent view, for example if we had a page view named views/user/list.jade, and within that view we did partial(‘edit’) it would attempt to load views/user/edit.jade, whereas partial(‘../messages’) would load views/messages.jade.
Header modification is also now stricter. I made a mistake where an asynchronous Mongoose call could happen after a redirect was sent. In such cases an exception will now be raised:
http.js:521
throw new Error("Can't use mutable header APIs after sent.");
If you see something like that in your own apps, try looking at the order of things are happening given that you’re likely to be using a lot of asynchronous calls.
And it looks like expressjs.com/guide.html refers to the latest version, so have a read of that to get up to speed.
Conclusion
Upgrading major versions of your platform and dependencies is probably almost always difficult. TJ has written a migration guide for Express 1.x to 2.x developers, so you should be OK migrating your own projects. Just remember it’s likely that many dependencies will need to be updated at once: obviously upgrading Express implies a Connect update.
The latest commit is 19fbb2.
JavaScript Garden, Made by Many's SXSW Node App, JavaScript Loader Comparison
JavaScript Garden

JavaScript Garden (GitHub: BonsaiDen / JavaScript-Garden) by Ivo Wetzel and Zhang Yi Jiang is a collection of interesting and quirky JavaScript example code.
I spend a good part of every day reading and writing about JavaScript, and I’ve found things in there that are new to me. It’s definite weekend reading material!
Made by Many’s SXSW Node App

Paul Battley blogged about Made by Many’s SXSW Node App, which is an Express app using Mongo and Socket.IO (a combination I’ve had a lot of success with, too). The app uses the Instagram API to publish real-time images posted by Paul’s colleagues at SXSW. You can check out the app here: sxsw.madebymany.com.
It’s simple but inventive. If you’re working at an agency and looking to get some Node into your day job, why not try something like this too?
JavaScript Loader Comparison

I’ve reviewed my share of JavaScript loaders on DailyJS, but I found this Hacker News JavaScript loader comparison post fascinating. 21 libraries are compared in quite some detail in the linked Google Docs spreadsheet.
The credit goes to Éric D and Webperf France:
Contact & info : http://eric.daspet.name/, @edasfr or @webperf_fr Authors of js loaders and webperf experts are more than welcome to request write access to the grid. Please ask, we are waiting for you.
Let's Make a Framework: DOM Manipulation
Welcome to part 53 of Let’s Make a Framework, the ongoing series about building a JavaScript framework.
If you haven’t been following along, these articles are tagged with lmaf. The project we’re creating is called Turing. Documentation is available at turingjs.com.
The Style and innerHTML Properties
After years of blindly manipulating the style and innerHTML properties, I noticed more modern frameworks advocate against this. If you think back to when I wrote about our animation module, you’ll remember that working with style attributes can be less than user friendly — it required a decent amount of helper methods just to do things like work with colours. That’s partially why frameworks like jQuery provide a .css() method — to provide a consistent interface.
It’s slightly harder to appreciate why working with innerHTML is bad. It’s fast, cross-browser, and easy to use. What’s not to like? Well, it’s a proprietary property. When XHTML was all the rage, using innerHTML caused problems when documents were served with an XML mime-type. It’s also inconsistently implemented; IE can treat it as read-only on tables, and there are other IE-related problems too.
Hopefully I’ve convinced you why methods like jQuery’s .css and .html are a good idea. But how do they work?
jQuery’s .html() Implementation
You’re probably wondering how exactly .html() works. After all, isn’t it just going to defer to innerHTML at some point?
The basic usage is with a string that contains HTML:
$('div.demo-container')
.html('<p>All new content.</p>');
It can also accept a function, but let’s just consider the string case to keep things focused.
The implementation is in manipulation.js. Basically, html will use innerHTML if possible:
if ( typeof value === "string" && !rnocache.test( value ) &&
( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
if ( this[i].nodeType === 1 ) {
jQuery.cleanData( this[i].getElementsByTagName("*") );
this[i].innerHTML = value;
}
}
} catch(e) {
// If using innerHTML throws an exception, use the fallback method
this.empty().append( value );
}
The first two lines are the most confusing part of this code. Let’s look at each part in sequence:
jQuery.support.leadingWhitespaceis set to true in browsers that preserve whitespace when inserting content withinnerHTMLrleadingWhitespace.test(value)checks to see if the HTML fragment has leading whitespacewrapMapis an object that in this case helps look for tags that can’t be inserted normallyrxhtmlTagis a regex that expands self-closing tags- A loop removes each existing Node to prevent memory leaks
- If
innerHTMLraises an exception, fall back toappend
If the value is a string, and the whitespace/wrapMap expressions return true, then inserting with innerHTML might be possible. Else use append.
wrapMap
I’ll need to explain append separately, but first let’s look at wrapMap:
wrapMap = {
option: [ 1, "<select multiple='multiple'>", "</select>" ],
legend: [ 1, "<fieldset>", "</fieldset>" ],
thead: [ 1, "<table>", "</table>" ],
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
area: [ 1, "<map>", "</map>" ],
_default: [ 0, "", "" ]
};
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
// IE can't serialize <link> and <script> tags normally
if ( !jQuery.support.htmlSerialize ) {
wrapMap._default = [ 1, "div<div>", "</div>" ];
}
Running it returns responses like this:
'<tr><td>Example</td></tr>'
> !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ]
false
'<div><p>Example content</p></div>'
> !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ]
true
append
In jQuery, append and many other methods rely on domManip. This method accepts a list of elements to create and insert, a confusing table argument, and a callback. The callback is used to actually manipulate the DOM. In the case of append it looks like this:
function( elem ) {
if (this.nodeType === 1) {
this.appendChild(elem);
}
}
The nodeType is checked to ensure it’s an element node, then appendChild is used to insert the content.
domManip
The append method is simple because domManip does the real work. Let’s take a high-level look (I’ve added some extra comments):
domManip: function( args, table, callback ) {
var results, first, fragment, parent,
value = args[0],
scripts = [];
// We can't cloneNode fragments that contain checked, in WebKit
if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
// run domManip on each element, but parse the element with jQuery() first
}
// If there's already an element
if ( this[0] ) {
parent = value && value.parentNode;
// If we're in a fragment, just use that instead of building a new one
if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
results = { fragment: parent };
} else {
results = jQuery.buildFragment( args, this, scripts );
}
fragment = results.fragment;
if ( fragment.childNodes.length === 1 ) {
first = fragment = fragment.firstChild;
} else {
first = fragment.firstChild;
}
if ( first ) {
table = table && jQuery.nodeName( first, "tr" );
// Call the callback with each element
for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
callback.call(
table ?
root(this[i], first) :
this[i],
// Make sure that we do not leak memory by inadvertently discarding
// the original fragment (which might have attached data) instead of
// using it; in addition, use the original fragment object for the last
// item instead of first because it can end up being emptied incorrectly
// in certain situations (Bug #8070).
// Fragments from the fragment cache must always be cloned and never used
// in place.
results.cacheable || (l > 1 && i < lastIndex) ?
jQuery.clone( fragment, true, true ) :
fragment
);
}
}
if ( scripts.length ) {
jQuery.each( scripts, evalScript );
}
}
return this;
}
As you might have noticed, jQuery.buildFragment seems to be doing something important here. The reality is that buildFragment manages caching and hands off the real work to jQuery.clean.
jQuery.clean
Bored yet? We’re nearly at the best part!
The middle of jQuery.clean has the magic we’ve been searching for:
if ( typeof elem === "string" && !rhtml.test( elem ) ) {
elem = context.createTextNode( elem );
} else if ( typeof elem === "string" ) {
// Fix "XHTML"-style tags in all browsers
elem = elem.replace(rxhtmlTag, "<$1></$2>");
// Trim whitespace, otherwise indexOf won't work as expected
var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
wrap = wrapMap[ tag ] || wrapMap._default,
depth = wrap[0],
div = context.createElement("div");
// Go to html and back, then peel off extra wrappers
div.innerHTML = wrap[1] + elem + wrap[2];
// Move to the right depth
while ( depth-- ) {
div = div.lastChild;
}
// Remove IE's autoinserted <tbody> from table fragments
if ( !jQuery.support.tbody ) {
If the element is a string and doesn’t have any tags, it’s a text node. Otherwise, expand self-closing tags, trim whitespace, create a shim div to extract some delicious DOM nodes, then handle IE’s table weirdness.
Conclusion
Explaining how jQuery implements html demonstrates just how much work is required to provide a consistent API for accessing innerHTML. However, implementing this stack of functionality makes many interesting DOM manipulation possible, beyond append.
Incidentally, if you want to see code that does this without dealing with as many browser headaches, try looking at Zepto’s source. Zepto only targets WebKit, which means it’s a great way to learn the fundamental techniques without worrying about legacy IE issues.
Next week I’ll explain how css works.
References
Node Roundup: forms, ngen, UglifyJS
Forms
Constructing a good form by hand is a lot of work. Popular frameworks like Ruby on Rails and Django contain code to make this process less painful. This module is an attempt to provide the same sort of helpers for node.js.
Forms by Caolan McMahon (with contributions from Ludwig Pettersson, Jed Parsons, and Rob Burns) is a library for generating and validating forms. It’ll generate markup, and can help process requests on the server as well.
There’s even an Express example for those of you working with that framework.
The API combines field definitions with validations, and handles things like confirmation and required fields:
reg_form = forms.create({
username: fields.string({required: true}),
password: fields.password({required: true}),
confirm: fields.password({
required: true,
validators: [validators.matchField('password')]
}),
email: fields.email()
});
Forms can be installed with npm:
npm install forms
ngen
ngen (MIT license) by TJ Holowaychuk is a Node package generator. If you’re looking to create your first Node package but don’t know where to start, this could be a great way to kick things off. Especially since TJ has released his fair share of Node packages already!
It’s probably best if you use this library with Node 0.4.x rather than 0.2.×.
Running it looks like this:
$ ngen ./project-1
Project name: project-1
Enter your name: Alex R. Young Esquire The First
Enter your email: alex@example.com
Project description: An example project
create : project-1/.npmignore
create : project-1/History.md
create : project-1/index.js
create : project-1/lib
create : project-1/lib/project-1.js
create : project-1/Makefile
create : project-1/package.json
create : project-1/Readme.md
create : project-1/support
create : project-1/test
create : project-1/test/project-1.test.js
$ ls project-1/
History.md Makefile Readme.md index.js lib package.json support test
UglifyJS
I recently used UglifyJS (GitHub: mishoo / UglifyJS, BSD license) as part of an open source project to generate minified code. I was very impressed with it, particularly with how well it worked alongside JSHint and node-jake.
To install it, use npm install uglify-js. That provides the uglifyjs commnad-line tool, as well as the Node library.
The API looks like this:
var uglify = require('uglify-js'),
jsp = uglify.parser,
pro = uglify.uglify,
ast = jsp.parse(fs.readFileSync('original.js').toString()),
outFile = fs.openSync('out-min.js', 'w+');
ast = pro.ast_mangle(ast);
ast = pro.ast_squeeze(ast);
fs.writeSync(outFile, pro.gen_code(ast));
That’s basically what my Jakefile uses to generate a minified version of my library.
jQuery Roundup: jQuery UI APIs, jQuery Smart AutoComplete, jFormer
jQuery API Redesigns
In API Redesigns: The Past, Present and Future on the jQuery UI Blog, Scott González talks about the origins, current state, and future of the jQuery UI APIs:
Over time, this led to what we have today, where something as simple as a draggable element has almost 30 options. On one hand, it’s impressive that so many various use cases can be handled, often with the use of just one or two of these options. On the other hand, finding the right one or two options to use can be a daunting task, especially for new users.
The goal of the 2.0 release is to have simpler APIs with increased stability and full test suites. This will require some backwards-incompatible changes, however:
We know that no one looks forward to refactoring existing code to work with API changes, and we’re working to make sure the transition process will be clear and simple. We hope that you, our users, understand that we need take this opportunity to refine jQuery UI to make it more robust, extensible, and maintainable in the long term.
jQuery Smart AutoComplete

jQuery-Smart-Auto-Complete (MIT License) by Lakshan Perera is an AutoComplete plugin that’s easy to install and comes with sensible default options. It works with keyboard controls, and supports custom filtering algorithms.
There’s a Smart AutoComplete demo which has plenty of examples, and Lakshan wrote a blog post introducing jQuery Smart AutoComplete.
jFormer

jFormer (MIT/GPL, demos, documentation) is a form framework written with jQuery and PHP. A PHP object, JFormer is used alongside some appropriate client-side JavaScript to take a lot of the drudgery out of form development.
This made me wonder if there’s anything similar that would work in Node or Ringo, and I found forms for Node which I’ll talk about tomorrow.
Node Deployment Recipes
During the publication of our Let’s Make a Web App tutorial series, people have been posting comments about hosting Node apps. In particular, the comments on Node Tutorial 13 are quite detailed. In this article I’ve summarised Node hosting approaches so you can pick the approach that suits you.
In the wider web development community there are some amazing plug-and-play solutions for hosting web apps. Hosting Node apps isn’t quite as easy, yet, but there are some excellent solutions that are both fast and easy to understand.
Upstart
Upstart is a replacement for the /sbin/init daemon. You can use it to start, stop, and restart Node processes. If you’re using Ubuntu you should already have it, if you’re using Debian or another Linux distribution it’s fairly easy to install. It actually comes with replacements for the sysvinit scripts that come with Debian. The Upstart Getting Started guide has more details.
This is an upstart script in /etc/init/myapp.conf that I knocked up to manage a Node app on EC2:
#!upstart
description "MyApp"
author "alex"
env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
respawn
start on runlevel [23]
script
export NODE_ENV=production
exec /usr/local/bin/node /data/apps/MyApp/app.js 2>&1 >> /var/log/node.log
end script
The respawn instruction will restart my app if it dies for some reason. There’s also a respawn limit flag which can limit respawning based on a timeout.
On a Debian/Ubuntu server I’d typically use the start, stop, and status commands to manage this process:
$ sudo status myapp
myapp start/running, process 9717
Alternative: Monit

I’ve also used Monit with great success. Monit can monitor processes and restart them when required. It’s possible to restart a process based on CPU usage or memory.
Monit relies on a PID file, so you may need to write a wrapper script around your Node app. There’s an example in Monit’s FAQ. Cluster can write out PID files.
In addition to many other features, Monit can be managed with a web interface and send out email alerts.
Cluster
To ease the management of your application further, and potentially better support multi-core servers, Cluster can be used. Apps have to be set up to use Cluster, but it’s very straightforward.
This is an Express example I’ve used before on DailyJS:
var app = require('express').createServer(),
cluster = require('cluster');
app.get('/', function(req, res){
res.send('hello world');
});
cluster(app)
.use(cluster.repl(8888))
.listen(3000);
Cluster has many interesting features, from zero-downtime reloading to a commnad-line console for real-time administration.
I asked TJ Holowaychuk how he manages production Node apps, and apparently he’s using Cluster. Cluster evolved from an older project called Spark, so it seems like it’s got some pedigree.
Authbind
The age old problem of hosting web software is port 80: binding to this port requires root. There are ways around this: some firewalls can redirect traffic from port 80 to a non-privileged port. An alternative to this is authbind, which can be easily installed in many distributions. In Debian it’s just a case of apt-get install authbind.
Once it’s installed, create a file in /etc/authbind/byport/80 and chown it to the user you want to run your Node app as. Then, if you’re using Monit or Upstart, make sure your Node process is launched with authbind and run it as that user.
The previous Upstart example would have to be adapted to work with authbind:
#!upstart
description "MyApp"
author "alex"
env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
respawn
start on runlevel [23]
script
export NODE_ENV=production
su -c 'authbind /usr/local/bin/node /data/apps/myapp/app.js 2>&1 >> /var/log/node.log' www-data
end script
Nginx
Almost a year ago I wrote a tutorial on using nginx to host Node apps. Servers like Apache and nginx can sit in front of your app and the web. This means you don’t need to run on a privileged port, and the web server can do jobs it’s good at like serving static files.
This may fit in better with your current hosting set up. You could still use a service monitor with Cluster to manage the Node processes.
EC2

I deployed my Upstart/Authbind/Cluster combo to EC2 without any trouble at all. I used the AWS Console to create EBS storage devices to keep my Mongo database, application, and static assets. After that it’s basic Linux sysadmin.
Just remember to add your IP address and port 22 to the security policy, else you won’t be able to connect!
Worzone, Yepnope, JSHint
Worzone

Worzone (GitHub: raimohanska / worzone) by Juha Paananen is a game written using Microsoft’s Reactive Extensions for JavaScript. There’s also a blog post about game programming with Microsoft’s RX library in which Juha explains some of the concepts behind reactive programming in JavaScript.
Yepnope

Yepnope (GitHub: SlexAxton / yepnope.js) by Alex Sexton and Ralph Holzmann is a script loader. I realise there’s a million script loaders, but this one caught my eye because it’s got a great site and documentation.
It can be used to load JavaScript or CSS. The example on the site looks like this:
yepnope({
test : Modernizr.geolocation,
yep : 'normal.js',
nope : ['polyfill.js', 'wrapper.js']
});
The test property is used to determine if the yep scripts should load, else the nope scripts will be loaded instead.
The library ships with a test suite, and the author notes it works very well with Modernizr:
Currently yepnope is being included in special builds of Modernizr, because it’s such a good companion to a feature testing library. The output of Modernizr is a fantastic input to yepnope.
It also supports plugins:
Yepnope was designed to be customizable. There are a few simple hooks throughout the loading process that allow you to inject code and change settings around on the fly. There are two main ways to do this: Prefixes and Filters.
JSHint
JSHint (GitHub: jshint / jshint is a fork of Crockford’s JSLint. The website allows you to test it out, but I recommend that you download jshint.js and use it locally.
It currently supports browsers, Node, and Rhino, so you should be able to integrate it with your existing projects.
Let's Make a Framework: Plugins Part 3
Welcome to part 52 of Let’s Make a Framework, the ongoing series about building a JavaScript framework.
If you haven’t been following along, these articles are tagged with lmaf. The project we’re creating is called Turing. Documentation is available at turingjs.com.
The init Method
In part 1 of the plugins section of this tutorial, I mentioned the concept of middleware. Middleware in libraries like Express is used to bridge client code with library code, and control flow (there’s usually a next() method passed in which you can call to propagate a value or continue execution).
In an Express app, it’s possible to provide a function to a route which will determine if the route is accessible. This is commonly used to load users from the session or forward them to a sign in page.
I’ve deliberately looked for a case in Turing that would benefit from a simplified middleware-inspired approach, and I decided to take a look at turing.init.
Less DOM Reliance
Right now, we can chain DOM-related code:
turing('.selector').click(function() { alert('clicked!'); });
And enumerable methods:
turing([1, 2, 3]).map(function(n) { return n * 10; });
But this is possible thanks to a slightly ugly hack residing in the DOM module:
// Chained calls
turing.init = function(arg) {
if (typeof arg === 'string' || typeof arg === 'undefined') {
// CSS selector
return new turing.domChain.init(arg);
} else if (arg && arg.length && turing.enumerable) {
// A list of some kind
return turing.enumerable.chain(arg);
}
};
I’ve never liked the way it checks if turing.enumerable is available, and how everything centres around the DOM module.
Function Registration
Instead, we can do this in turing.core.js:
var middleware = [];
function turing() {
if (arguments.length > 0) {
var result;
for (var i = 0; i < middleware.length; i++) {
result = middleware[i].apply(turing, arguments);
// If a value is returned, stop and return it, else keep looping
if (result) return result;
}
}
}
// This can be overriden by libraries that extend turing(...)
turing.init = function(fn) {
middleware.unshift(fn);
};
If a “middleware” function returns something, then execution will stop and this value will be returned from turing().
Because I’m using unshift to add the registered functions in reverse order, your own application code could extend turing() in some amusing ways:
turing.init(function(a) { if (a === 'hello') return 'world'; });
turing('hello');
// => "world"
The usefulness of this is highly debatable, however.
Built-in Module Extensions
Now each module can do this:
// DOM, which provides turing('.selector')
turing.init(function(arg) {
if (typeof arg === 'string' || typeof arg === 'undefined') {
// CSS selector
return turing.domChain.init(arg);
}
});
// DOM ready in the events module, which provides turing(function() {} );
turing.init(function(arg) {
if (arguments.length === 1
&& typeof arguments[0] === 'function') {
turing.events.ready(arguments[0]);
}
});
// Enumerable module, which provides turing([1, 2, 3]).map(function() {});
turing.init(function(arg) {
if (arg.hasOwnProperty.length && typeof arg !== 'string') {
return turing.enumerable.chain(arg);
}
});
Granted, this isn’t as sophisticated as the middleware provided by Connect and Express, but it does give us a neater way of extending turing() dynamically, and plugins or other code could also extend it.
Conclusion
Each module is now responsible for how it extends turing() by allowing it to look at the arguments. This has allowed me to tidy up Turing’s internal code, but I’m not convinced it’s useful outside of this. It did allow me to make an amusing Hello, World example, though.
