Building a date picker component

First install component(1) with npm:

$ npm install -g component

Or if you don’t have node installed at all, on OSX execute:

$ (cd /usr/local && \
   curl -L# http://nodejs.org/dist/v0.8.15/node-v0.8.15-darwin-x86.tar.gz \
   | tar -zx --strip 1) \
  && npm install -g component \
  && printf "installed component(1) %s\n" $(component --version)

Next you’ll need to bootstrap a new component, you can do this manually or use the quick component-create(1) command:

$ component create datepicker
repo (username/project): component/datepicker
description: Datepicker ui component built on component/calendar
does this component have js? y  
does this component have css? y
does this component have html? 

      create : datepicker
      create : datepicker/index.js
      create : datepicker/datepicker.css
      create : datepicker/Makefile
      create : datepicker/Readme.md
      create : datepicker/History.md
      create : datepicker/.gitignore
      create : datepicker/component.json

Adding dependencies

Next cd into the new directory and install the component/calendar component as a dependency:

$ component install component/calendar

    install : component/calendar@master
        dep : component/range@master
    install : component/range@master
        dep : component/jquery@master
    install : component/jquery@master
        dep : component/emitter@master
    install : component/emitter@master
        sep : component/in-groups-of@master
    install : component/in-groups-of@master
      fetch : component/calendar:index.js
      fetch : component/calendar:lib/utils.js
      fetch : component/calendar:lib/template.js
      fetch : component/calendar:lib/calendar.js
      fetch : component/calendar:lib/days.js
      fetch : component/calendar:lib/calendar.css
      fetch : component/range:index.js
      fetch : component/jquery:index.js
      fetch : component/in-groups-of:index.js
      fetch : component/emitter:index.js
   complete : component/range
   complete : component/in-groups-of
   complete : component/emitter
   complete : component/jquery
   complete : component/calendar

If you cat the component.json file you’ll see that component-install(1) has added the dependency for us:

  cat component.json 
  {
    "name": "datepicker",
    "repo": "component/datepicker",
    "description": "Datepicker ui component built on component/calendar",
    "version": "0.0.1",
    "keywords": [],
    "dependencies": {
      "component/calendar": "*"
    },
    "development": {},
    "license": "MIT",
    "scripts": [
      "index.js"
    ],
    "styles": [
      "datepicker.css"
    ]

Creating the component

Like any other software it’s good to have a suite of tests, or at very least a functioning demo for developers and end-users. In this case we’ll just create example.html to test drive the date picker, create the file and add the following HTML:

<!DOCTYPE html>
<html>
  <head>
    <title>Datepicker</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" href="build/build.css">
    <script src="build/build.js"></script>
  </head>
  <body>
    <input type="text" name="date" placeholder="Choose a date">

    <script>
       var picker = require('datepicker');
       var el = document.querySelector('[name=date]');
       picker(el);
    </script>
  </body>
</html>

Our date picker is going to be pretty simple, we’re going to handle click events for the element passed to picker(), and then display the Calendar in a Popover instance, populating the input when a selection is made.

Before getting started you’ll want to install the popover component, event utility, and the optional “aurora” theme:

$ component install component/popover component/aurora component/event

Or with brace expansion:

$ component install component/{popover,aurora,event}

The following JavaScript snippet is what will go into ./index.js, the main entry-point script of the component. As you can see here the dependencies are explicitly required at the top of the file via the commonjs module system, making it very obvious what this module is interacting with. Next we export a single object, the Datepicker constructor itself which sets up a bit of event handling boilerplate.

var Calendar = require('calendar')
  , Popover = require('popover')
  , event = require('event')

module.exports = Datepicker;

function Datepicker(el) {
  if (!(this instanceof Datepicker)) return new Datepicker(el);
  this.el = el;
  event.bind(el, 'click', this.onclick.bind(this));
}

Datepicker.prototype.onclick = function(e){

};

NOTE: The use of “event” may seem low-level here, and that’s because it is, the event module is nothing more than a cross-browser event binding utility. These APIs are not designed to be cute, they’re designed to drastically reduce the dependency bloat, by only using what your component needs. “Cute” APIs are provided by higher level components such as the jQuery-like dom component, and are typically recommended for app-level use only

To finish up the JavaScript portion of the Datepicker instantiate a new Calendar in the constructor, and add a classname for styling purposes. Next in the .onclick handler a new Popover is passed the cal element for its content, and a datepicker-popover classname is given here for styling purposes as well, then finally the call to popover.show(this.el) shows the popover relative to the <input> element.

var Calendar = require('calendar')
  , Popover = require('popover')
  , event = require('event')

module.exports = Datepicker;

function Datepicker(el) {
  if (!(this instanceof Datepicker)) return new Datepicker(el);
  this.el = el;
  this.cal = new Calendar;
  this.cal.el.addClass('datepicker-calendar');
  event.bind(el, 'click', this.onclick.bind(this));
}

Datepicker.prototype.onclick = function(e){
  this.cal.on('change', this.onchange.bind(this));
  this.popover = new Popover(this.cal.el);
  this.popover.classname = 'datepicker-popover popover';
  this.popover.show(this.el);
};

Datepicker.prototype.onchange = function(date){
  el.value = date.getFullYear()
    + '/'
    + date.getMonth()
    + '/'
    + date.getDate();

  this.popover.hide();
};

Building the component

To build the component invoke the following component-build(1) command:

$ component build

Or simply use make, as the targets are already set up in the Makefile for you:

$ make

A new directory named ./build will now have been created for you with the resulting build.css and build.js files.

To make this process transparent in development I recommend using the watch command that some environments already have, for those that do not have it there’s watch(1). Before working on a component you may now simply watch the make command and chuck that process in the background to get out of your way:

$ watch make &

When you’re done invoke fg to foreground the job again, or kill it with:

$ kill %1

Styling the component

Without custom styling the Aurora calendar / popover themes will look something like the following, not exactly great for a date picker since the calendar already looks self-contained.

datepicker component before styling

Add the following CSS to ./datepicker.css to cancel out the popover border for the datepicker popover only:

.datepicker-calendar {
  font: 10px "Helvetica Neue", Helvetica, Arial, sans-serif;
}

.datepicker-popover .tip-arrow {
  top: auto;
}

.datepicker-popover .tip-inner {
  border: none;
}

Now re-build and you should have the following completed datepicker:

completed datepicker component

Publishing

To “publish” the component all you need to do is push it to GitHub and then install with component install myname/datepicker! No fighting over names, you can call them whatever you like. To increase discoverability of your component you can then add it to the Wiki component listing and the component-search(1) command will index it.

Get the code for this component at component/datepicker.

For more on components check out the component repo and the Wiki.

Monitoring processes with mon

mon is an extremely small, simple, and light-weight alternative to monit for monitoring processes. Monit’s approach of using a DSL is at times inflexible and often annoying. Mon’s approach is to monitor only a single process, monitoring of several require a mon instance per process, however reducing single points of failure.

This may sound like it’s a lot of work to manage, but I promise you it’s not! There’s another tool for this called mongroup(1) to tie them together.

Monitoring a single process

Mon instances weigh in at about 400kb per process, so you don’t have to worry about spawning a bunch of them. The simplest use of mon accepts a command to execute, and keep alive:

$ mon "echo hello; sleep 5"

Mon will execute the command with /bin/sh -c, so brace expansion and other shell goodies are completely fine. Once the sub process exits, mon will bring it back to life. By default mon logs to stdout:

mon : child 94136
mon : sh -c "echo hey; sleep 5"
hey
mon : last restart less than one second ago
mon : 10 attempts remaining
mon : child 94138
mon : sh -c "echo hey; sleep 5"
hey
mon : last restart 5 seconds ago
mon : 9 attempts remaining
mon : child 94140
mon : sh -c "echo hey; sleep 5"
hey

Mon will continue to execute the command until mon itself is signalled with SIGQUIT or SIGTERM at which point it will signal the child using the same signal, and gracefully exit.

When a process continues to fail upon restart, cyclic spawning will be detected by mon, it will then exit and log a warning. By default 10 restart attempts within 60 seconds are allowed, however you may tweak this value with --attempts <n>.

Failure alerts

Mon provides two facilities for notification. The first is the --on-restart <cmd> flag, which mon will invoke upon any restart. This is useful for emailing administrators the tail of a log file, notifying your team via IRC, etcetera.

The second, and more crucial facility is the --on-error <cmd> flag, which is invoked only when a cyclic restart is detected, and mon has bailed out. Administrators should be notified immediately as the process is completely down.

Daemonization

Mon’s --daemonize flag may be used to background the process and disassociate with the terminal, at this point stdio will be redirected to the log file specified by --log, otherwise defaulting as “./mon.log”, typically this looks something like:

$ mon -d -l /var/log/app.log "node app.js"

Monitoring multiple processes with mongroup

Using mon with several flags is obviously not something you’d want to be typing all the time, but part of the benefit of using mon is that shell scripts become your DSL. If you’re not interested in doing this yourself but have several processes to manage I recommend checking out a project by jgallen23 called mongroup(1). I’ve forked the project to add some goodies, until merged you can find them here.

Mongroup uses a simple configuration file, defaulting to the name ./mongroup.conf, which simply lists out the pids and files directories, as well as one or more processes to spawn:

 pids = /var/run
 logs = /var/log
 web1 = node server 3000
 web2 = node server 3001
 web3 = node server 3002
 web4 = node server 3003
 redis = redis-server

Mongroup ships with typical init-style commands start, stop, restart, status and so on, without a lot of the boilerplate associated with writing init scripts.

Launching processes

To check the status of your monitoring group, simply invoke mongroup status, or mongroup, as it’s the default sub-command. You’ll see a list of process names, pids, and the status itself:

Firing up the entire suite of processes takes only a single command, mongroup start:

Checking the status again will show the process uptime:

You may also start, stop, or restart single processes at a time via:

$ mongroup stop [name]
$ mongroup start [name]
$ mongroup restart [name]

Since mongroup is working-directory sensitive unless the --config <file> flag is specified, I recommend adding a small snippet to your shell profile similar to the following:

procs() {
  (cd ~ && mongroup $@)
}

If you’re super paranoid you can monitor mon with mon:

  $ mon "mon 'node app'"

That’s all for now!

EDIT: changes to mongroup(1) have been merged! https://github.com/jgallen23/mongroup

Express 3.0

Express 3.0 is here (finally) and while it is mostly a refinement release, between it and Connect 2.x there are some helpful new features. Sorry for the massive delay! Been busy and wanted to get a reasonable amount of documentation up on expressjs.com before releasing, more docs will be coming soon.

Keep in mind that the goal of Express is to aid you with HTTP, not to become a framework super-power like Rails, so this update may be underwhelming to some since it’s merely a refinement.

Connect 2.x

Changes introduced by Connect 2.x:

  • added err.status support to Connect’s default end-point
  • added session() “proxy” setting to trust “X-Forwarded-Proto”
  • added cookieSession() middleware
  • added compress() middleware for gzipped responses
  • added multipart() middleware
  • added json() middleware
  • added urlencoded() middleware
  • added limit option to the three above middleware
  • added defer option to multipart() to listen on formidable’s events
  • added debug() instrumentation to aid in debugging
  • changed basicAuth()’s req.remoteUser to req.user
  • changed session() to only set-cookie on modification (hashed session json)
  • changed bodyParser() to be an aggregate of json(), multipart() and urlencoded()
  • moved many cookie-related utils into npm
  • moved static()’s logic into a separate npm module named “send”
  • increase perf ~%20 by memoizing url parsing
  • removed router() middleware
  • fixed default encoding for logger(), now “utf8” instead of “ascii”
  • fixed mount-path case-sensitivity

    Connect docs are available at http://www.senchalabs.org/connect/, and will eventually be mirrored on expressjs.com as well for convenience, along with usage guides.

Express 3.x

Changes introduced by Express 3.x:

  • added several new examples in ./examples
  • added unit testing for the examples (most of them at least)
  • added res.jsonp() to explicitly opt-in to JSONP support
  • added ETags and conditional-GET handling to res.send() responses
  • added “jsonp callback name” setting
  • added support for status code as first or second arg to res.send() and res.redirect()
  • added req.range(size) to parse Range header fields
  • added req.auth for basic auth
  • added res.links(obj) to set response the Link header field for pagination
  • added res.format(obj) for content-negotiation
  • added req.fresh for conditional-GETs
  • added req.stale for conditional-GETs
  • added mount-point relative redirection support to res.redirect()
  • added req.ip for the remote address (supporting reverse proxies)
  • added req.ips for remote address(es) (supporting reverse proxies)
  • added [] support in jsonp callback
  • added app.get(name) to compliment app.set(name, val)
  • added app.engine() to register template engines (replaces app.register())
  • added req.subdomains to return an array of subdomains
  • added req.protocol to return the request protocol string (“http” or “https”)
  • added req.secure to assert that req.protocol is “https”
  • added req.path to return the parsed url’s pathname
  • added req.host to return hostname (Host void of port)
  • added debug() instrumentation to aid debugging
  • added req.accepts()
  • added req.acceptsLanguage()
  • added req.acceptsCharset()
  • added req.accepted
  • added req.acceptedLanguages
  • added req.acceptedCharsets
  • added “json replacer” setting to manipulate json responses (remove private keys etc)
  • added “json spaces” setting to compress or expand json as you like (defaults to 2 in dev)
  • added express.application prototype
  • added express.request prototype
  • added express.response prototype
  • added app.render() for app-level templates
  • added res.type() to replace old res.contentType()
  • added { signed: true } option to res.cookie()
  • added async signature to res.render(), engines in consolidate.js work OOTB
  • removed partial()
  • removed express-level layout support (engines provide similar)
  • renamed “case sensitive routes” to “case sensitive routing”
  • removed res.signedCookie()
  • removed “root” setting
  • removed res.redirect('home') support
  • removed req.notify()
  • removed app.register()
  • removed app.redirect()
  • removed app.is()
  • removed app.helpers()
  • removed app.dynamicHelpers()

    Head over to the New Features in 3.x wiki page for a more comprehensive list of additions, or to 3.x migration to help you upgrade if you wish to do so.

&#8220;path&#8221; - 45 minute digial painting with pixelmator

“path” - 45 minute digial painting with pixelmator

more game WIP